diff --git a/config/staging.edn b/config/staging.edn index 0c77e289..f32d4c6c 100644 --- a/config/staging.edn +++ b/config/staging.edn @@ -1,11 +1,14 @@ {:db {:server "database"} - :datomic-url "datomic:ddb://us-east-1/integreat/integreat-staging" + :datomic-url "datomic:ddb://us-east-1/integreat-staging/integreat-staging" + :base-url "https://staging3.app.integreatconsult.com" + :solr-uri "http://solr-staging.local:8983" + :solr-impl :solr :scheme "https" :dd-env "staging" :dd-service "integreat-app" :jwt-secret "auto ap invoices are awesome" - :invoice-import-queue-url "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging" - :requests-queue-url "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-background-request-staging" + :invoice-import-queue-url "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging" + :requests-queue-url "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-background-request-staging" :invoice-email "invoices-staging@mail.app.integreatconsult.com" :import-failure-destination-email "bryce@brycecovertoperations.com" @@ -32,5 +35,4 @@ :yodlee2-proxy-port 8888 :plaid {:base-url "https://development.plaid.com" :client-id "61bfab05f7e762001b323f79" - :secret-key "637432f4c967bda8b5d77a1dc67e5c"} - } + :secret-key "637432f4c967bda8b5d77a1dc67e5c"}} diff --git a/iol_ion/src/iol_ion/tx.clj b/iol_ion/src/iol_ion/tx.clj index 133c402d..b6971238 100644 --- a/iol_ion/src/iol_ion/tx.clj +++ b/iol_ion/src/iol_ion/tx.clj @@ -17,36 +17,42 @@ [db [type id]] (let [{:expected-deposit/keys [total client date]} (d/pull db '[:expected-deposit/total :expected-deposit/client :expected-deposit/date] id)] #:journal-entry - {:source "expected-deposit" - :original-entity id + {:source "expected-deposit" + :original-entity id - :client client - :date date - :amount total - :vendor :vendor/ccp-square - :line-items [#:journal-entry-line - {:credit total - :location "A" - :account :account/receipts-split} - #:journal-entry-line - {:debit total - :location "A" - :account :account/ccp}]})) + :client client + :date date + :amount total + :vendor :vendor/ccp-square + :line-items [#:journal-entry-line + {:credit total + :location "A" + :account :account/receipts-split} + #:journal-entry-line + {:debit total + :location "A" + :account :account/ccp}]})) (defn regenerate-literals [] (require 'com.github.ivarref.gen-fn) - (spit - "resources/functions.edn" - (let [datomic-fn @(resolve 'com.github.ivarref.gen-fn/datomic-fn)] - [(datomic-fn :pay #'iol-ion.tx.pay/pay) - (datomic-fn :plus #'iol-ion.tx.plus/plus) - (datomic-fn :propose-invoice #'iol-ion.tx.propose-invoice/propose-invoice) - (datomic-fn :reset-rels #'iol-ion.tx.reset-rels/reset-rels) - (datomic-fn :reset-scalars #'iol-ion.tx.reset-scalars/reset-scalars) - (datomic-fn :upsert-entity #'iol-ion.tx.upsert-entity/upsert-entity) - (datomic-fn :upsert-invoice #'iol-ion.tx.upsert-invoice/upsert-invoice) - (datomic-fn :upsert-ledger #'iol-ion.tx.upsert-ledger/upsert-ledger) - (datomic-fn :upsert-transaction #'iol-ion.tx.upsert-transaction/upsert-transaction)]))) + (spit + "resources/functions.edn" + (let [datomic-fn @(resolve 'com.github.ivarref.gen-fn/datomic-fn)] + [(datomic-fn :pay #'iol-ion.tx.pay/pay) + (datomic-fn :plus #'iol-ion.tx.plus/plus) + (datomic-fn :propose-invoice #'iol-ion.tx.propose-invoice/propose-invoice) + (datomic-fn :reset-rels #'iol-ion.tx.reset-rels/reset-rels) + (datomic-fn :reset-scalars #'iol-ion.tx.reset-scalars/reset-scalars) + (datomic-fn :upsert-entity #'iol-ion.tx.upsert-entity/upsert-entity) + (datomic-fn :upsert-invoice #'iol-ion.tx.upsert-invoice/upsert-invoice) + (datomic-fn :upsert-ledger #'iol-ion.tx.upsert-ledger/upsert-ledger) + (datomic-fn :upsert-transaction #'iol-ion.tx.upsert-transaction/upsert-transaction)]))) + +(comment + (regenerate-literals) + + (auto-ap.datomic/install-functions) + ) \ No newline at end of file diff --git a/iol_ion/src/iol_ion/tx/pay.clj b/iol_ion/src/iol_ion/tx/pay.clj index 6067cd50..f18669af 100644 --- a/iol_ion/src/iol_ion/tx/pay.clj +++ b/iol_ion/src/iol_ion/tx/pay.clj @@ -6,6 +6,6 @@ new-outstanding-balance (- current-outstanding-balance amount)] [[:upsert-invoice {:db/id e :invoice/outstanding-balance new-outstanding-balance - :invoice/status (if (> new-outstanding-balance 0) - :invoice-status/unpaid - :invoice-status/paid)}]])) + :invoice/status (if (< -0.0001 new-outstanding-balance 0.0001) + :invoice-status/paid + :invoice-status/unpaid)}]])) diff --git a/package-lock.json b/package-lock.json index ae80585f..cd78b8d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,11 +45,14 @@ } }, "node_modules/@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@discoveryjs/json-ext": { @@ -61,62 +64,80 @@ "node": ">=10.0.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "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.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "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==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "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/@nodelib/fs.scandir": { @@ -157,19 +178,30 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@popperjs/core": { - "version": "2.11.5", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", - "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, "node_modules/@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", "dev": true, "dependencies": { "mini-svg-data-uri": "^1.2.3" @@ -179,63 +211,63 @@ } }, "node_modules/@types/d3-array": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.4.tgz", - "integrity": "sha512-nwvEkG9vYOc0Ic7G7kwgviY4AQlTfYGIZ0fqB7CQHXGyYM6nO7kJh5EguSNA3jfh4rq7Sb7eMVq8isuvg2/miQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" }, "node_modules/@types/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" }, "node_modules/@types/d3-ease": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", - "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" }, "node_modules/@types/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "dependencies": { "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", - "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" }, "node_modules/@types/d3-scale": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz", - "integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-shape": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.1.tgz", - "integrity": "sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", "dependencies": { "@types/d3-path": "*" } }, "node_modules/@types/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" }, "node_modules/@types/d3-timer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", - "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" }, "node_modules/@types/eslint": { - "version": "8.4.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", - "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "version": "8.56.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", + "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -243,9 +275,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -253,173 +285,176 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "20.11.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz", + "integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "undici-types": "~5.26.4" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, "node_modules/@webpack-cli/configtest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", - "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, "engines": { "node": ">=14.15.0" @@ -430,9 +465,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", - "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, "engines": { "node": ">=14.15.0" @@ -443,9 +478,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", - "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, "engines": { "node": ">=14.15.0" @@ -473,9 +508,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -485,9 +520,9 @@ } }, "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "peerDependencies": { "acorn": "^8" @@ -518,6 +553,32 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -554,24 +615,26 @@ "peer": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "peer": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -588,26 +651,35 @@ } }, "node_modules/browserslist": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", - "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001165", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.621", - "escalade": "^3.1.1", - "node-releases": "^1.1.67" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/buffer-from": { @@ -627,22 +699,30 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001170", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz", - "integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true, "funding": [ { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } - ], + ] + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "peer": true, "dependencies": { "anymatch": "~3.1.2", @@ -656,6 +736,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -674,22 +757,14 @@ } }, "node_modules/chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, "engines": { "node": ">=6.0" } }, - "node_modules/classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -704,29 +779,54 @@ "node": ">=6" } }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, + "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, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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, + "peer": true + }, "node_modules/colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6" + } }, "node_modules/compute-scroll-into-view": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", - "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "peer": true + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==" }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -742,11 +842,6 @@ "node": ">= 8" } }, - "node_modules/css-unit-converter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", - "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -761,14 +856,14 @@ } }, "node_modules/csstype": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/d3-array": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.3.tgz", - "integrity": "sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "dependencies": { "internmap": "1 - 2" }, @@ -904,39 +999,49 @@ } }, "node_modules/downshift": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.3.tgz", - "integrity": "sha512-RA1MuaNcTbt0j+sVLhSs8R2oZbBXYAtdQP/V+uHhT3DoDteZzJPjlC+LQVm9T07Wpvo84QXaZtUCePLDTDwGXg==", + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.12.tgz", + "integrity": "sha512-7XB/iaSJVS4T8wGFT3WRXmSF1UlBHAA40DshZtkrIscIN+VC+Lh363skLxFTvJwtNgHxAMDGEHT4xsyQFWL+UA==", "dependencies": { - "@babel/runtime": "^7.13.10", + "@babel/runtime": "^7.14.8", "compute-scroll-into-view": "^1.0.17", "prop-types": "^15.7.2", - "react-is": "^17.0.2" + "react-is": "^17.0.2", + "tslib": "^2.3.0" }, "peerDependencies": { "react": ">=16.12.0" } }, - "node_modules/downshift/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, "node_modules/dropzone": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-4.3.0.tgz", - "integrity": "sha1-SLC48q0JKHLktTW2cqfD8aHWfJE=" + "integrity": "sha512-KAP4sc9wjaU5xLhZ7olSH1ni72IbXk2l9iF9Ai5p3slwDtKTJunKkQpdFg7voyOcUU+6j75xEhHh+yPqd/Z/PA==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "peer": true }, "node_modules/electron-to-chromium": { - "version": "1.3.629", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz", - "integrity": "sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ==", + "version": "1.4.707", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.707.tgz", + "integrity": "sha512-qRq74Mo7ChePOU6GHdfAJ0NREXU8vQTlVlfWz3wNygFay6xrd/fY2J7oGHwrhFeU30OVctGLdTh/FcnokTWpng==", "dev": true }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "peer": true + }, "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -947,9 +1052,9 @@ } }, "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", + "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -959,15 +1064,15 @@ } }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", "dev": true }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -999,9 +1104,9 @@ } }, "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -1022,9 +1127,9 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, "engines": { "node": ">=0.8.x" @@ -1045,9 +1150,9 @@ } }, "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.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "peer": true, "dependencies": { @@ -1090,9 +1195,9 @@ } }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "peer": true, "dependencies": { @@ -1112,26 +1217,58 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flowbite": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.6.5.tgz", - "integrity": "sha512-eI4h3pIRI9d7grlYq14r0A01KUtw7189sPLLx/O2i7JyPEWpbleScfYuEc48XTeNjk1xxm/JHgZkD9kjyOWAlA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.8.1.tgz", + "integrity": "sha512-lXTcO8a6dRTPFpINyOLcATCN/pK1Of/jY4PryklPllAiqH64tSDUsOdQpar3TO59ZXWwugm2e92oaqwH6X90Xg==", "dependencies": { "@popperjs/core": "^2.9.3", "mini-svg-data-uri": "^1.4.3" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, - "peer": true + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "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, @@ -1144,27 +1281,32 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "peer": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1190,23 +1332,11 @@ "dev": true }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1216,10 +1346,22 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -1230,90 +1372,11 @@ }, "engines": { "node": ">=8" - } - }, - "node_modules/import-local/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-local/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/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==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "peer": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "peer": true - }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -1345,12 +1408,12 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1366,6 +1429,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1404,7 +1477,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/isobject": { @@ -1416,6 +1489,25 @@ "node": ">=0.10.0" } }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "peer": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -1431,9 +1523,9 @@ } }, "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, "peer": true, "bin": { @@ -1492,6 +1584,18 @@ "node": ">=6.11.5" } }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1508,6 +1612,16 @@ "loose-envify": "cli.js" } }, + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "peer": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -1539,21 +1653,21 @@ } }, "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "dependencies": { - "mime-db": "1.44.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -1568,22 +1682,35 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "peer": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/minisearch": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-3.0.2.tgz", - "integrity": "sha512-7rTrJEzovKNi5LSwiIr5aCfJNNo6Lk4O9HTVzjFTMdp+dSr6UisUnEqdwj4rBgNcAcaWW5ClpXnpgTurv8PGqA==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-3.3.0.tgz", + "integrity": "sha512-DlOEfLtiRKcEuShEaaufoDpWKv94lWDSRK7Bkcd0htqHEFZ1vqTi3IIW8cYcPIlomQjaCdiZXk4pyzBNc79I2Q==" }, "node_modules/mz": { "version": "2.7.0", @@ -1598,9 +1725,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -1623,9 +1750,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "1.1.67", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", - "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/normalize-path": { @@ -1641,7 +1768,7 @@ "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "engines": { "node": ">=0.10.0" } @@ -1656,14 +1783,31 @@ "node": ">= 6" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "peer": true, "dependencies": { - "wrappy": "1" + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/p-try": { @@ -1689,16 +1833,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1714,12 +1848,28 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -1745,19 +1895,31 @@ } }, "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, "peer": true, "engines": { "node": ">= 6" } }, + "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==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -1775,7 +1937,7 @@ ], "peer": true, "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -1801,13 +1963,6 @@ "postcss": "^8.0.0" } }, - "node_modules/postcss-import/node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "peer": true - }, "node_modules/postcss-js": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", @@ -1829,22 +1984,28 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "peer": true, "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { "node": ">= 14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" @@ -1858,6 +2019,19 @@ } } }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/postcss-nested": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", @@ -1879,9 +2053,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", "dev": true, "peer": true, "dependencies": { @@ -1893,24 +2067,31 @@ } }, "node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "peer": true }, "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -1947,9 +2128,9 @@ } }, "node_modules/react": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", - "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -1959,37 +2140,32 @@ } }, "node_modules/react-dom": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", - "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "scheduler": "^0.20.1" + "scheduler": "^0.20.2" }, "peerDependencies": { - "react": "17.0.1" + "react": "17.0.2" } }, "node_modules/react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-plaid-link": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/react-plaid-link/-/react-plaid-link-3.3.2.tgz", - "integrity": "sha512-W2L9C4RCE/KFFia2SUFFTi8SYRQ1UMUXh4iLE/oo4EQ8UYAT6msKzWvauj8bJirlrkzeiUtY6wgkmWil/okaNg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/react-plaid-link/-/react-plaid-link-3.5.1.tgz", + "integrity": "sha512-OSbPVEIQY3RDroDGyimRh9vUpZfSVzKVCwrbGOSIjcmluHnPKTkvJ1BnYbvE7kH+v8urJXMHloV43uMTNY3SLg==", "dependencies": { "prop-types": "^15.7.2", "react-script-hook": "^1.6.0" @@ -2013,18 +2189,10 @@ "react-dom": "^16.8.0 || ^17 || ^18" } }, - "node_modules/react-popper/node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/react-prop-types": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz", - "integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=", + "integrity": "sha512-IyjsJhDX9JkoOV9wlmLaS7z+oxYoIWhfzDcFy7inwoAKTu+VcVNrVpPmLeioJ94y6GeDRsnwarG1py5qofFQMg==", "dependencies": { "warning": "^3.0.0" }, @@ -2032,16 +2200,12 @@ "react": ">=0.14.0" } }, - "node_modules/react-resize-detector": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz", - "integrity": "sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==", + "node_modules/react-prop-types/node_modules/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==", "dependencies": { - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + "loose-envify": "^1.0.0" } }, "node_modules/react-script-hook": { @@ -2068,46 +2232,23 @@ } }, "node_modules/react-smooth": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.3.tgz", - "integrity": "sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.0.tgz", + "integrity": "sha512-2NMXOBY1uVUQx1jBeENGA497HK20y6CPGYL1ZnJLeoQ8rrc3UfmOM82sRxtzpcoCkUMy4CS0RGylfuVhuFjBgg==", "dependencies": { - "fast-equals": "^5.0.0", - "react-transition-group": "2.9.0" + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" }, "peerDependencies": { - "prop-types": "^15.6.0", - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-smooth/node_modules/dom-helpers": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", - "dependencies": { - "@babel/runtime": "^7.1.2" - } - }, - "node_modules/react-smooth/node_modules/react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", - "dependencies": { - "dom-helpers": "^3.4.0", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" - }, - "peerDependencies": { - "react": ">=15.0.0", - "react-dom": ">=15.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-transition-group": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -2143,25 +2284,23 @@ } }, "node_modules/recharts": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.6.2.tgz", - "integrity": "sha512-dVhNfgI21LlF+4AesO3mj+i+9YdAAjoGaDWIctUgH/G2iy14YVtb/DSUeic77xr19rbKCiq+pQGfeg2kJQDHig==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.2.tgz", + "integrity": "sha512-9bpxjXSF5g81YsKkTSlaX7mM4b6oYI1mIYck6YkUcWuL3tomADccI51/6thY4LmvhYuRTwpfrOvE80Zc3oBRfQ==", "dependencies": { - "classnames": "^2.2.5", + "clsx": "^2.0.0", "eventemitter3": "^4.0.1", - "lodash": "^4.17.19", + "lodash": "^4.17.21", "react-is": "^16.10.2", - "react-resize-detector": "^8.0.4", - "react-smooth": "^2.0.2", + "react-smooth": "^4.0.0", "recharts-scale": "^0.4.4", - "reduce-css-calc": "^2.1.8", + "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "engines": { - "node": ">=12" + "node": ">=14" }, "peerDependencies": { - "prop-types": "^15.6.0", "react": "^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } @@ -2174,6 +2313,11 @@ "decimal.js-light": "^2.4.1" } }, + "node_modules/recharts/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -2186,27 +2330,18 @@ "node": ">= 10.13.0" } }, - "node_modules/reduce-css-calc": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", - "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", - "dependencies": { - "css-unit-converter": "^1.1.1", - "postcss-value-parser": "^3.3.0" - } - }, "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -2294,18 +2429,18 @@ ] }, "node_modules/scheduler": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz", - "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -2321,9 +2456,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -2362,6 +2497,19 @@ "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/signature_pad": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-2.3.2.tgz", @@ -2396,16 +2544,120 @@ "source-map": "^0.6.0" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "7.1.6", + "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", @@ -2416,17 +2668,7 @@ "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 6" + "node": ">=16 || 14 >=14.17" } }, "node_modules/supports-color": { @@ -2457,9 +2699,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", "dev": true, "peer": true, "dependencies": { @@ -2468,10 +2710,10 @@ "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -2483,7 +2725,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, @@ -2495,13 +2736,6 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "peer": true - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -2512,13 +2746,13 @@ } }, "node_modules/terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", + "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", "dev": true, "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -2530,16 +2764,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.14", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -2563,6 +2797,12 @@ } } }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2586,6 +2826,11 @@ "node": ">=0.8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2602,7 +2847,7 @@ "node_modules/trim-canvas": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/trim-canvas/-/trim-canvas-0.1.2.tgz", - "integrity": "sha1-YgRX9f7PVktSHTXF/NTaWDBNbkU=" + "integrity": "sha512-nd4Ga3iLFV94mdhW9JFMLpQbHUyCQuhFOD71PEAt1NjtMD5wbZctzhX8c3agHNybMR5zXD1XTGoIEWk995E6pQ==" }, "node_modules/ts-interface-checker": { "version": "0.1.13", @@ -2612,11 +2857,46 @@ "peer": true }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -2634,9 +2914,9 @@ "peer": true }, "node_modules/victory-vendor": { - "version": "36.6.10", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.10.tgz", - "integrity": "sha512-7YqYGtsA4mByokBhCjk+ewwPhUfzhR1I3Da6/ZsZUv/31ceT77RKoaqrxRq5Ki+9we4uzf7+A+7aG2sfYhm7nA==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -2655,17 +2935,17 @@ } }, "node_modules/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", "dependencies": { "loose-envify": "^1.0.0" } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -2676,22 +2956,22 @@ } }, "node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -2700,9 +2980,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -2723,17 +3003,17 @@ } }, "node_modules/webpack-cli": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", - "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.1", - "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.1", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", "colorette": "^2.0.14", - "commander": "^9.4.1", + "commander": "^10.0.1", "cross-spawn": "^7.0.3", "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", @@ -2767,28 +3047,23 @@ } } }, - "node_modules/webpack-cli/node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, "node_modules/webpack-cli/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, "engines": { - "node": "^12.20.0 || >=14" + "node": ">=14" } }, "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" }, "engines": { @@ -2820,24 +3095,118 @@ } }, "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "peer": true }, - "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yaml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "dev": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } @@ -2852,11 +3221,11 @@ "peer": true }, "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "requires": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.14.0" } }, "@discoveryjs/json-ext": { @@ -2865,53 +3234,68 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "peer": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + } + }, "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } }, "@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.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true }, "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "@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==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { @@ -2943,78 +3327,86 @@ "fastq": "^1.6.0" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "peer": true + }, "@popperjs/core": { - "version": "2.11.5", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", - "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, "@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", "dev": true, "requires": { "mini-svg-data-uri": "^1.2.3" } }, "@types/d3-array": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.4.tgz", - "integrity": "sha512-nwvEkG9vYOc0Ic7G7kwgviY4AQlTfYGIZ0fqB7CQHXGyYM6nO7kJh5EguSNA3jfh4rq7Sb7eMVq8isuvg2/miQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" }, "@types/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" }, "@types/d3-ease": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", - "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" }, "@types/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "requires": { "@types/d3-color": "*" } }, "@types/d3-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", - "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" }, "@types/d3-scale": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz", - "integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", "requires": { "@types/d3-time": "*" } }, "@types/d3-shape": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.1.tgz", - "integrity": "sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", "requires": { "@types/d3-path": "*" } }, "@types/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" }, "@types/d3-timer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", - "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" }, "@types/eslint": { - "version": "8.4.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", - "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "version": "8.56.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", + "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", "dev": true, "requires": { "@types/estree": "*", @@ -3022,9 +3414,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "requires": { "@types/eslint": "*", @@ -3032,187 +3424,190 @@ } }, "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "20.11.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz", + "integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "undici-types": "~5.26.4" + } + }, + "@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, "@webpack-cli/configtest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", - "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, "requires": {} }, "@webpack-cli/info": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", - "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, "requires": {} }, "@webpack-cli/serve": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", - "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, "requires": {} }, @@ -3229,15 +3624,15 @@ "dev": true }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true }, "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "requires": {} }, @@ -3260,6 +3655,20 @@ "dev": true, "requires": {} }, + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "peer": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "peer": true + }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -3293,21 +3702,20 @@ "peer": true }, "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "peer": true }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "peer": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "braces": { @@ -3321,16 +3729,15 @@ } }, "browserslist": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", - "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001165", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.621", - "escalade": "^3.1.1", - "node-releases": "^1.1.67" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" } }, "buffer-from": { @@ -3347,15 +3754,15 @@ "peer": true }, "caniuse-lite": { - "version": "1.0.30001170", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz", - "integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true }, "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "peer": true, "requires": { @@ -3382,18 +3789,10 @@ } }, "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true }, "clone-deep": { "version": "4.0.1", @@ -3406,30 +3805,46 @@ "shallow-clone": "^3.0.0" } }, + "clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" + }, + "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, + "peer": 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, + "peer": true + }, "colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "compute-scroll-into-view": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", - "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, "peer": true }, + "compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3441,11 +3856,6 @@ "which": "^2.0.1" } }, - "css-unit-converter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", - "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" - }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3454,14 +3864,14 @@ "peer": true }, "csstype": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "d3-array": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.3.tgz", - "integrity": "sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "requires": { "internmap": "1 - 2" } @@ -3564,38 +3974,46 @@ } }, "downshift": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.3.tgz", - "integrity": "sha512-RA1MuaNcTbt0j+sVLhSs8R2oZbBXYAtdQP/V+uHhT3DoDteZzJPjlC+LQVm9T07Wpvo84QXaZtUCePLDTDwGXg==", + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.12.tgz", + "integrity": "sha512-7XB/iaSJVS4T8wGFT3WRXmSF1UlBHAA40DshZtkrIscIN+VC+Lh363skLxFTvJwtNgHxAMDGEHT4xsyQFWL+UA==", "requires": { - "@babel/runtime": "^7.13.10", + "@babel/runtime": "^7.14.8", "compute-scroll-into-view": "^1.0.17", "prop-types": "^15.7.2", - "react-is": "^17.0.2" - }, - "dependencies": { - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - } + "react-is": "^17.0.2", + "tslib": "^2.3.0" } }, "dropzone": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-4.3.0.tgz", - "integrity": "sha1-SLC48q0JKHLktTW2cqfD8aHWfJE=" + "integrity": "sha512-KAP4sc9wjaU5xLhZ7olSH1ni72IbXk2l9iF9Ai5p3slwDtKTJunKkQpdFg7voyOcUU+6j75xEhHh+yPqd/Z/PA==" + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "peer": true }, "electron-to-chromium": { - "version": "1.3.629", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz", - "integrity": "sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ==", + "version": "1.4.707", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.707.tgz", + "integrity": "sha512-qRq74Mo7ChePOU6GHdfAJ0NREXU8vQTlVlfWz3wNygFay6xrd/fY2J7oGHwrhFeU30OVctGLdTh/FcnokTWpng==", "dev": true }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "peer": true + }, "enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -3603,21 +4021,21 @@ } }, "envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", + "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", "dev": true }, "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", "dev": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true }, "eslint-scope": { @@ -3640,9 +4058,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -3659,9 +4077,9 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, "fast-deep-equal": { @@ -3676,9 +4094,9 @@ "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==" }, "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.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "peer": true, "requires": { @@ -3714,9 +4132,9 @@ "dev": true }, "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "peer": true, "requires": { @@ -3733,49 +4151,68 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flowbite": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.6.5.tgz", - "integrity": "sha512-eI4h3pIRI9d7grlYq14r0A01KUtw7189sPLLx/O2i7JyPEWpbleScfYuEc48XTeNjk1xxm/JHgZkD9kjyOWAlA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.8.1.tgz", + "integrity": "sha512-lXTcO8a6dRTPFpINyOLcATCN/pK1Of/jY4PryklPllAiqH64tSDUsOdQpar3TO59ZXWwugm2e92oaqwH6X90Xg==", "requires": { "@popperjs/core": "^2.9.3", "mini-svg-data-uri": "^1.4.3" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, - "peer": true + "peer": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } }, "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, "peer": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "peer": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" } }, "glob-parent": { @@ -3795,102 +4232,36 @@ "dev": true }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "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 }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "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==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "peer": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "peer": true - }, "internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -3913,12 +4284,12 @@ } }, "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "requires": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "is-extglob": { @@ -3928,6 +4299,13 @@ "dev": true, "peer": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3957,7 +4335,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isobject": { @@ -3966,6 +4344,17 @@ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "peer": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -3978,9 +4367,9 @@ } }, "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, "peer": true }, @@ -4027,6 +4416,15 @@ "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -4040,6 +4438,13 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "peer": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -4065,18 +4470,18 @@ } }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "mime-db": "1.44.0" + "mime-db": "1.52.0" } }, "mini-svg-data-uri": { @@ -4085,19 +4490,26 @@ "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==" }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "peer": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" } }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "peer": true + }, "minisearch": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-3.0.2.tgz", - "integrity": "sha512-7rTrJEzovKNi5LSwiIr5aCfJNNo6Lk4O9HTVzjFTMdp+dSr6UisUnEqdwj4rBgNcAcaWW5ClpXnpgTurv8PGqA==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-3.3.0.tgz", + "integrity": "sha512-DlOEfLtiRKcEuShEaaufoDpWKv94lWDSRK7Bkcd0htqHEFZ1vqTi3IIW8cYcPIlomQjaCdiZXk4pyzBNc79I2Q==" }, "mz": { "version": "2.7.0", @@ -4112,9 +4524,9 @@ } }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "peer": true }, @@ -4125,9 +4537,9 @@ "dev": true }, "node-releases": { - "version": "1.1.67", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", - "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "normalize-path": { @@ -4140,7 +4552,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-hash": { "version": "3.0.0", @@ -4149,14 +4561,22 @@ "dev": true, "peer": true }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "peer": true, "requires": { - "wrappy": "1" + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" } }, "p-try": { @@ -4176,13 +4596,6 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "peer": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -4195,12 +4608,22 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true + "dev": true }, "picomatch": { "version": "2.3.1", @@ -4217,20 +4640,29 @@ "peer": true }, "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, "peer": true }, + "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==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "peer": true, "requires": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -4245,15 +4677,6 @@ "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "peer": true - } } }, "postcss-js": { @@ -4267,14 +4690,23 @@ } }, "postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dev": true, "peer": true, "requires": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "dependencies": { + "lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "peer": true + } } }, "postcss-nested": { @@ -4288,9 +4720,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", "dev": true, "peer": true, "requires": { @@ -4299,24 +4731,33 @@ } }, "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "peer": true }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "queue-microtask": { @@ -4336,43 +4777,38 @@ } }, "react": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", - "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "react-dom": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", - "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "scheduler": "^0.20.1" + "scheduler": "^0.20.2" } }, "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-plaid-link": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/react-plaid-link/-/react-plaid-link-3.3.2.tgz", - "integrity": "sha512-W2L9C4RCE/KFFia2SUFFTi8SYRQ1UMUXh4iLE/oo4EQ8UYAT6msKzWvauj8bJirlrkzeiUtY6wgkmWil/okaNg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/react-plaid-link/-/react-plaid-link-3.5.1.tgz", + "integrity": "sha512-OSbPVEIQY3RDroDGyimRh9vUpZfSVzKVCwrbGOSIjcmluHnPKTkvJ1BnYbvE7kH+v8urJXMHloV43uMTNY3SLg==", "requires": { "prop-types": "^15.7.2", "react-script-hook": "^1.6.0" @@ -4385,32 +4821,24 @@ "requires": { "react-fast-compare": "^3.0.1", "warning": "^4.0.2" - }, - "dependencies": { - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } - } } }, "react-prop-types": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz", - "integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=", + "integrity": "sha512-IyjsJhDX9JkoOV9wlmLaS7z+oxYoIWhfzDcFy7inwoAKTu+VcVNrVpPmLeioJ94y6GeDRsnwarG1py5qofFQMg==", "requires": { "warning": "^3.0.0" - } - }, - "react-resize-detector": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz", - "integrity": "sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==", - "requires": { - "lodash": "^4.17.21" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==", + "requires": { + "loose-envify": "^1.0.0" + } + } } }, "react-script-hook": { @@ -4429,39 +4857,19 @@ } }, "react-smooth": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.3.tgz", - "integrity": "sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.0.tgz", + "integrity": "sha512-2NMXOBY1uVUQx1jBeENGA497HK20y6CPGYL1ZnJLeoQ8rrc3UfmOM82sRxtzpcoCkUMy4CS0RGylfuVhuFjBgg==", "requires": { - "fast-equals": "^5.0.0", - "react-transition-group": "2.9.0" - }, - "dependencies": { - "dom-helpers": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", - "requires": { - "@babel/runtime": "^7.1.2" - } - }, - "react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", - "requires": { - "dom-helpers": "^3.4.0", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" - } - } + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" } }, "react-transition-group": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "requires": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -4490,19 +4898,25 @@ } }, "recharts": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.6.2.tgz", - "integrity": "sha512-dVhNfgI21LlF+4AesO3mj+i+9YdAAjoGaDWIctUgH/G2iy14YVtb/DSUeic77xr19rbKCiq+pQGfeg2kJQDHig==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.2.tgz", + "integrity": "sha512-9bpxjXSF5g81YsKkTSlaX7mM4b6oYI1mIYck6YkUcWuL3tomADccI51/6thY4LmvhYuRTwpfrOvE80Zc3oBRfQ==", "requires": { - "classnames": "^2.2.5", + "clsx": "^2.0.0", "eventemitter3": "^4.0.1", - "lodash": "^4.17.19", + "lodash": "^4.17.21", "react-is": "^16.10.2", - "react-resize-detector": "^8.0.4", - "react-smooth": "^2.0.2", + "react-smooth": "^4.0.0", "recharts-scale": "^0.4.4", - "reduce-css-calc": "^2.1.8", + "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } } }, "recharts-scale": { @@ -4522,27 +4936,18 @@ "resolve": "^1.20.0" } }, - "reduce-css-calc": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", - "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", - "requires": { - "css-unit-converter": "^1.1.1", - "postcss-value-parser": "^3.3.0" - } - }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "requires": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -4586,18 +4991,18 @@ "dev": true }, "scheduler": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz", - "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "requires": { "@types/json-schema": "^7.0.8", @@ -4606,9 +5011,9 @@ } }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -4638,6 +5043,13 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true + }, "signature_pad": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-2.3.2.tgz", @@ -4666,29 +5078,99 @@ "source-map": "^0.6.0" } }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "peer": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true + } + } + }, "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, "peer": true, "requires": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "7.1.6", + "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "peer": true - } } }, "supports-color": { @@ -4707,9 +5189,9 @@ "dev": true }, "tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", "dev": true, "peer": true, "requires": { @@ -4718,10 +5200,10 @@ "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -4733,18 +5215,8 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "peer": true - } } }, "tapable": { @@ -4754,28 +5226,36 @@ "dev": true }, "terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", + "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", "dev": true, "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } } }, "terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.14", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" } }, "thenify": { @@ -4798,6 +5278,11 @@ "thenify": ">= 3.1.0 < 4" } }, + "tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4811,7 +5296,7 @@ "trim-canvas": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/trim-canvas/-/trim-canvas-0.1.2.tgz", - "integrity": "sha1-YgRX9f7PVktSHTXF/NTaWDBNbkU=" + "integrity": "sha512-nd4Ga3iLFV94mdhW9JFMLpQbHUyCQuhFOD71PEAt1NjtMD5wbZctzhX8c3agHNybMR5zXD1XTGoIEWk995E6pQ==" }, "ts-interface-checker": { "version": "0.1.13", @@ -4821,11 +5306,26 @@ "peer": true }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4843,9 +5343,9 @@ "peer": true }, "victory-vendor": { - "version": "36.6.10", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.10.tgz", - "integrity": "sha512-7YqYGtsA4mByokBhCjk+ewwPhUfzhR1I3Da6/ZsZUv/31ceT77RKoaqrxRq5Ki+9we4uzf7+A+7aG2sfYhm7nA==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", "requires": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -4864,17 +5364,17 @@ } }, "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", "requires": { "loose-envify": "^1.0.0" } }, "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -4882,22 +5382,22 @@ } }, "webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -4906,25 +5406,25 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" } }, "webpack-cli": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", - "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.1", - "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.1", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", "colorette": "^2.0.14", - "commander": "^9.4.1", + "commander": "^10.0.1", "cross-spawn": "^7.0.3", "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", @@ -4934,27 +5434,22 @@ "webpack-merge": "^5.7.3" }, "dependencies": { - "colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, "commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true } } }, "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, "requires": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" } }, @@ -4974,22 +5469,87 @@ } }, "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "peer": true + "peer": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true + }, + "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, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } }, "yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "dev": true, "peer": true } diff --git a/resources/functions.edn b/resources/functions.edn index b4802409..9c6497a0 100644 --- a/resources/functions.edn +++ b/resources/functions.edn @@ -1 +1 @@ -[#:db{:ident :pay, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e amount], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) amount (genfn-coerce-arg amount)] (do (let [current-outstanding-balance (-> (dc/pull db [:invoice/outstanding-balance] e) :invoice/outstanding-balance) new-outstanding-balance (- current-outstanding-balance amount)] [[:upsert-invoice {:invoice/status (if (> new-outstanding-balance 0) :invoice-status/unpaid :invoice-status/paid), :db/id e, :invoice/outstanding-balance new-outstanding-balance}]]))))))"}} #:db{:ident :plus, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e a amount], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) a (genfn-coerce-arg a) amount (genfn-coerce-arg amount)] (do [[:db/add e a (-> (dc/pull db [a] e) a (+ amount))]])))))"}} #:db{:ident :propose-invoice, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db invoice], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [invoice (genfn-coerce-arg invoice)] (do (let [existing? (boolean (seq (dc/q (quote [:find ?i :in $ ?invoice-number ?client ?vendor :where [?i :invoice/invoice-number ?invoice-number] [?i :invoice/client ?client] [?i :invoice/vendor ?vendor] (not [?i :invoice/status :invoice-status/voided])]) db (:invoice/invoice-number invoice) (:invoice/client invoice) (:invoice/vendor invoice))))] (if existing? [] [[:upsert-invoice invoice]])))))))"}} #:db{:ident :reset-rels, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e a vs], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) a (genfn-coerce-arg a) vs (genfn-coerce-arg vs)] (do (assert (every? :db/id vs) (format \"In order to reset attribute %s, every value must have :db/id\" a)) (let [ids (when-not (string? e) (->> (dc/q (quote [:find ?z :in $ ?e ?a :where [?e ?a ?z]]) db e a) (map first))) new-id-set (set (map :db/id vs)) retract-ids (filter (complement new-id-set) ids) {is-component? :db/isComponent} (dc/pull db [:db/isComponent] a) new-rels (filter (complement (set ids)) (map :db/id vs))] (-> [] (into (map (fn [i] (if is-component? [:db/retractEntity i] [:db/retract e a i])) retract-ids)) (into (map (fn [i] [:db/add e a i]) new-rels)) (into (map (fn [i] [:upsert-entity i]) vs)))))))))"}} #:db{:ident :reset-scalars, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e a vs], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) a (genfn-coerce-arg a) vs (genfn-coerce-arg vs)] (do (let [extant (when-not (string? e) (->> (dc/q (quote [:find ?z :in $ ?e ?a :where [?e ?a ?z]]) db e a) (map first))) retracts (filter (complement (set vs)) extant) new (filter (complement (set extant)) vs)] (-> [] (into (map (fn [i] [:db/retract e a i]) retracts)) (into (map (fn [i] [:db/add e a i]) new)))))))))"}} #:db{:ident :upsert-entity, :fn #db/fn{:lang :clojure, :imports [[java.util UUID]], :requires [[datomic.api :as dc]], :params [db entity], :code "(let [] (letfn [(-random-tempid [] (do (str (UUID/randomUUID)))) (-by [f fv xs] (do (reduce (fn* [p1__67490# p2__67491#] (assoc p1__67490# (f p2__67491#) (fv p2__67491#))) {} xs))) (-pull-many [db read ids] (do (->> (dc/q (quote [:find (pull ?e r) :in $ [?e ...] r]) db ids read) (map first))))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [entity (genfn-coerce-arg entity)] (do (when-not (or (:db/id entity) (:db/ident entity)) (datomic.api/cancel #:cognitect.anomalies{:message (str \"Cannot upsert without :db/id or :db/ident, \" entity), :category :cognitect.anomalies/incorrect})) (let [e (or (:db/id entity) (:db/ident entity)) is-new? (string? e) extant-entity (when-not is-new? (dc/pull db (keys entity) (or (:db/id entity) (:db/ident entity)))) ident->value-type (-by :db/ident (comp :db/ident :db/valueType) (-pull-many db [#:db{:valueType [:db/ident]} :db/ident] (keys entity))) ident->cardinality (-by :db/ident (comp :db/ident :db/cardinality) (-pull-many db [#:db{:cardinality [:db/ident]} :db/ident] (keys entity))) ops (->> entity (reduce (fn [ops [a v]] (cond (= :db/id a) ops (= :db/ident a) ops (or (= v (a extant-entity)) (= v (:db/ident (a extant-entity) :nope)) (= v (:db/id (a extant-entity)) :nope)) ops (and (nil? v) (not (nil? (a extant-entity)))) (if (= :db.cardinality/many (ident->cardinality a)) (into ops (map (fn [v] [:db/retract e a (cond-> v (:db/id v) :db/id)]) (a extant-entity))) (conj ops [:db/retract e a (cond-> (a extant-entity) (:db/id (a extant-entity)) :db/id)])) (nil? v) ops (and (sequential? v) (= :db.type/tuple (ident->value-type a)) (not (= :db.cardinality/many (ident->cardinality a)))) (conj ops [:db/add e a v]) (and (sequential? v) (= :db.type/ref (ident->value-type a)) (every? map? v)) (into ops [[:reset-rels e a v]]) (= :db.cardinality/many (ident->cardinality a)) (into ops [[:reset-scalars e a v]]) (and (sequential? v) (not= :db.type/ref (ident->value-type a))) (into ops [[:reset-scalars e a v]]) (and (map? v) (= :db.type/ref (ident->value-type a))) (let [id (or (:db/id v) (-random-tempid))] (-> ops (conj [:db/add e a id]) (into [[:upsert-entity (assoc v :db/id id)]]))) :else (conj ops [:db/add e a v]))) []))] ops))))))"}} #:db{:ident :upsert-invoice, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db invoice], :code "(let [] (letfn [(-remove-nils [m] (do (let [result (reduce-kv (fn [m k v] (if (not (nil? v)) (assoc m k v) m)) {} m)] (if (seq result) result nil)))) (invoice->journal-entry [db invoice-id raw-invoice-id] (do (let [entity (dc/pull db (quote [:invoice/total :invoice/exclude-from-ledger :invoice/outstanding-balance :invoice/date #:invoice{:client [:db/id :client/code], :status [:db/ident], :import-status [:db/ident], :vendor [:db/id :vendor/name], :payment [:db/id #:payment{:status [:db/ident]}], :expense-accounts [:invoice-expense-account/account :invoice-expense-account/amount :invoice-expense-account/location]}]) invoice-id) credit-invoice? (< (:invoice/total entity 0.0) 0.0)] (when-not (or (not (:invoice/total entity)) (= true (:invoice/exclude-from-ledger entity)) (= :import-status/pending (:db/ident (:invoice/import-status entity))) (= :invoice-status/voided (:db/ident (:invoice/status entity))) (< -0.001 (:invoice/total entity) 0.001)) (-remove-nils #:journal-entry{:date (:invoice/date entity), :original-entity raw-invoice-id, :client (:db/id (:invoice/client entity)), :line-items (into [(cond-> {:journal-entry-line/account :account/accounts-payable, :db/id (str raw-invoice-id \"-\" 0), :journal-entry-line/location \"A\"} credit-invoice? (assoc :journal-entry-line/debit (Math/abs (:invoice/total entity))) (not credit-invoice?) (assoc :journal-entry-line/credit (Math/abs (:invoice/total entity))))] (map-indexed (fn [i ea] (cond-> {:journal-entry-line/account (:db/id (:invoice-expense-account/account ea)), :db/id (str raw-invoice-id \"-\" (inc i)), :journal-entry-line/location (or (:invoice-expense-account/location ea) \"HQ\")} credit-invoice? (assoc :journal-entry-line/credit (Math/abs (:invoice-expense-account/amount ea))) (not credit-invoice?) (assoc :journal-entry-line/debit (Math/abs (:invoice-expense-account/amount ea))))) (:invoice/expense-accounts entity))), :source \"invoice\", :cleared (and (< (:invoice/outstanding-balance entity) 0.01) (every? (fn* [p1__67493#] (= :payment-status/cleared (:payment/status p1__67493#))) (:invoice/payments entity))), :amount (Math/abs (:invoice/total entity)), :vendor (:db/id (:invoice/vendor entity))})))))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [invoice (genfn-coerce-arg invoice)] (do (let [upserted-entity [[:upsert-entity invoice]] with-invoice (dc/with db upserted-entity) invoice-id (or (-> with-invoice :tempids (get (:db/id invoice))) (:db/id invoice)) journal-entry (invoice->journal-entry (:db-after with-invoice) invoice-id (:db/id invoice))] (into upserted-entity (if journal-entry [[:upsert-ledger journal-entry]] [[:db/retractEntity [:journal-entry/original-entity (:db/id invoice)]]]))))))))"}} #:db{:ident :upsert-ledger, :fn #db/fn{:lang :clojure, :imports [[java.util UUID]], :requires [[datomic.api :as dc]], :params [db ledger-entry], :code "(let [extant-read (quote [:db/id :journal-entry/date :journal-entry/client #:journal-entry{:line-items [:journal-entry-line/account :journal-entry-line/location :db/id :journal-entry-line/client+account+location+date]}])] (letfn [(-random-tempid [] (do (dc/tempid :db.part/user))) (get-line-items-after [db journal-entry] (do (for [jel (:journal-entry/line-items journal-entry) next-jel (->> (dc/index-pull db {:selector [:db/id :journal-entry-line/client+account+location+date], :index :avet, :start [:journal-entry-line/client+account+location+date (:journal-entry-line/client+account+location+date jel) (:db/id jel)]}) (take-while (fn line-must-match-client-account-location [result] (and (= (take 3 (:journal-entry-line/client+account+location+date result)) (take 3 (:journal-entry-line/client+account+location+date jel))) (not= (:db/id jel) (:db/id result))))) (take 2)) :when next-jel] (:db/id next-jel)))) (calc-client+account+location+date [je jel] (do [(or (:db/id (:journal-entry/client je)) (:journal-entry/client je)) (or (:db/id (:journal-entry-line/account jel)) (:journal-entry-line/account jel)) (-> jel :journal-entry-line/location) (-> je :journal-entry/date)]))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [ledger-entry (genfn-coerce-arg ledger-entry)] (do (assert (:journal-entry/date ledger-entry) (format \"Must at least provide date when updating ledger: %s\" (pr-str ledger-entry))) (assert (:journal-entry/client ledger-entry) \"Must at least provide client when updating ledger\") (let [extant-entry (or (when-let [original-entity (:journal-entry/original-entity ledger-entry)] (dc/pull db extant-read [:journal-entry/original-entity original-entity])) (when-let [external-id (:journal-entry/external-id ledger-entry)] (dc/pull db extant-read [:journal-entry/external-id external-id]))) extant-entry-exists? (:db/id extant-entry)] (cond-> [[:upsert-entity (into (-> ledger-entry (assoc :db/id (or (:db/id ledger-entry) (:db/id extant-entry) (-random-tempid))) (update :journal-entry/line-items (fn [lis] (mapv (fn* [p1__67497#] (-> p1__67497# (assoc :journal-entry-line/dirty true) (assoc :journal-entry-line/client+account+location+date (calc-client+account+location+date ledger-entry p1__67497#)))) lis)))))]] extant-entry-exists? (into (map (fn [li] {:db/id li, :journal-entry-line/dirty true}) (get-line-items-after db extant-entry))))))))))"}} #:db{:ident :upsert-transaction, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db transaction], :code "(let [my-transaction {:transaction/bank-account 17592232681223, :transaction/date (read-string \"#inst \\\"2024-02-24T08:00:00.000-00:00\\\"\"), :transaction/matched-rule 17592233159891, :transaction/client 17592232577980, :transaction/status \"POSTED\", :transaction/plaid-merchant {:plaid-merchant/name \"Rotten Robbie\", :db/id \"b2776792-9e2b-46e8-a9c8-bf80abea359e\"}, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc\", :transaction/id \"11a4a13e713d63f476009027e9a53e217e13d0192a37df8ab96c0eed4bdbe996\", :transaction/description-original \"Rotten Robbie #03\", :transaction/approval-status #:db{:id 17592231963877, :ident :transaction-approval-status/approved}, :transaction/amount -84.43, :transaction/accounts [{:transaction-account/account 17592231963549, :db/id \"c402c7b3-c11b-484b-b670-bd48f79a3e5f\", :transaction-account/location \"CB\", :transaction-account/amount 84.43}], :transaction/raw-id \"gQypbv5946F08op74wZmidDg8qD8Q1fM6gEBP\", :transaction/vendor 17592232627053} my-journal #:journal-entry{:vendor 17592232627053, :amount 84.43, :date (read-string \"#inst \\\"2024-02-24T08:00:00.000-00:00\\\"\"), :alternate-description \"Rotten Robbie #03\", :original-entity \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc\", :client 17592232577980, :source \"transaction\", :line-items [{:journal-entry-line/credit 84.43, :journal-entry-line/account 17592232681223, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc-0\", :journal-entry-line/location \"A\"} {:journal-entry-line/account 17592231963549, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc-1\", :journal-entry-line/debit 84.43, :journal-entry-line/location \"CB\"} {:journal-entry-line/account 17592231963549, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc-2\", :journal-entry-line/debit 84.43, :journal-entry-line/location \"CB\"}], :cleared true}] (letfn [(-remove-nils [m] (do (let [result (reduce-kv (fn [m k v] (if (not (nil? v)) (assoc m k v) m)) {} m)] (if (seq result) result nil)))) (transaction->journal-entry [db transaction-id raw-transaction-id] (do (let [entity (dc/pull db [:transaction/client :transaction/date :transaction/description-original :db/id :transaction/vendor :transaction/amount :transaction/cleared-against #:transaction{:bank-account [:db/id #:bank-account{:type [:db/ident]}], :approval-status [:db/ident], :accounts [:transaction-account/account :transaction-account/location :transaction-account/amount]}] transaction-id) decreasing? (< (or (:transaction/amount entity) 0.0) 0.0) credit-from-bank? decreasing? debit-from-bank? (not decreasing?)] (when (and (not (= :transaction-approval-status/excluded (:db/ident (:transaction/approval-status entity)))) (not (= :transaction-approval-status/suppressed (:db/ident (:transaction/approval-status entity)))) (:transaction/amount entity) (not (< -0.001 (:transaction/amount entity) 0.001))) (-remove-nils #:journal-entry{:vendor (:db/id (:transaction/vendor entity)), :amount (Math/abs (:transaction/amount entity)), :date (:transaction/date entity), :alternate-description (:transaction/description-original entity), :original-entity raw-transaction-id, :client (:db/id (:transaction/client entity)), :cleared-against (:transaction/cleared-against entity), :source \"transaction\", :line-items (into [(-remove-nils {:journal-entry-line/credit (when credit-from-bank? (Math/abs (:transaction/amount entity))), :journal-entry-line/account (:db/id (:transaction/bank-account entity)), :db/id (str raw-transaction-id \"-\" 0), :journal-entry-line/debit (when debit-from-bank? (Math/abs (:transaction/amount entity))), :journal-entry-line/location \"A\"})] (map-indexed (fn [i a] (-remove-nils {:journal-entry-line/credit (when debit-from-bank? (Math/abs (:transaction-account/amount a))), :journal-entry-line/account (:db/id (:transaction-account/account a)), :db/id (str raw-transaction-id \"-\" (inc i)), :journal-entry-line/debit (when credit-from-bank? (Math/abs (:transaction-account/amount a))), :journal-entry-line/location (:transaction-account/location a)})) (if (seq (:transaction/accounts entity)) (:transaction/accounts entity) [#:transaction-account{:amount (:transaction/amount entity)}]))), :cleared true})))))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [transaction (genfn-coerce-arg transaction)] (do (let [upserted-entity [[:upsert-entity (dissoc transaction :transaction/payment :import-batch/_entry)]] with-transaction (dc/with db upserted-entity) transaction-id (or (-> with-transaction :tempids (get (:db/id transaction))) (:db/id transaction)) journal-entry (transaction->journal-entry (:db-after with-transaction) transaction-id (:db/id transaction))] (into [[:upsert-entity transaction]] (if journal-entry [[:upsert-ledger journal-entry]] [[:db/retractEntity [:journal-entry/original-entity (:db/id transaction)]]]))))))))"}}] \ No newline at end of file +[#:db{:ident :pay, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e amount], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) amount (genfn-coerce-arg amount)] (do (let [current-outstanding-balance (-> (dc/pull db [:invoice/outstanding-balance] e) :invoice/outstanding-balance) new-outstanding-balance (- current-outstanding-balance amount)] [[:upsert-invoice {:invoice/status (if (< -1.0E-4 new-outstanding-balance 1.0E-4) :invoice-status/paid :invoice-status/unpaid), :db/id e, :invoice/outstanding-balance new-outstanding-balance}]]))))))"}} #:db{:ident :plus, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e a amount], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) a (genfn-coerce-arg a) amount (genfn-coerce-arg amount)] (do [[:db/add e a (-> (dc/pull db [a] e) a (+ amount))]])))))"}} #:db{:ident :propose-invoice, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db invoice], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [invoice (genfn-coerce-arg invoice)] (do (let [existing? (boolean (seq (dc/q (quote [:find ?i :in $ ?invoice-number ?client ?vendor :where [?i :invoice/invoice-number ?invoice-number] [?i :invoice/client ?client] [?i :invoice/vendor ?vendor] (not [?i :invoice/status :invoice-status/voided])]) db (:invoice/invoice-number invoice) (:invoice/client invoice) (:invoice/vendor invoice))))] (if existing? [] [[:upsert-invoice invoice]])))))))"}} #:db{:ident :reset-rels, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e a vs], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) a (genfn-coerce-arg a) vs (genfn-coerce-arg vs)] (do (assert (every? :db/id vs) (format \"In order to reset attribute %s, every value must have :db/id\" a)) (let [ids (when-not (string? e) (->> (dc/q (quote [:find ?z :in $ ?e ?a :where [?e ?a ?z]]) db e a) (map first))) new-id-set (set (map :db/id vs)) retract-ids (filter (complement new-id-set) ids) {is-component? :db/isComponent} (dc/pull db [:db/isComponent] a) new-rels (filter (complement (set ids)) (map :db/id vs))] (-> [] (into (map (fn [i] (if is-component? [:db/retractEntity i] [:db/retract e a i])) retract-ids)) (into (map (fn [i] [:db/add e a i]) new-rels)) (into (map (fn [i] [:upsert-entity i]) vs)))))))))"}} #:db{:ident :reset-scalars, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db e a vs], :code "(let [] (letfn [] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [e (genfn-coerce-arg e) a (genfn-coerce-arg a) vs (genfn-coerce-arg vs)] (do (let [extant (when-not (string? e) (->> (dc/q (quote [:find ?z :in $ ?e ?a :where [?e ?a ?z]]) db e a) (map first))) retracts (filter (complement (set vs)) extant) new (filter (complement (set extant)) vs)] (-> [] (into (map (fn [i] [:db/retract e a i]) retracts)) (into (map (fn [i] [:db/add e a i]) new)))))))))"}} #:db{:ident :upsert-entity, :fn #db/fn{:lang :clojure, :imports [[java.util UUID]], :requires [[datomic.api :as dc]], :params [db entity], :code "(let [] (letfn [(-random-tempid [] (do (str (UUID/randomUUID)))) (-by [f fv xs] (do (reduce (fn* [p1__703811# p2__703812#] (assoc p1__703811# (f p2__703812#) (fv p2__703812#))) {} xs))) (-pull-many [db read ids] (do (->> (dc/q (quote [:find (pull ?e r) :in $ [?e ...] r]) db ids read) (map first))))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [entity (genfn-coerce-arg entity)] (do (when-not (or (:db/id entity) (:db/ident entity)) (datomic.api/cancel #:cognitect.anomalies{:message (str \"Cannot upsert without :db/id or :db/ident, \" entity), :category :cognitect.anomalies/incorrect})) (let [e (or (:db/id entity) (:db/ident entity)) is-new? (string? e) extant-entity (when-not is-new? (dc/pull db (keys entity) (or (:db/id entity) (:db/ident entity)))) ident->value-type (-by :db/ident (comp :db/ident :db/valueType) (-pull-many db [#:db{:valueType [:db/ident]} :db/ident] (keys entity))) ident->cardinality (-by :db/ident (comp :db/ident :db/cardinality) (-pull-many db [#:db{:cardinality [:db/ident]} :db/ident] (keys entity))) ops (->> entity (reduce (fn [ops [a v]] (cond (= :db/id a) ops (= :db/ident a) ops (or (= v (a extant-entity)) (= v (:db/ident (a extant-entity) :nope)) (= v (:db/id (a extant-entity)) :nope)) ops (and (nil? v) (not (nil? (a extant-entity)))) (if (= :db.cardinality/many (ident->cardinality a)) (into ops (map (fn [v] [:db/retract e a (cond-> v (:db/id v) :db/id)]) (a extant-entity))) (conj ops [:db/retract e a (cond-> (a extant-entity) (:db/id (a extant-entity)) :db/id)])) (nil? v) ops (and (sequential? v) (= :db.type/tuple (ident->value-type a)) (not (= :db.cardinality/many (ident->cardinality a)))) (conj ops [:db/add e a v]) (and (sequential? v) (= :db.type/ref (ident->value-type a)) (every? map? v)) (into ops [[:reset-rels e a v]]) (= :db.cardinality/many (ident->cardinality a)) (into ops [[:reset-scalars e a v]]) (and (sequential? v) (not= :db.type/ref (ident->value-type a))) (into ops [[:reset-scalars e a v]]) (and (map? v) (= :db.type/ref (ident->value-type a))) (let [id (or (:db/id v) (-random-tempid))] (-> ops (conj [:db/add e a id]) (into [[:upsert-entity (assoc v :db/id id)]]))) :else (conj ops [:db/add e a v]))) []))] ops))))))"}} #:db{:ident :upsert-invoice, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db invoice], :code "(let [] (letfn [(-remove-nils [m] (do (let [result (reduce-kv (fn [m k v] (if (not (nil? v)) (assoc m k v) m)) {} m)] (if (seq result) result nil)))) (invoice->journal-entry [db invoice-id raw-invoice-id] (do (let [entity (dc/pull db (quote [:invoice/total :invoice/exclude-from-ledger :invoice/outstanding-balance :invoice/date #:invoice{:client [:db/id :client/code], :status [:db/ident], :import-status [:db/ident], :vendor [:db/id :vendor/name], :payment [:db/id #:payment{:status [:db/ident]}], :expense-accounts [:invoice-expense-account/account :invoice-expense-account/amount :invoice-expense-account/location]}]) invoice-id) credit-invoice? (< (:invoice/total entity 0.0) 0.0)] (when-not (or (not (:invoice/total entity)) (= true (:invoice/exclude-from-ledger entity)) (= :import-status/pending (:db/ident (:invoice/import-status entity))) (= :invoice-status/voided (:db/ident (:invoice/status entity))) (< -0.001 (:invoice/total entity) 0.001)) (-remove-nils #:journal-entry{:date (:invoice/date entity), :original-entity raw-invoice-id, :client (:db/id (:invoice/client entity)), :line-items (into [(cond-> {:journal-entry-line/account :account/accounts-payable, :db/id (str raw-invoice-id \"-\" 0), :journal-entry-line/location \"A\"} credit-invoice? (assoc :journal-entry-line/debit (Math/abs (:invoice/total entity))) (not credit-invoice?) (assoc :journal-entry-line/credit (Math/abs (:invoice/total entity))))] (map-indexed (fn [i ea] (cond-> {:journal-entry-line/account (:db/id (:invoice-expense-account/account ea)), :db/id (str raw-invoice-id \"-\" (inc i)), :journal-entry-line/location (or (:invoice-expense-account/location ea) \"HQ\")} credit-invoice? (assoc :journal-entry-line/credit (Math/abs (:invoice-expense-account/amount ea))) (not credit-invoice?) (assoc :journal-entry-line/debit (Math/abs (:invoice-expense-account/amount ea))))) (:invoice/expense-accounts entity))), :source \"invoice\", :cleared (and (< (:invoice/outstanding-balance entity) 0.01) (every? (fn* [p1__703814#] (= :payment-status/cleared (:payment/status p1__703814#))) (:invoice/payments entity))), :amount (Math/abs (:invoice/total entity)), :vendor (:db/id (:invoice/vendor entity))})))))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [invoice (genfn-coerce-arg invoice)] (do (let [upserted-entity [[:upsert-entity invoice]] with-invoice (dc/with db upserted-entity) invoice-id (or (-> with-invoice :tempids (get (:db/id invoice))) (:db/id invoice)) journal-entry (invoice->journal-entry (:db-after with-invoice) invoice-id (:db/id invoice))] (into upserted-entity (if journal-entry [[:upsert-ledger journal-entry]] [[:db/retractEntity [:journal-entry/original-entity (:db/id invoice)]]]))))))))"}} #:db{:ident :upsert-ledger, :fn #db/fn{:lang :clojure, :imports [[java.util UUID]], :requires [[datomic.api :as dc]], :params [db ledger-entry], :code "(let [extant-read (quote [:db/id :journal-entry/date :journal-entry/client #:journal-entry{:line-items [:journal-entry-line/account :journal-entry-line/location :db/id :journal-entry-line/client+account+location+date]}])] (letfn [(-random-tempid [] (do (dc/tempid :db.part/user))) (get-line-items-after [db journal-entry] (do (for [jel (:journal-entry/line-items journal-entry) next-jel (->> (dc/index-pull db {:selector [:db/id :journal-entry-line/client+account+location+date], :index :avet, :start [:journal-entry-line/client+account+location+date (:journal-entry-line/client+account+location+date jel) (:db/id jel)]}) (take-while (fn line-must-match-client-account-location [result] (and (= (take 3 (:journal-entry-line/client+account+location+date result)) (take 3 (:journal-entry-line/client+account+location+date jel))) (not= (:db/id jel) (:db/id result))))) (take 2)) :when next-jel] (:db/id next-jel)))) (calc-client+account+location+date [je jel] (do [(or (:db/id (:journal-entry/client je)) (:journal-entry/client je)) (or (:db/id (:journal-entry-line/account jel)) (:journal-entry-line/account jel)) (-> jel :journal-entry-line/location) (-> je :journal-entry/date)]))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [ledger-entry (genfn-coerce-arg ledger-entry)] (do (assert (:journal-entry/date ledger-entry) (format \"Must at least provide date when updating ledger: %s\" (pr-str ledger-entry))) (assert (:journal-entry/client ledger-entry) \"Must at least provide client when updating ledger\") (let [extant-entry (or (when-let [original-entity (:journal-entry/original-entity ledger-entry)] (dc/pull db extant-read [:journal-entry/original-entity original-entity])) (when-let [external-id (:journal-entry/external-id ledger-entry)] (dc/pull db extant-read [:journal-entry/external-id external-id]))) extant-entry-exists? (:db/id extant-entry)] (cond-> [[:upsert-entity (into (-> ledger-entry (assoc :db/id (or (:db/id ledger-entry) (:db/id extant-entry) (-random-tempid))) (update :journal-entry/line-items (fn [lis] (mapv (fn* [p1__703818#] (-> p1__703818# (assoc :journal-entry-line/dirty true) (assoc :journal-entry-line/client+account+location+date (calc-client+account+location+date ledger-entry p1__703818#)))) lis)))))]] extant-entry-exists? (into (map (fn [li] {:db/id li, :journal-entry-line/dirty true}) (get-line-items-after db extant-entry))))))))))"}} #:db{:ident :upsert-transaction, :fn #db/fn{:lang :clojure, :imports [], :requires [[datomic.api :as dc]], :params [db transaction], :code "(let [my-transaction {:transaction/bank-account 17592232681223, :transaction/date (read-string \"#inst \\\"2024-02-24T08:00:00.000-00:00\\\"\"), :transaction/matched-rule 17592233159891, :transaction/client 17592232577980, :transaction/status \"POSTED\", :transaction/plaid-merchant {:plaid-merchant/name \"Rotten Robbie\", :db/id \"b2776792-9e2b-46e8-a9c8-bf80abea359e\"}, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc\", :transaction/id \"11a4a13e713d63f476009027e9a53e217e13d0192a37df8ab96c0eed4bdbe996\", :transaction/description-original \"Rotten Robbie #03\", :transaction/approval-status #:db{:id 17592231963877, :ident :transaction-approval-status/approved}, :transaction/amount -84.43, :transaction/accounts [{:transaction-account/account 17592231963549, :db/id \"c402c7b3-c11b-484b-b670-bd48f79a3e5f\", :transaction-account/location \"CB\", :transaction-account/amount 84.43}], :transaction/raw-id \"gQypbv5946F08op74wZmidDg8qD8Q1fM6gEBP\", :transaction/vendor 17592232627053} my-journal #:journal-entry{:vendor 17592232627053, :amount 84.43, :date (read-string \"#inst \\\"2024-02-24T08:00:00.000-00:00\\\"\"), :alternate-description \"Rotten Robbie #03\", :original-entity \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc\", :client 17592232577980, :source \"transaction\", :line-items [{:journal-entry-line/credit 84.43, :journal-entry-line/account 17592232681223, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc-0\", :journal-entry-line/location \"A\"} {:journal-entry-line/account 17592231963549, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc-1\", :journal-entry-line/debit 84.43, :journal-entry-line/location \"CB\"} {:journal-entry-line/account 17592231963549, :db/id \"ac2efd80-bb03-48b2-b0d0-6b47a5c119dc-2\", :journal-entry-line/debit 84.43, :journal-entry-line/location \"CB\"}], :cleared true}] (letfn [(-remove-nils [m] (do (let [result (reduce-kv (fn [m k v] (if (not (nil? v)) (assoc m k v) m)) {} m)] (if (seq result) result nil)))) (transaction->journal-entry [db transaction-id raw-transaction-id] (do (let [entity (dc/pull db [:transaction/client :transaction/date :transaction/description-original :db/id :transaction/vendor :transaction/amount :transaction/cleared-against #:transaction{:bank-account [:db/id #:bank-account{:type [:db/ident]}], :approval-status [:db/ident], :accounts [:transaction-account/account :transaction-account/location :transaction-account/amount]}] transaction-id) decreasing? (< (or (:transaction/amount entity) 0.0) 0.0) credit-from-bank? decreasing? debit-from-bank? (not decreasing?)] (when (and (not (= :transaction-approval-status/excluded (:db/ident (:transaction/approval-status entity)))) (not (= :transaction-approval-status/suppressed (:db/ident (:transaction/approval-status entity)))) (:transaction/amount entity) (not (< -0.001 (:transaction/amount entity) 0.001))) (-remove-nils #:journal-entry{:vendor (:db/id (:transaction/vendor entity)), :amount (Math/abs (:transaction/amount entity)), :date (:transaction/date entity), :alternate-description (:transaction/description-original entity), :original-entity raw-transaction-id, :client (:db/id (:transaction/client entity)), :cleared-against (:transaction/cleared-against entity), :source \"transaction\", :line-items (into [(-remove-nils {:journal-entry-line/credit (when credit-from-bank? (Math/abs (:transaction/amount entity))), :journal-entry-line/account (:db/id (:transaction/bank-account entity)), :db/id (str raw-transaction-id \"-\" 0), :journal-entry-line/debit (when debit-from-bank? (Math/abs (:transaction/amount entity))), :journal-entry-line/location \"A\"})] (map-indexed (fn [i a] (-remove-nils {:journal-entry-line/credit (when debit-from-bank? (Math/abs (:transaction-account/amount a))), :journal-entry-line/account (:db/id (:transaction-account/account a)), :db/id (str raw-transaction-id \"-\" (inc i)), :journal-entry-line/debit (when credit-from-bank? (Math/abs (:transaction-account/amount a))), :journal-entry-line/location (:transaction-account/location a)})) (if (seq (:transaction/accounts entity)) (:transaction/accounts entity) [#:transaction-account{:amount (:transaction/amount entity)}]))), :cleared true})))))] (let [genfn-coerce-arg (clojure.core/fn [x] (clojure.walk/prewalk (clojure.core/fn [e] (if (clojure.core/some? e) (do (clojure.core/when (clojure.core/instance? clojure.lang.PersistentTreeMap e) (throw (clojure.core/ex-info \"Using sorted-map will cause different types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/var? e) (throw (clojure.core/ex-info \"Using var does not work for remote transactor\" {:val e}))) (clojure.core/when (clojure.core/or (clojure.core/= clojure.lang.PersistentList$EmptyList (.getClass e)) (clojure.core/instance? clojure.lang.PersistentList e)) (throw (clojure.core/ex-info \"Using list will cause indistinguishable types in transactor for in-mem and remote\" {:val e}))) (clojure.core/when (clojure.core/instance? clojure.lang.PersistentQueue e) (throw (clojure.core/ex-info \"Using clojure.lang.PersistentQueue does not work for remote transactor\" {:val e}))) (clojure.core/cond (clojure.core/instance? java.util.HashSet e) (clojure.core/into #{} e) (clojure.core/and (clojure.core/instance? java.util.List e) (clojure.core/not (clojure.core/vector? e))) (clojure.core/vec e) :else e)) e)) x))] (let [transaction (genfn-coerce-arg transaction)] (do (let [upserted-entity [[:upsert-entity (dissoc transaction :transaction/payment :import-batch/_entry)]] with-transaction (dc/with db upserted-entity) transaction-id (or (-> with-transaction :tempids (get (:db/id transaction))) (:db/id transaction)) journal-entry (transaction->journal-entry (:db-after with-transaction) transaction-id (:db/id transaction))] (into [[:upsert-entity transaction]] (if journal-entry [[:upsert-ledger journal-entry]] [[:db/retractEntity [:journal-entry/original-entity (:db/id transaction)]]]))))))))"}}] \ No newline at end of file diff --git a/resources/input.css b/resources/input.css index 650cf1fa..0bbe8621 100644 --- a/resources/input.css +++ b/resources/input.css @@ -135,6 +135,14 @@ display: inherit; } +.htmx-request .htmx-indicator-invisible { + visibility: hidden !important; +} + +.htmx-indicator-invisible { + display: inherit; +} + .htmx-swapping .fade-out { opacity: 0.0 !important; } diff --git a/resources/public/css/main.css b/resources/public/css/main.css index 70961a19..b7a31221 100644 --- a/resources/public/css/main.css +++ b/resources/public/css/main.css @@ -468,5 +468,4 @@ table.balance-sheet th.total { background-color: whitesmoke !important; border-color: whitesmoke !important; box-shadow: none; -} - +} \ No newline at end of file diff --git a/resources/public/js/alpine-vals.js b/resources/public/js/alpine-vals.js new file mode 100644 index 00000000..55af6cbf --- /dev/null +++ b/resources/public/js/alpine-vals.js @@ -0,0 +1,29 @@ +document.addEventListener('alpine:init', () => { + Alpine.directive('hx-val', (el, { value, expression }, { evaluateLater, effect, cleanup, evaluate }) => { + var config = function(evt) { + evt.detail.parameters[value] = evaluate(expression); // add a new parameter into the request + } + el.addEventListener('htmx:configRequest', config); + cleanup(() => { + el.removeEventListener('htmx:configRequest', config); + }) + }) + + Alpine.directive('dispatch', (el, { value, expression }, { evaluateLater, effect, cleanup, evaluate }) => { + let dependent_properties = evaluateLater(expression) + + effect(() => { + dependent_properties(props => { + el.dispatchEvent( + new CustomEvent(value, { + props, + bubbles: true, + // Allows events to pass the shadow DOM barrier. + composed: true, + cancelable: true, + }) + ) + }) + }) + }) +}) \ No newline at end of file diff --git a/resources/public/js/htmx-disable.js b/resources/public/js/htmx-disable.js index fa4f86f9..50891c95 100644 --- a/resources/public/js/htmx-disable.js +++ b/resources/public/js/htmx-disable.js @@ -122,7 +122,7 @@ htmx.defineExtension('trigger-filter', { initDatepicker = function(elem) { const modalParent = elem.closest('#modal-content'); if (modalParent) { - elem.dp = new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true, container: ".modal-stack"}); + elem.dp = new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true, container: "#modal-content .modal-card"}); } else { elem.dp = new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true}); } diff --git a/resources/public/output.css b/resources/public/output.css index 4f4f0be5..440bac81 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1 +1 @@ -/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-2{margin:.5rem}.m-4{margin:1rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-8{margin-right:2rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mr-16{margin-right:4rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-\[350px\]{height:350px}.h-\[600px\]{height:600px}.h-full{height:100%}.h-screen{height:100vh}.h-\[700px\]{height:700px}.max-h-0{max-height:0}.max-h-96{max-height:24rem}.max-h-screen{max-height:100vh}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-1\/4{width:25%}.w-16{width:4rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-72{width:18rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[10em\]{width:10em}.w-\[20em\]{width:20em}.w-\[30em\]{width:30em}.w-\[5em\]{width:5em}.w-\[600px\]{width:600px}.w-\[748px\]{width:748px}.w-\[7em\]{width:7em}.w-\[850px\]{width:850px}.w-\[8em\]{width:8em}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.max-w-6xl{max-width:72rem}.flex-1{flex:1 1 0%}.flex-initial{flex:0 1 auto}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-100,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes gentleGrow{0%{transform:scale(1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:scale(1.1);animation-timing-function:cubic-bezier(0,0,.2,1)}to{transform:scale(1);animation-timing-function:cubic-bezier(.8,0,1,1)}}.animate-gg{animation:gentleGrow 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-move{cursor:move}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-2{row-gap:.5rem}.gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.place-self-end{place-self:end}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-dotted{border-style:dotted}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-primary-600{--tw-border-opacity:1;border-color:rgb(97 145 37/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(246 245 255/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(255 3 3/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(252 233 106/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pr-6{padding-right:1.5rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[0\.6rem\]{font-size:.6rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-300{--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}.text-green-500{--tw-text-opacity:1;color:rgb(121 181 46/var(--tw-text-opacity))}.text-green-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-green-700{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-300{--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-purple-600{--tw-text-opacity:1;color:rgb(126 58 242/var(--tw-text-opacity))}.text-red-300{--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-added .swipe-left-swap,.htmx-added.swipe-left-swap{opacity:1!important;--tw-scale-x:1!important;--tw-scale-y:1!important;--tw-translate-x:-50%!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.swipe-left-swap{opacity:1;--tw-scale-x:1;--tw-scale-y:1;--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-settling.htmx-added .swipe-left-swap,.htmx-settling.htmx-added.swipe-left-swap{opacity:0!important;--tw-scale-x:.75!important;--tw-scale-y:.75!important;--tw-translate-x:50%!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}.live-removed{animation:pulse-red .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-removed{animation:pulse-dark-red .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}@keyframes pulse-red{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-red{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.ct-series-a .ct-bar{stroke:#79b52e;fill:#79b52e;stroke-width:20px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:border-green-300:hover{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-200:hover{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-400:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(148 196 88/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}.peer:hover~.peer-hover\:block{display:block}.htmx-swapping\:-translate-x-2\/3.htmx-swapping{--tw-translate-x:-66.666667%}.htmx-swapping\:-translate-x-2\/3.htmx-swapping,.htmx-swapping\:translate-x-2\/3.htmx-swapping{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping\:translate-x-2\/3.htmx-swapping{--tw-translate-x:66.666667%}.htmx-swapping\:scale-0.htmx-swapping{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping\:opacity-0.htmx-swapping{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:translate-x-1\/4.htmx-swapping{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:-translate-x-1\/4.htmx-swapping{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:scale-75.htmx-swapping,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:scale-75.htmx-swapping{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:opacity-0.htmx-swapping,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:opacity-0.htmx-swapping{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:ease-in.htmx-swapping,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:ease-in.htmx-swapping{transition-timing-function:cubic-bezier(.4,0,1,1)}.htmx-swapping .htmx-swapping\:-translate-x-2\/3{--tw-translate-x:-66.666667%}.htmx-swapping .htmx-swapping\:-translate-x-2\/3,.htmx-swapping .htmx-swapping\:translate-x-2\/3{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping .htmx-swapping\:translate-x-2\/3{--tw-translate-x:66.666667%}.htmx-swapping .htmx-swapping\:scale-0{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping .htmx-swapping\:opacity-0{opacity:0}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:translate-x-1\/4{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:-translate-x-1\/4{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:scale-75,.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:scale-75{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:opacity-0,.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:opacity-0{opacity:0}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:ease-in,.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.htmx-added\:-translate-x-2\/3.htmx-added{--tw-translate-x:-66.666667%}.htmx-added\:-translate-x-2\/3.htmx-added,.htmx-added\:translate-x-2\/3.htmx-added{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added\:translate-x-2\/3.htmx-added{--tw-translate-x:66.666667%}.htmx-added\:scale-0.htmx-added{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added\:opacity-0.htmx-added{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:-translate-x-1\/4.htmx-added{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:translate-x-1\/4.htmx-added{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:scale-75.htmx-added,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:scale-75.htmx-added{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:opacity-0.htmx-added,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:opacity-0.htmx-added{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:ease-out.htmx-added,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:ease-out.htmx-added{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .htmx-added\:-translate-x-2\/3{--tw-translate-x:-66.666667%}.htmx-added .htmx-added\:-translate-x-2\/3,.htmx-added .htmx-added\:translate-x-2\/3{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added .htmx-added\:translate-x-2\/3{--tw-translate-x:66.666667%}.htmx-added .htmx-added\:scale-0{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added .htmx-added\:opacity-0{opacity:0}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:-translate-x-1\/4{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:translate-x-1\/4{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:scale-75,.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:scale-75{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:opacity-0,.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:opacity-0{opacity:0}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:ease-out,.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-400){--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-green-800){--tw-border-opacity:1;border-color:rgb(48 72 18/var(--tw-border-opacity))}:is(.dark .dark\:border-primary-500){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-100){--tw-text-opacity:1;color:rgb(204 235 251/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-green-400){--tw-text-opacity:1;color:rgb(148 196 88/var(--tw-text-opacity))}:is(.dark .dark\:text-primary-500){--tw-text-opacity:1;color:rgb(121 181 46/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .hover\:dark\:border-green-800):hover{--tw-border-opacity:1;border-color:rgb(48 72 18/var(--tw-border-opacity))}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .hover\:dark\:bg-gray-800):hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .hover\:dark\:text-green-400):hover{--tw-text-opacity:1;color:rgb(148 196 88/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:ml-4{margin-left:1rem}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.sm\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:block{display:block}.md\:table-cell{display:table-cell}.md\:h-\[600px\]{height:600px}.md\:w-\[750px\]{width:750px}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:-translate-x-full{--tw-translate-x:-100%}.lg\:-translate-x-full,.lg\:translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:translate-x-0{--tw-translate-x:0px}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file +/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-2{margin:.5rem}.m-4{margin:1rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-8{margin-right:2rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-\[350px\]{height:350px}.h-\[600px\]{height:600px}.h-full{height:100%}.h-screen{height:100vh}.max-h-0{max-height:0}.max-h-96{max-height:24rem}.max-h-screen{max-height:100vh}.w-1\/2{width:50%}.w-1\/4{width:25%}.w-16{width:4rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-72{width:18rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[10em\]{width:10em}.w-\[20em\]{width:20em}.w-\[30em\]{width:30em}.w-\[5em\]{width:5em}.w-\[600px\]{width:600px}.w-\[748px\]{width:748px}.w-\[7em\]{width:7em}.w-\[850px\]{width:850px}.w-\[8em\]{width:8em}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.max-w-2xl{max-width:42rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.flex-1{flex:1 1 0%}.flex-initial{flex:0 1 auto}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-100,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes gentleGrow{0%{transform:scale(1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:scale(1.1);animation-timing-function:cubic-bezier(0,0,.2,1)}to{transform:scale(1);animation-timing-function:cubic-bezier(.8,0,1,1)}}.animate-gg{animation:gentleGrow 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-move{cursor:move}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-2{row-gap:.5rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.place-self-end{place-self:end}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-dotted{border-style:dotted}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-primary-600{--tw-border-opacity:1;border-color:rgb(97 145 37/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(246 245 255/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(255 3 3/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(252 233 106/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pr-6{padding-right:1.5rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[0\.6rem\]{font-size:.6rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-300{--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}.text-green-500{--tw-text-opacity:1;color:rgb(121 181 46/var(--tw-text-opacity))}.text-green-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-green-700{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-300{--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-purple-600{--tw-text-opacity:1;color:rgb(126 58 242/var(--tw-text-opacity))}.text-red-300{--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-added .swipe-left-swap,.htmx-added.swipe-left-swap{opacity:1!important;--tw-scale-x:1!important;--tw-scale-y:1!important;--tw-translate-x:-50%!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.swipe-left-swap{opacity:1;--tw-scale-x:1;--tw-scale-y:1;--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-settling.htmx-added .swipe-left-swap,.htmx-settling.htmx-added.swipe-left-swap{opacity:0!important;--tw-scale-x:.75!important;--tw-scale-y:.75!important;--tw-translate-x:50%!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}.live-removed{animation:pulse-red .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-removed{animation:pulse-dark-red .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}@keyframes pulse-red{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-red{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-request .htmx-indicator-invisible{visibility:hidden!important}.htmx-indicator-invisible{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.ct-series-a .ct-bar{stroke:#79b52e;fill:#79b52e;stroke-width:20px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:border-green-300:hover{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-200:hover{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-400:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(148 196 88/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}.peer:hover~.peer-hover\:block{display:block}.htmx-swapping\:-translate-x-2\/3.htmx-swapping{--tw-translate-x:-66.666667%}.htmx-swapping\:-translate-x-2\/3.htmx-swapping,.htmx-swapping\:translate-x-2\/3.htmx-swapping{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping\:translate-x-2\/3.htmx-swapping{--tw-translate-x:66.666667%}.htmx-swapping\:scale-0.htmx-swapping{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping\:opacity-0.htmx-swapping{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:translate-x-1\/4.htmx-swapping{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:-translate-x-1\/4.htmx-swapping{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:scale-75.htmx-swapping,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:scale-75.htmx-swapping{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:opacity-0.htmx-swapping,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:opacity-0.htmx-swapping{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-swapping\:ease-in.htmx-swapping,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-swapping\:ease-in.htmx-swapping{transition-timing-function:cubic-bezier(.4,0,1,1)}.htmx-swapping .htmx-swapping\:-translate-x-2\/3{--tw-translate-x:-66.666667%}.htmx-swapping .htmx-swapping\:-translate-x-2\/3,.htmx-swapping .htmx-swapping\:translate-x-2\/3{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping .htmx-swapping\:translate-x-2\/3{--tw-translate-x:66.666667%}.htmx-swapping .htmx-swapping\:scale-0{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-swapping .htmx-swapping\:opacity-0{opacity:0}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:translate-x-1\/4{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:-translate-x-1\/4{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:scale-75,.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:scale-75{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:opacity-0,.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:opacity-0{opacity:0}.group\/transition.backward .htmx-swapping .group-\[\.backward\]\/transition\:htmx-swapping\:ease-in,.group\/transition.forward .htmx-swapping .group-\[\.forward\]\/transition\:htmx-swapping\:ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.htmx-added\:-translate-x-2\/3.htmx-added{--tw-translate-x:-66.666667%}.htmx-added\:-translate-x-2\/3.htmx-added,.htmx-added\:translate-x-2\/3.htmx-added{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added\:translate-x-2\/3.htmx-added{--tw-translate-x:66.666667%}.htmx-added\:scale-0.htmx-added{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added\:opacity-0.htmx-added{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:-translate-x-1\/4.htmx-added{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:translate-x-1\/4.htmx-added{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:scale-75.htmx-added,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:scale-75.htmx-added{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:opacity-0.htmx-added,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:opacity-0.htmx-added{opacity:0}.group\/transition.backward .group-\[\.backward\]\/transition\:htmx-added\:ease-out.htmx-added,.group\/transition.forward .group-\[\.forward\]\/transition\:htmx-added\:ease-out.htmx-added{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .htmx-added\:-translate-x-2\/3{--tw-translate-x:-66.666667%}.htmx-added .htmx-added\:-translate-x-2\/3,.htmx-added .htmx-added\:translate-x-2\/3{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added .htmx-added\:translate-x-2\/3{--tw-translate-x:66.666667%}.htmx-added .htmx-added\:scale-0{--tw-scale-x:0;--tw-scale-y:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-added .htmx-added\:opacity-0{opacity:0}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:-translate-x-1\/4{--tw-translate-x:-25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:translate-x-1\/4{--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:scale-75,.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:scale-75{--tw-scale-x:.75;--tw-scale-y:.75;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:opacity-0,.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:opacity-0{opacity:0}.group\/transition.backward .htmx-added .group-\[\.backward\]\/transition\:htmx-added\:ease-out,.group\/transition.forward .htmx-added .group-\[\.forward\]\/transition\:htmx-added\:ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-400){--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-green-800){--tw-border-opacity:1;border-color:rgb(48 72 18/var(--tw-border-opacity))}:is(.dark .dark\:border-primary-500){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-100){--tw-text-opacity:1;color:rgb(204 235 251/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-green-400){--tw-text-opacity:1;color:rgb(148 196 88/var(--tw-text-opacity))}:is(.dark .dark\:text-primary-500){--tw-text-opacity:1;color:rgb(121 181 46/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .hover\:dark\:border-green-800):hover{--tw-border-opacity:1;border-color:rgb(48 72 18/var(--tw-border-opacity))}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .hover\:dark\:bg-gray-800):hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .hover\:dark\:text-green-400):hover{--tw-text-opacity:1;color:rgb(148 196 88/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:ml-4{margin-left:1rem}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.sm\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:block{display:block}.md\:table-cell{display:table-cell}.md\:h-\[600px\]{height:600px}.md\:w-\[750px\]{width:750px}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file diff --git a/resources/schema.edn b/resources/schema.edn index d2216645..3092422f 100644 --- a/resources/schema.edn +++ b/resources/schema.edn @@ -1334,10 +1334,7 @@ :db/cardinality #:db{:ident :db.cardinality/one}, :db/doc "The specific client this rule is for", :db/ident :transaction-rule/client} - {:db/valueType #:db{:ident :db.type/string}, - :db/cardinality #:db{:ident :db.cardinality/one}, - :db/doc "The specific client group this rule is for", - :db/ident :transaction-rule/client-group} + {:db/valueType #:db{:ident :db.type/string}, :db/cardinality #:db{:ident :db.cardinality/one}, :db/doc "The specific client group this rule is for", :db/ident :transaction-rule/client-group} {:db/valueType #:db{:ident :db.type/ref}, :db/cardinality #:db{:ident :db.cardinality/one}, :db/doc "The specific bank account this rule is for", diff --git a/src/clj/auto_ap/datomic/clients.clj b/src/clj/auto_ap/datomic/clients.clj index a408e7ff..5e55b2f1 100644 --- a/src/clj/auto_ap/datomic/clients.clj +++ b/src/clj/auto_ap/datomic/clients.clj @@ -37,11 +37,10 @@ :bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance] :bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id] :bank-account/integration-status [:integration-status/message - :db/id - :integration-status/last-attempt - :integration-status/last-updated - {:integration-status/state [:db/ident]}]} - ]} + :db/id + :integration-status/last-attempt + :integration-status/last-updated + {:integration-status/state [:db/ident]}]}]} {:yodlee-provider-account/_client [*]} {:plaid-item/_client [*]} {:client/emails [:db/id :email-contact/email :email-contact/description]}]) @@ -61,7 +60,7 @@ (fn [bas] (map (fn [i ba] (-> ba - (update :bank-account/type :db/ident ) + (update :bank-account/type :db/ident) (update-in [:bank-account/integration-status :integration-status/state] :db/ident) (update-in [:bank-account/integration-status :integration-status/last-attempt] #(some-> % coerce/to-date-time)) (update-in [:bank-account/integration-status :integration-status/last-updated] #(some-> % coerce/to-date-time)) @@ -71,9 +70,9 @@ (defn get-all [] (->> (dc/q '[:find (pull ?e r) :in $ r - :where [?e :client/name]] - (dc/db conn) - full-read) + :where [?e :client/name]] + (dc/db conn) + full-read) (map first) (map cleanse))) @@ -98,23 +97,23 @@ (map cleanse))) (defn get-by-id [id] - (->> - (dc/pull (dc/db conn ) - full-read - id) + (->> + (dc/pull (dc/db conn) + full-read + id) (cleanse))) (defn code->id [code] - (->> + (->> (dc/q '[:find ?e - :in $ ?code - :where [?e :client/code ?code]] + :in $ ?code + :where [?e :client/code ?code]] (dc/db conn) code) (first) (first))) (defn best-match [identifier] - (when (and identifier (not-empty identifier)) + (when (and identifier (not-empty identifier)) (some-> (solr/query solr/impl "clients" {"query" (format "_text_:\"%s\"" (str/upper-case (solr/escape identifier))) "fields" "id"}) @@ -126,7 +125,7 @@ (defn exact-match [identifier] - (when (and identifier (not-empty identifier)) + (when (and identifier (not-empty identifier)) (some-> (solr/query solr/impl "clients" {"query" (format "exact:\"%s\"" (str/upper-case (solr/escape identifier))) "fields" "id"}) @@ -149,7 +148,6 @@ "code" (:client/code result) "exact" (map str/upper-case matches)}))) - (defn raw-graphql-ids [db args] (let [name-like-ids (cond (not (str/blank? (:name-like args))) (set (map (comp #(Long/parseLong %) :id) @@ -172,24 +170,24 @@ matching-ids) (set (map :db/id (:clients args)))) - + query (cond-> {:query {:find [] - :in ['$ ] + :in ['$] :where []} :args [db]} valid-ids (merge-query {:query {:in ['[?e ...]]} :args [(set valid-ids)]}) - + (:sort args) (add-sorter-fields {"name" ['[?e :client/name ?sort-name]]} args) true (merge-query {:query {:find ['?sort-default '?e] :where ['[?e :client/name ?sort-default]]}}))] (->> (query2 query) - (apply-sort-3 (update args :sort conj {:sort-key "default-2" :asc true})) - (apply-pagination args)))) + (apply-sort-3 (update args :sort conj {:sort-key "default-2" :asc true})) + (apply-pagination args)))) (defn graphql-results [ids db args] (let [results (->> (pull-many db full-read @@ -201,6 +199,6 @@ (defn get-graphql-page [args] (let [db (dc/db conn) {ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)] - + [(->> (graphql-results ids-to-retrieve db args)) matching-count])) diff --git a/src/clj/auto_ap/graphql/accounts.clj b/src/clj/auto_ap/graphql/accounts.clj index d2a53263..ffc03063 100644 --- a/src/clj/auto_ap/graphql/accounts.clj +++ b/src/clj/auto_ap/graphql/accounts.clj @@ -22,7 +22,7 @@ (defn get-all-graphql [context args _] (assert-admin (:id context)) (let [args (assoc args :id (:id context)) - [accounts _ ] (d-accounts/get-graphql (assoc (<-graphql args) :per-page Integer/MAX_VALUE))] + [accounts _] (d-accounts/get-graphql (assoc (<-graphql args) :per-page Integer/MAX_VALUE))] (map ->graphql accounts))) (defn default-for-vendor [context args _] @@ -31,34 +31,32 @@ (->graphql (d-accounts/clientize result (:client_id args))))) (def search-pattern [:db/id - :account/numeric-code - :account/location - {:account/vendor-allowance [:db/ident] - :account/default-allowance [:db/ident] - :account/invoice-allowance [:db/ident]}]) + :account/numeric-code + :account/location + {:account/vendor-allowance [:db/ident] + :account/default-allowance [:db/ident] + :account/invoice-allowance [:db/ident]}]) (defn search- [id query client] (let [client-part (if (some->> client (can-see-client? id)) (format "((applicability:(global OR optional) AND -client_id:*) OR (account_client_override_id:* AND client_id:%s))" client) - "(applicability:(global OR optional) AND -client_id:*)" - - ) + "(applicability:(global OR optional) AND -client_id:*)") query (format "_text_:(%s) AND %s" (cleanse-query query) client-part)] (mu/log ::searching :search-query query) (for [{:keys [account_id name] :as g} (solr/query solr/impl "accounts" - {"query" query - "fields" "id, name, client_id, numeric_code, applicability, account_id"})] - + {"query" query + "fields" "id, name, client_id, numeric_code, applicability, account_id"})] + {:account_id (first account_id) - :name (first name)}))) + :name (first name)}))) (defn search [context {query :query client :client_id allowance :allowance vendor-id :vendor_id} _] (when client (assert-can-see-client (:id context) client)) (let [num (some-> (re-find #"([0-9]+)" query) second - (not-empty ) + (not-empty) Integer/parseInt) - + valid-allowances (cond-> #{:allowance/allowed :allowance/warn} (is-admin? (:id context)) (conj :allowance/admin-only)) @@ -71,77 +69,76 @@ vendor-account (when vendor-id (-> (dc/q '[:find ?da - :in $ ?v - :where [?v :vendor/default-account ?da]] - (dc/db conn) - vendor-id) + :in $ ?v + :where [?v :vendor/default-account ?da]] + (dc/db conn) + vendor-id) ffirst)) xform (comp - (filter (fn [[_ a]] - (or - (valid-allowances (-> a allowance :db/ident)) - (= (:db/id a) vendor-account)))) - (map (fn [[n a]] - {:name (str (:account/numeric-code a) " - " n) - :id (:db/id a) - :location (:account/location a) - :warning (when (= :allowance/warn (-> a allowance :db/ident)) - "This account is not typically used for this purpose.")})))] - (if query + (filter (fn [[_ a]] + (or + (valid-allowances (-> a allowance :db/ident)) + (= (:db/id a) vendor-account)))) + (map (fn [[n a]] + {:name (str (:account/numeric-code a) " - " n) + :id (:db/id a) + :location (:account/location a) + :warning (when (= :allowance/warn (-> a allowance :db/ident)) + "This account is not typically used for this purpose.")})))] + (if query (if num (->> (dc/q '[:find ?n (pull ?i pattern) - :in $ ?numeric-code ?allowance pattern - :where [?i :account/numeric-code ?numeric-code] - [?i :account/name ?n] - (or [?i :account/applicability :account-applicability/global] - [?i :account/applicability :account-applicability/optional] - [?i :account/applicability :account-applicability/customized])] - (dc/db conn) - num - allowance - search-pattern) + :in $ ?numeric-code ?allowance pattern + :where [?i :account/numeric-code ?numeric-code] + [?i :account/name ?n] + (or [?i :account/applicability :account-applicability/global] + [?i :account/applicability :account-applicability/optional] + [?i :account/applicability :account-applicability/customized])] + (dc/db conn) + num + allowance + search-pattern) (sequence xform)) (->> (search- (:id context) query client) (sequence - (comp (map (fn [i] [(:name i) (dc/pull (dc/db conn) search-pattern (:account_id i))])) - xform)))) + (comp (map (fn [i] [(:name i) (dc/pull (dc/db conn) search-pattern (:account_id i))])) + xform)))) []))) (defn rebuild-search-index [] (solr/index-documents-raw - solr/impl - "accounts" - (for [result (map first (dc/qseq {:query '[:find (pull ?aco [:account-client-override/search-terms :account-client-override/client :db/id {:account/_client-overrides [:account/numeric-code :account/location :db/id {:account/applicability [:db/ident]}]}]) - :in $ - :where [?aco :account-client-override/client ] - [?aco :account-client-override/search-terms ] - [_ :account/client-overrides ?aco]] - :args [(dc/db conn)]})) - :when (:account/numeric-code (:account/_client-overrides result))] - {"id" (:db/id result) - "account_id" (:db/id (:account/_client-overrides result)) - "account_client_override_id" (str (:db/id result)) - "name" (:account-client-override/search-terms result) - "client_id" (str (:db/id (:account-client-override/client result))) - "numeric_code" (:account/numeric-code (:account/_client-overrides result)) - "location" (:account/location (:account/_client-overrides result)) - "applicability" (name (:db/ident (:account/applicability (:account/_client-overrides result))))})) + solr/impl + "accounts" + (for [result (map first (dc/qseq {:query '[:find (pull ?aco [:account-client-override/search-terms :account-client-override/client :db/id {:account/_client-overrides [:account/numeric-code :account/location :db/id {:account/applicability [:db/ident]}]}]) + :in $ + :where [?aco :account-client-override/client] + [?aco :account-client-override/search-terms] + [_ :account/client-overrides ?aco]] + :args [(dc/db conn)]})) + :when (:account/numeric-code (:account/_client-overrides result))] + {"id" (:db/id result) + "account_id" (:db/id (:account/_client-overrides result)) + "account_client_override_id" (str (:db/id result)) + "name" (:account-client-override/search-terms result) + "client_id" (str (:db/id (:account-client-override/client result))) + "numeric_code" (:account/numeric-code (:account/_client-overrides result)) + "location" (:account/location (:account/_client-overrides result)) + "applicability" (name (:db/ident (:account/applicability (:account/_client-overrides result))))})) (solr/index-documents-raw - solr/impl - "accounts" - (for [result (map first (dc/qseq {:query '[:find (pull ?a [:account/numeric-code - :account/search-terms - {:account/applicability [:db/ident]} - :db/id - :account/location]) - :in $ - :where [?a :account/search-terms ]] - :args [(dc/db conn)]})) - :when (:account/search-terms result) - ] - {"id" (:db/id result) - "account_id" (:db/id result) - "name" (:account/search-terms result) - "numeric_code" (:account/numeric-code result) - "location" (:account/location result) - "applicability" (name (:db/ident (:account/applicability result)))}))) + solr/impl + "accounts" + (for [result (map first (dc/qseq {:query '[:find (pull ?a [:account/numeric-code + :account/search-terms + {:account/applicability [:db/ident]} + :db/id + :account/location]) + :in $ + :where [?a :account/search-terms]] + :args [(dc/db conn)]})) + :when (:account/search-terms result)] + {"id" (:db/id result) + "account_id" (:db/id result) + "name" (:account/search-terms result) + "numeric_code" (:account/numeric-code result) + "location" (:account/location result) + "applicability" (name (:db/ident (:account/applicability result)))}))) \ No newline at end of file diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj index f101def9..a77df35a 100644 --- a/src/clj/auto_ap/graphql/checks.clj +++ b/src/clj/auto_ap/graphql/checks.clj @@ -423,7 +423,6 @@ nil)})) (defn get-payment-page [context args _] - (alog/info ::TEST) (let [[payments checks-count] (d-checks/get-graphql (-> args :filters (<-graphql) diff --git a/src/clj/auto_ap/graphql/utils.clj b/src/clj/auto_ap/graphql/utils.clj index e49f5b6b..4486b09b 100644 --- a/src/clj/auto_ap/graphql/utils.clj +++ b/src/clj/auto_ap/graphql/utils.clj @@ -1,16 +1,17 @@ (ns auto-ap.graphql.utils - (:require [clojure.string :as str] - [auto-ap.datomic :refer [conn]] - [clj-time.coerce :as coerce] + (:require [auto-ap.datomic :refer [conn]] + [auto-ap.logging :as alog] [auto-ap.time :as atime] [buddy.auth :refer [throw-unauthorized]] + [clj-time.coerce :as coerce] + [clojure.set :as set] + [clojure.string :as str] + [clojure.walk :as walk] + [com.brunobonacci.mulog :as mu] + [com.walmartlabs.lacinia.util :refer [attach-resolvers]] [datomic.api :as dc] [iol-ion.query :refer [entid]] - [clojure.walk :as walk] - [com.walmartlabs.lacinia.util :refer [attach-resolvers]] - [com.brunobonacci.mulog :as mu] - [clojure.set :as set] - [auto-ap.logging :as alog])) + [slingshot.slingshot :refer [throw+]])) (defn snake->kebab [s] @@ -192,3 +193,29 @@ (if (seq extra-client-ids) (set/intersection user-client-ids extra-client-ids) user-client-ids))) + +(defn exception->notification [f] + (try + (f) + (catch Throwable e + (throw (ex-info (.getMessage e) + {:type :notification} + e))))) + +(defn exception->4xx [f] + (try + (f) + (catch Throwable e +(throw+ (ex-info (.getMessage e) {:type :form-validation + :form-validation-errors [(.getMessage e)]})) + #_(throw (ex-info (.getMessage e) + {:type :notification} + e))))) + +(defn notify-if-locked [client-id date] + (try + (assert-not-locked client-id date) + (catch Exception e + (throw (ex-info (.getMessage e) + {:type :notification} + e))))) diff --git a/src/clj/auto_ap/graphql/vendors.clj b/src/clj/auto_ap/graphql/vendors.clj index 3da3fd85..413907a3 100644 --- a/src/clj/auto_ap/graphql/vendors.clj +++ b/src/clj/auto_ap/graphql/vendors.clj @@ -21,18 +21,18 @@ (defn can-user-edit-vendor? [vendor-id id] (if (is-admin? id) - true - (empty? - (set/difference (set (->> (dc/q '[:find ?c - :in $ ?v - :where [?vu :vendor-usage/vendor ?v] - [?vu :vendor-usage/client ?c] - [?vu :vendor-usage/count ?d] - [(>= ?d 0)]] - (dc/db conn) - vendor-id) - (map first))) - (set (map :db/id (:user/clients id))))))) + true + (empty? + (set/difference (set (->> (dc/q '[:find ?c + :in $ ?v + :where [?vu :vendor-usage/vendor ?v] + [?vu :vendor-usage/client ?c] + [?vu :vendor-usage/count ?d] + [(>= ?d 0)]] + (dc/db conn) + vendor-id) + (map first))) + (set (map :db/id (:user/clients id))))))) (defn upsert-vendor [context {{:keys [id name hidden terms code print_as primary_contact plaid_merchant secondary_contact address default_account_id invoice_reminder_schedule schedule_payment_dom terms_overrides account_overrides] :as in} :vendor} _] (when (and id (not (can-user-edit-vendor? id (:id context)))) @@ -63,11 +63,11 @@ hidden false) terms-overrides (mapv - (fn [to] - #:vendor-terms-override {:client (:client_id to) - :terms (:terms to) - :db/id (or (:id to) (random-tempid))}) - terms_overrides) + (fn [to] + #:vendor-terms-override {:client (:client_id to) + :terms (:terms to) + :db/id (or (:id to) (random-tempid))}) + terms_overrides) account-overrides (mapv (fn [ao] #:vendor-account-override {:client (:client_id ao) @@ -75,11 +75,11 @@ :db/id (or (:id ao) (random-tempid))}) account_overrides) schedule-payment-dom (mapv - (fn [ao] - #:vendor-schedule-payment-dom {:client (:client_id ao) - :dom (:dom ao) - :db/id (or (:id ao) (random-tempid))}) - schedule_payment_dom) + (fn [ao] + #:vendor-schedule-payment-dom {:client (:client_id ao) + :dom (:dom ao) + :db/id (or (:id ao) (random-tempid))}) + schedule_payment_dom) transaction [:upsert-entity (cond-> #:vendor {:db/id (if id id "vendor") @@ -114,41 +114,40 @@ "secondary") :name (:name secondary_contact) :phone (:phone secondary_contact) - :email (:email secondary_contact)}) - ) + :email (:email secondary_contact)})) :search-terms [name]} (is-admin? (:id context)) (assoc - :vendor/legal-entity-name (:legal_entity_name in) - :vendor/legal-entity-first-name (:legal_entity_first_name in) - :vendor/legal-entity-middle-name (:legal_entity_middle_name in) - :vendor/legal-entity-last-name (:legal_entity_last_name in) - :vendor/legal-entity-tin (:legal_entity_tin in) - :vendor/legal-entity-tin-type (enum->keyword (:legal_entity_tin_type in) "legal-entity-tin-type") - :vendor/legal-entity-1099-type (enum->keyword (:legal_entity_1099_type in) "legal-entity-1099-type") - :vendor/plaid-merchant plaid_merchant - :vendor/account-overrides account-overrides - :vendor/terms-overrides terms-overrides - :vendor/schedule-payment-dom schedule-payment-dom - :vendor/automatically-paid-when-due (:automatically_paid_when_due in)))] + :vendor/legal-entity-name (:legal_entity_name in) + :vendor/legal-entity-first-name (:legal_entity_first_name in) + :vendor/legal-entity-middle-name (:legal_entity_middle_name in) + :vendor/legal-entity-last-name (:legal_entity_last_name in) + :vendor/legal-entity-tin (:legal_entity_tin in) + :vendor/legal-entity-tin-type (enum->keyword (:legal_entity_tin_type in) "legal-entity-tin-type") + :vendor/legal-entity-1099-type (enum->keyword (:legal_entity_1099_type in) "legal-entity-1099-type") + :vendor/plaid-merchant plaid_merchant + :vendor/account-overrides account-overrides + :vendor/terms-overrides terms-overrides + :vendor/schedule-payment-dom schedule-payment-dom + :vendor/automatically-paid-when-due (:automatically_paid_when_due in)))] + - transaction-result (audit-transact [transaction] (:id context)) new-vendor (d-vendors/get-by-id (or (-> transaction-result :tempids (get "vendor")) id))] - + (auto-ap.solr/index-documents-raw - auto-ap.solr/impl - "vendors" - [{"id" (:db/id new-vendor) - "name" (:vendor/name new-vendor) - "hidden" (boolean (:vendor/hidden new-vendor))}]) - + auto-ap.solr/impl + "vendors" + [{"id" (:db/id new-vendor) + "name" (:vendor/name new-vendor) + "hidden" (boolean (:vendor/hidden new-vendor))}]) + (-> new-vendor (->graphql)))) (defn merge-vendors [context {:keys [from to]} _] (let [transaction (->> (dc/q {:find '[?x ?a2] - :in '[$ ?vendor-from ] + :in '[$ ?vendor-from] :where ['[?x ?a ?vendor-from] '[?a :db/ident ?a2]]} (dc/db conn) @@ -165,13 +164,13 @@ (defn get-graphql [context args _] (assert-admin (:id context)) (let [args (assoc args :id (:id context)) - [vendors vendors-count ] (d-vendors/get-graphql (<-graphql args))] + [vendors vendors-count] (d-vendors/get-graphql (<-graphql args))] (result->page vendors vendors-count :vendors args))) (defn get-by-id [context args _] (->graphql - (d-vendors/get-graphql-by-id (assoc args :id (:id context)) - (:id args)))) + (d-vendors/get-graphql-by-id (assoc args :id (:id context)) + (:id args)))) (defn partial-match-first [query matches] (if-let [best-match (->> matches @@ -187,7 +186,7 @@ (defn search [context args _] (if-let [query (not-empty (cleanse-query (:query args)))] (let [search-query (str "name:(" query ")")] - + (for [{:keys [id name]} (solr/query solr/impl "vendors" {"query" (cond-> search-query (not (is-admin? (:id context))) (str " hidden:false")) @@ -210,4 +209,4 @@ :args [(dc/db conn)]})] {"id" (:db/id result) "name" (:vendor/name result) - "hidden" (boolean (:vendor/hidden result))})))) + "hidden" (boolean (:vendor/hidden result))})))) \ No newline at end of file diff --git a/src/clj/auto_ap/handler.clj b/src/clj/auto_ap/handler.clj index 7e370ac8..864e082a 100644 --- a/src/clj/auto_ap/handler.clj +++ b/src/clj/auto_ap/handler.clj @@ -1,42 +1,44 @@ (ns auto-ap.handler - (:require - [amazonica.core :refer [defcredential]] - [auto-ap.client-routes :as client-routes] - [auto-ap.datomic :refer [conn pull-many]] - [auto-ap.datomic.clients :as d-clients] - [auto-ap.graphql.utils :refer [assert-can-see-client limited-clients]] - [auto-ap.logging :as alog] - [auto-ap.routes.auth :as auth] - [auto-ap.routes.exports :as exports] - [auto-ap.routes.ezcater :as ezcater] - [auto-ap.routes.graphql :as graphql] - [auto-ap.routes.health :as health] - [auto-ap.routes.invoices :as invoices] - [auto-ap.routes.queries :as queries] - [auto-ap.routes.yodlee2 :as yodlee2] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.core :as ssr] - [bidi.bidi :as bidi] - [bidi.ring :refer [->ResourcesMaybe make-handler]] - [buddy.auth.backends.session :refer [session-backend]] - [buddy.auth.backends.token :refer [jws-backend]] - [buddy.auth.middleware :refer [wrap-authentication wrap-authorization]] - [cemerick.url :as url] - [clj-time.coerce :as coerce] - [clj-time.core :as time] - [clojure.string :as str] - [clojure.edn :as edn] - [com.brunobonacci.mulog :as mu] - [config.core :refer [env]] - [datomic.api :as dc] - [ring.middleware.edn :refer [wrap-edn-params]] - [ring.middleware.multipart-params :as mp] - [ring.middleware.params :refer [wrap-params]] - [ring.middleware.reload :refer [wrap-reload]] - [ring.middleware.session :refer [wrap-session]] - [ring.middleware.session.cookie :refer [cookie-store]] - [ring.util.response :as response] - [clojure.set :as set])) + (:require [amazonica.core :refer [defcredential]] + [auto-ap.client-routes :as client-routes] + [auto-ap.datomic :refer [conn pull-many]] + [auto-ap.datomic.clients :as d-clients] + [auto-ap.graphql.utils :refer [assert-can-see-client + limited-clients]] + [auto-ap.logging :as alog] + [auto-ap.routes.auth :as auth] + [auto-ap.routes.exports :as exports] + [auto-ap.routes.ezcater :as ezcater] + [auto-ap.routes.graphql :as graphql] + [auto-ap.routes.health :as health] + [auto-ap.routes.invoices :as invoices] + [auto-ap.routes.queries :as queries] + [auto-ap.routes.yodlee2 :as yodlee2] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.core :as ssr] + [bidi.bidi :as bidi] + [bidi.ring :refer [->ResourcesMaybe make-handler]] + [buddy.auth.backends.session :refer [session-backend]] + [buddy.auth.backends.token :refer [jws-backend]] + [buddy.auth.middleware :refer [wrap-authentication + wrap-authorization]] + [cemerick.url :as url] + [cheshire.core :as cheshire] + [clj-time.coerce :as coerce] + [clj-time.core :as time] + [clojure.edn :as edn] + [clojure.set :as set] + [clojure.string :as str] + [com.brunobonacci.mulog :as mu] + [config.core :refer [env]] + [datomic.api :as dc] + [hiccup2.core :as hiccup] + [ring.middleware.edn :refer [wrap-edn-params]] + [ring.middleware.multipart-params :as mp] + [ring.middleware.params :refer [wrap-params]] + [ring.middleware.session :refer [wrap-session]] + [ring.middleware.session.cookie :refer [cookie-store]] + [ring.util.response :as response])) (when (:aws-access-key-id env) (defcredential (:aws-access-key-id env) (:aws-secret-access-key env) (:aws-region env))) @@ -102,14 +104,21 @@ match->handler)) (defn wrap-guess-route [handler] - (fn [{:keys [uri request-method] :as request}] + (fn [{:keys [uri request-method headers] :as request}] (let [matched-route (:handler (bidi.bidi/match-route all-routes uri - :request-method request-method))] + :request-method request-method)) + matched-hx-current-url-route (some->> (get headers "hx-current-url") + url/url + :path + (bidi/match-route ssr-routes/only-routes) + :handler)] (handler (assoc request :matched-route - matched-route))))) + matched-route + :matched-current-page-route + matched-hx-current-url-route))))) (defn test-match-route [method uri] (bidi.bidi/match-route all-routes @@ -225,7 +234,13 @@ clients (some->> client-ids seq (pull-many (dc/db conn) - d-clients/full-read))] + '[:db/id :client/name :client/code :client/locations + :client/matches :client/feature-flags + {:client/bank-accounts [:db/id + {:bank-account/type [:db/ident]} + :bank-account/number + :bank-account/name + :bank-account/code]}]))] (mu/with-context {:clients (take 10 (map :client/code clients))} (handler (assoc request @@ -284,6 +299,19 @@ (clojure.pprint/pprint (:session request)) (handler request))) +(defn wrap-error [handler] + (fn error-handling-request [request] + (try + (handler request) + (catch Throwable e + (if (= :notification (:type (ex-data e))) + {:status 200 + :headers {"hx-trigger" (cheshire/generate-string + {"notification" (str (hiccup/html [:div (.getMessage e)]))}) + "hx-reswap" "none"}} + {:status 500 + :body (pr-str e)}))))) + #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defonce app (-> route-handler @@ -308,4 +336,5 @@ #_(wrap-reload) (wrap-params) (mp/wrap-multipart-params) - (wrap-edn-params))) + (wrap-edn-params) + (wrap-error))) diff --git a/src/clj/auto_ap/query_params.clj b/src/clj/auto_ap/query_params.clj index 3f4f8d4b..c269e7cf 100644 --- a/src/clj/auto_ap/query_params.clj +++ b/src/clj/auto_ap/query_params.clj @@ -25,20 +25,20 @@ (defn parse-sort [grid-spec q] (if (not-empty q) - (->> - (str/split q #",") - (map (fn [k] - (let [[key asc?] (str/split k #":") - matching-header (first (filter #(= (str key) (:sort-key %)) (:headers grid-spec)))] - {:sort-key (str key) - :asc (boolean (= "asc" asc?)) - :matching-header matching-header - :name (:name matching-header) - :sort-icon (if (= (boolean (= "asc" asc?)) true) - svg/sort-down - svg/sort-up)}))) - (filter :matching-header) - (into [])) + (->> + (str/split q #",") + (map (fn [k] + (let [[key asc?] (str/split k #":") + matching-header (first (filter #(= (str key) (:sort-key %)) (:headers grid-spec)))] + {:sort-key (str key) + :asc (boolean (= "asc" asc?)) + :matching-header matching-header + :name (:name matching-header) + :sort-icon (if (= (boolean (= "asc" asc?)) true) + svg/sort-down + svg/sort-up)}))) + (filter :matching-header) + (into [])) [])) (defn parse-long [l] @@ -55,30 +55,30 @@ (defn apply-date-range [source-key start-date-key end-date-key] (fn [query-params] - (dissoc - (condp = (source-key query-params) - "week" - (assoc query-params - start-date-key (time/plus (time/now) (time/days -7)) - end-date-key (time/now)) + (dissoc + (condp = (source-key query-params) + "week" + (assoc query-params + start-date-key (time/plus (time/now) (time/days -7)) + end-date-key (time/now)) - "month" - (assoc query-params - start-date-key (time/plus (time/now) (time/months -1)) - end-date-key (time/now)) + "month" + (assoc query-params + start-date-key (time/plus (time/now) (time/months -1)) + end-date-key (time/now)) - "year" - (assoc query-params - start-date-key (time/plus (time/now) (time/years -1)) - end-date-key (time/now)) + "year" + (assoc query-params + start-date-key (time/plus (time/now) (time/years -1)) + end-date-key (time/now)) - "all" - (assoc query-params - start-date-key (time/plus (time/now) (time/years -3)) - end-date-key (time/now)) + "all" + (assoc query-params + start-date-key (time/plus (time/now) (time/years -3)) + end-date-key (time/now)) - query-params) - :date-range))) + query-params) + :date-range))) (defn apply-toggle-sort [grid-spec] (fn toggle-sort [query-params] diff --git a/src/clj/auto_ap/routes/exports.clj b/src/clj/auto_ap/routes/exports.clj index 2333de7e..031d2a8c 100644 --- a/src/clj/auto_ap/routes/exports.clj +++ b/src/clj/auto_ap/routes/exports.clj @@ -660,7 +660,7 @@ :export-ntg-sales-snapshot (-> export-ntg-sales-snapshot wrap-csv-response (wrap-schema-enforce :query-schema (mc/schema [:map [:date {:required true - :decode/string #(try (atime/parse % atime/iso-date) (catch Exception e nil))} :some]]) ) + :decode/string #(try (atime/parse % atime/iso-date) (catch Exception _ nil))} :some]]) ) (wrap-form-4xx-2 (fn [_] {:body "Invalid Date"})) (wrap-predetermined-api-key "fd07755a-ed4c-4c9a-ad85-fbdd8af37206") ) diff --git a/src/clj/auto_ap/routes/exports.fiddle b/src/clj/auto_ap/routes/exports.fiddle index 4cc28e33..3d52b4ce 100644 --- a/src/clj/auto_ap/routes/exports.fiddle +++ b/src/clj/auto_ap/routes/exports.fiddle @@ -1,3 +1,29 @@ +(ns auto-ap.routes.exports + (:require + [auto-ap.datomic :refer [conn pull-attr pull-many]] + [auto-ap.datomic.accounts :as accounts] + [auto-ap.datomic.clients :as d-clients] + [auto-ap.datomic.transactions :as d-transactions] + [auto-ap.datomic.vendors :as vendor] + [auto-ap.graphql :as graphql] + [auto-ap.graphql.utils + :refer [->graphql <-graphql assert-admin assert-can-see-client]] + [auto-ap.logging :as alog] + [auto-ap.routes.utils :refer [wrap-secure]] + [auto-ap.ssr.utils :refer [wrap-schema-enforce wrap-form-4xx-2]] + [auto-ap.time :as atime] + [buddy.sign.jwt :as jwt] + [cheshire.generate :as generate] + [clj-time.coerce :as coerce :refer [to-date]] + [clj-time.core :as time] + [clojure.data.csv :as csv] + [clojure.edn :refer [read-string]] + [com.unbounce.dogstatsd.core :as statsd] + [config.core :refer [env]] + [datomic.api :as dc] + [malli.core :as mc] + [ring.middleware.json :refer [wrap-json-response]] + [venia.core :as venia])) (let [query [[:all_payments {:client-code "VS" diff --git a/src/clj/auto_ap/routes/ezcater_xls.clj b/src/clj/auto_ap/routes/ezcater_xls.clj index 734351c4..ec591ec4 100644 --- a/src/clj/auto_ap/routes/ezcater_xls.clj +++ b/src/clj/auto_ap/routes/ezcater_xls.clj @@ -192,10 +192,11 @@ (upload-xls request) (base-page request - (com/page {:nav (com/admin-aside-nav) + (com/page {:nav com/admin-aside-nav :client-selection (:client-selection (:session request)) :client (:client request) :identity (:identity request) + :request request :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :admin-ezcater-xls) :hx-trigger "clientSelected from:body" diff --git a/src/clj/auto_ap/ssr/account.clj b/src/clj/auto_ap/ssr/account.clj index e44677d7..211fe7d1 100644 --- a/src/clj/auto_ap/ssr/account.clj +++ b/src/clj/auto_ap/ssr/account.clj @@ -4,6 +4,7 @@ [auto-ap.graphql.utils :refer [assert-can-see-client can-see-client? cleanse-query is-admin?]] [auto-ap.solr :as solr] + [auto-ap.logging :as alog] [auto-ap.ssr.utils :refer [entity-id ref->enum-schema wrap-schema-enforce]] [com.brunobonacci.mulog :as mu] @@ -34,8 +35,7 @@ :name (first name)}))) -(defn account-search [{{:keys [q client-id allowance vendor-id] :as qp} :query-params id :identity}] - +(defn account-search [{{:keys [q client-id purpose vendor-id] :as qp} :query-params id :identity}] (when client-id (assert-can-see-client id client-id)) (let [num (some-> (re-find #"([0-9]+)" q) @@ -46,9 +46,9 @@ valid-allowances (cond-> #{:allowance/allowed :allowance/warn} (is-admin? id) (conj :allowance/admin-only)) - allowance (cond (= allowance :vendor) + allowance (cond (= purpose "vendor") :account/vendor-allowance - (= allowance :invoice) + (= purpose "invoice") :account/invoice-allowance :else :account/default-allowance) @@ -99,6 +99,6 @@ [:maybe entity-id]] [:vendor-id {:optional true} [:maybe entity-id]] - [:allowance {:optional true} - [:maybe (ref->enum-schema "allowance")]]]))) + [:purpose {:optional true} + [:maybe :string]]]))) diff --git a/src/clj/auto_ap/ssr/admin.clj b/src/clj/auto_ap/ssr/admin.clj index 540093ff..0477acc8 100644 --- a/src/clj/auto_ap/ssr/admin.clj +++ b/src/clj/auto_ap/ssr/admin.clj @@ -44,7 +44,7 @@ (defn page [request] (base-page request - (com/page {:nav (com/admin-aside-nav) + (com/page {:nav com/admin-aside-nav :client-selection (:client-selection (:session request)) :clients (:clients request) :client (:client request) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index eedc1b89..4f492067 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -132,12 +132,12 @@ (def grid-page (helper/build {:id "entity-table" - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp - (query-params/parse-key :code query-params/parse-long) - (helper/default-parse-query-params grid-page)) + (query-params/parse-key :code query-params/parse-long) + (helper/default-parse-query-params grid-page)) :action-buttons (fn [_] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-new-dialog)) @@ -145,8 +145,8 @@ "New Account")]) :row-buttons (fn [_ entity] [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes - :admin-account-edit-dialog - :db/id (:db/id entity)))} + :admin-account-edit-dialog + :db/id (:db/id entity)))} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} diff --git a/src/clj/auto_ap/ssr/admin/background_jobs.clj b/src/clj/auto_ap/ssr/admin/background_jobs.clj index 6922232a..992aa554 100644 --- a/src/clj/auto_ap/ssr/admin/background_jobs.clj +++ b/src/clj/auto_ap/ssr/admin/background_jobs.clj @@ -89,7 +89,7 @@ (def grid-page (helper/build {:id "job-table" :id-fn :arn - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :fetch-page fetch-page :action-buttons (fn [request] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-job-start-dialog)) @@ -118,8 +118,8 @@ (when (and (:start-date e) (:end-date e)) (str (time/in-minutes (time/interval - (:start-date e) - (:end-date e))) " minutes")))} + (:start-date e) + (:end-date e))) " minutes")))} {:key "name" :name "Name" :render :name} diff --git a/src/clj/auto_ap/ssr/admin/clients.clj b/src/clj/auto_ap/ssr/admin/clients.clj index 1957deb9..36002d2e 100644 --- a/src/clj/auto_ap/ssr/admin/clients.clj +++ b/src/clj/auto_ap/ssr/admin/clients.clj @@ -172,7 +172,7 @@ (def grid-page (helper/build {:id "entity-table" - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (helper/default-parse-query-params grid-page) @@ -1352,14 +1352,16 @@ :validation-route ::route/navigate)) mm/Initializable (init-step-params - [_ request] + [_ multi-form-state request] (let [bank-account-type (get-in request [:query-params :bank-account-type])] - (cond-> - {:db/id (str (java.util.UUID/randomUUID)) - :new? true} + (if (= {} (:step-params multi-form-state)) + (cond-> + {:db/id (str (java.util.UUID/randomUUID)) + :new? true} - bank-account-type (assoc :bank-account/type (keyword "bank-account-type" bank-account-type) - :bank-account/visible true)))) + bank-account-type (assoc :bank-account/type (keyword "bank-account-type" bank-account-type) + :bank-account/visible true)) + (:step-params multi-form-state)))) mm/Discardable (can-discard? [_ step-params] diff --git a/src/clj/auto_ap/ssr/admin/excel_invoice.clj b/src/clj/auto_ap/ssr/admin/excel_invoice.clj index ecce2dd9..98ae86b0 100644 --- a/src/clj/auto_ap/ssr/admin/excel_invoice.clj +++ b/src/clj/auto_ap/ssr/admin/excel_invoice.clj @@ -242,11 +242,12 @@ (defn page [{:keys [form-params form-errors] :as request}] (base-page request - (com/page {:nav (com/admin-aside-nav) + (com/page {:nav com/admin-aside-nav :client-selection (:client-selection (:session request)) :clients (:clients request) :client (:client request) - :identity (:identity request)} + :identity (:identity request) + :request request} (com/breadcrumbs {} [:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)} "Admin"]) [:div.flex.space-x-4 diff --git a/src/clj/auto_ap/ssr/admin/history.clj b/src/clj/auto_ap/ssr/admin/history.clj index 0929e728..fea7e388 100644 --- a/src/clj/auto_ap/ssr/admin/history.clj +++ b/src/clj/auto_ap/ssr/admin/history.clj @@ -165,10 +165,11 @@ (let [entity-id (or (some-> query-params (get "entity-id") Long/parseLong) (some-> route-params (get :entity-id) Long/parseLong))] (base-page request - (com/page {:nav (com/admin-aside-nav) + (com/page {:nav com/admin-aside-nav :client-selection (:client-selection (:session request)) :client (:client request) :identity (:identity request) + :request request :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :admin-history) :hx-trigger "clientSelected from:body" diff --git a/src/clj/auto_ap/ssr/admin/import_batch.clj b/src/clj/auto_ap/ssr/admin/import_batch.clj index 8bb9a894..68ae0b8e 100644 --- a/src/clj/auto_ap/ssr/admin/import_batch.clj +++ b/src/clj/auto_ap/ssr/admin/import_batch.clj @@ -124,7 +124,7 @@ (def grid-page (helper/build {:id "entity-table" :id-fn :db/id - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :fetch-page fetch-page :page-specific-nav filters :row-buttons (fn [_ entity] @@ -138,7 +138,7 @@ :end (:end-date (:parsed-query-params request))} :id "date-range"}) [1 :hx-swap-oob] true)]) :parse-query-params (comp - (helper/default-parse-query-params grid-page)) + (helper/default-parse-query-params grid-page)) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} "Admin"] diff --git a/src/clj/auto_ap/ssr/admin/sales_summaries.clj b/src/clj/auto_ap/ssr/admin/sales_summaries.clj index e324ab5c..05c8e506 100644 --- a/src/clj/auto_ap/ssr/admin/sales_summaries.clj +++ b/src/clj/auto_ap/ssr/admin/sales_summaries.clj @@ -118,7 +118,7 @@ (def grid-page (helper/build {:id "entity-table" :id-fn :db/id - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :fetch-page fetch-page :page-specific-nav filters :row-buttons (fn [_ entity] @@ -162,9 +162,9 @@ (reduce + 0.0 (map :sales-summary-item/discount x))) (reduce + 0.0 (map :sales-summary-item/tax x))))]) [:li "Sales subtotal: " (format "$%,.2f" (- (+ (reduce + 0.0 (map :sales-summary-item/total (:sales-summary/sales-items ss))) - (reduce + 0.0 (map :sales-summary-item/discount (:sales-summary/sales-items ss)))) + (reduce + 0.0 (map :sales-summary-item/discount (:sales-summary/sales-items ss)))) - (reduce + 0.0 (map :sales-summary-item/tax (:sales-summary/sales-items ss)))))] + (reduce + 0.0 (map :sales-summary-item/tax (:sales-summary/sales-items ss)))))] [:li "Tax: " (format "$%,.2f" (:sales-summary/total-tax ss))] [:li "Tips: " (format "$%,.2f" (:sales-summary/total-tip ss))] [:li (com/pill {:color (if (dollars= total-debits total-credits) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 05aa6564..84555e37 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -176,7 +176,7 @@ (def grid-page (helper/build {:id "entity-table" - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp @@ -470,6 +470,7 @@ (com/validated-field {:errors (fc/field-errors) :x-data (hx/json {:location (fc/field-value)})} + ;; TODO make this thing into a component [:div {:hx-trigger "changed" :hx-target "next *" :hx-swap "outerHTML" @@ -815,7 +816,7 @@ (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" :errors (fc/field-errors)} - (com/radio {:options (ref->radio-options "transaction-approval-status") + (com/radio-card {:options (ref->radio-options "transaction-approval-status") :value (fc/field-value) :name (fc/field-name) :size :small diff --git a/src/clj/auto_ap/ssr/admin/vendors.clj b/src/clj/auto_ap/ssr/admin/vendors.clj index 901e8300..bbd7bd3a 100644 --- a/src/clj/auto_ap/ssr/admin/vendors.clj +++ b/src/clj/auto_ap/ssr/admin/vendors.clj @@ -49,7 +49,7 @@ :placeholder "Cash" :size :small})) (com/field {:label "Type"} - (com/radio {:size :small + (com/radio-card {:size :small :name "type" :value (:type (:parsed-query-params request)) :options [{:value "" @@ -136,7 +136,7 @@ (def grid-page (helper/build {:id "entity-table" - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp diff --git a/src/clj/auto_ap/ssr/company.clj b/src/clj/auto_ap/ssr/company.clj index c609e086..17fbb8dd 100644 --- a/src/clj/auto_ap/ssr/company.clj +++ b/src/clj/auto_ap/ssr/company.clj @@ -130,7 +130,7 @@ (defn page [{:keys [identity matched-route] :as request}] (base-page request - (com/page {:nav (com/company-aside-nav) + (com/page {:nav com/company-aside-nav :client-selection (:client-selection (:session request)) :client (:client request) :identity (:identity request) diff --git a/src/clj/auto_ap/ssr/company/company_1099.clj b/src/clj/auto_ap/ssr/company/company_1099.clj index 70a8712d..65e49602 100644 --- a/src/clj/auto_ap/ssr/company/company_1099.clj +++ b/src/clj/auto_ap/ssr/company/company_1099.clj @@ -90,7 +90,7 @@ (def grid-page (helper/build {:id "entity-table" - :nav (com/company-aside-nav) + :nav com/company-aside-nav :id-fn (comp :db/id second) :fetch-page fetch-page :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes @@ -126,46 +126,46 @@ (-> vendor :vendor/legal-entity-last-name)))]] (when-let [t99-type (some-> vendor :vendor/legal-entity-1099-type :db/ident name)] (com/pill - {:class "text-xs font-medium" - :color :primary} - (str/capitalize t99-type)) + {:class "text-xs font-medium" + :color :primary} + (str/capitalize t99-type)) )])} {:key "tin" :name "TIN" :sort-key "tin" :show-starting "md" :render (fn [[_ vendor]] - [:div.flex.gap-4 - (when-let [tin (-> vendor :vendor/legal-entity-tin)] - [:span {:class "text-xs font-medium py-0.5 "} - tin]) - (when-let [tin-type (some-> vendor :vendor/legal-entity-tin-type :db/ident name)] - (com/pill {:class "text-xs font-medium" - :color :yellow} - (name tin-type)))] - )} + [:div.flex.gap-4 + (when-let [tin (-> vendor :vendor/legal-entity-tin)] + [:span {:class "text-xs font-medium py-0.5 "} + tin]) + (when-let [tin-type (some-> vendor :vendor/legal-entity-tin-type :db/ident name)] + (com/pill {:class "text-xs font-medium" + :color :yellow} + (name tin-type)))] + )} {:key "address" :name "Address" :sort-key "address" :show-starting "lg" :render (fn [[_ vendor]] - (if (-> vendor :vendor/address :address/street1) - [:div - [:div (-> vendor :vendor/address :address/street1)] " " - [:div - (-> vendor :vendor/address :address/street2)] " " - [:div - (-> vendor :vendor/address :address/city) " " - (-> vendor :vendor/address :address/state) "," - (-> vendor :vendor/address :address/zip)]] - [:p.text-sm.italic.text-gray-400 "No address"]))} + (if (-> vendor :vendor/address :address/street1) + [:div + [:div (-> vendor :vendor/address :address/street1)] " " + [:div + (-> vendor :vendor/address :address/street2)] " " + [:div + (-> vendor :vendor/address :address/city) " " + (-> vendor :vendor/address :address/state) "," + (-> vendor :vendor/address :address/zip)]] + [:p.text-sm.italic.text-gray-400 "No address"]))} {:key "paid" :name "Paid" :sort-key "paid" :render (fn [[_ _ paid]] (com/pill {:class "text-xs font-medium" :color :primary} - "Paid $" (Math/round paid)))}]})) + "Paid $" (Math/round paid)))}]})) diff --git a/src/clj/auto_ap/ssr/company/plaid.clj b/src/clj/auto_ap/ssr/company/plaid.clj index 8ab4e736..78a27ff4 100644 --- a/src/clj/auto_ap/ssr/company/plaid.clj +++ b/src/clj/auto_ap/ssr/company/plaid.clj @@ -133,7 +133,7 @@ (def grid-page (helper/build {:id "plaid-table" - :nav (com/company-aside-nav) + :nav com/company-aside-nav :fetch-page fetch-page :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :company)} @@ -181,9 +181,9 @@ :name "Accounts" :show-starting "md" :render (fn [e] - [:ul - (for [a (:plaid-item/accounts e)] - [:li (:plaid-account/name a) " - " (:plaid-account/number a)])])}]})) + [:ul + (for [a (:plaid-item/accounts e)] + [:li (:plaid-account/name a) " - " (:plaid-account/number a)])])}]})) (def page (helper/page-route grid-page)) diff --git a/src/clj/auto_ap/ssr/company/reports.clj b/src/clj/auto_ap/ssr/company/reports.clj index 053f4778..cf6fad3a 100644 --- a/src/clj/auto_ap/ssr/company/reports.clj +++ b/src/clj/auto_ap/ssr/company/reports.clj @@ -70,7 +70,7 @@ (def grid-page (helper/build {:id "report-table" - :nav (com/company-aside-nav) + :nav com/company-aside-nav :fetch-page fetch-page :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :company)} diff --git a/src/clj/auto_ap/ssr/company/yodlee.clj b/src/clj/auto_ap/ssr/company/yodlee.clj index 8f36b87e..4d9267ef 100644 --- a/src/clj/auto_ap/ssr/company/yodlee.clj +++ b/src/clj/auto_ap/ssr/company/yodlee.clj @@ -122,7 +122,7 @@ fastlink.open({fastLinkURL: '%s', (def grid-page (helper/build {:id "yodlee-table" - :nav (com/company-aside-nav) + :nav com/company-aside-nav :id-fn :db/id :fetch-page fetch-page :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes @@ -136,19 +136,19 @@ fastlink.open({fastLinkURL: '%s', :route :company-yodlee-table :action-buttons (fn [request] [[:div.flex.flex-col.flex-shrink - [:div.flex-shrink - (com/button {:color :primary - :on-click "openFastlink()" - :disabled (if (:client request) - false - true) - :hx-get (bidi/path-for ssr-routes/only-routes - :company-yodlee-fastlink-dialog) - :hx-target "#modal-holder"} - (com/button-icon {} svg/refresh) - "Link new account")] - (when-not (:client request) - [:div.text-xs "Note: please select a specific customer to link a new account."])]]) + [:div.flex-shrink + (com/button {:color :primary + :on-click "openFastlink()" + :disabled (if (:client request) + false + true) + :hx-get (bidi/path-for ssr-routes/only-routes + :company-yodlee-fastlink-dialog) + :hx-target "#modal-holder"} + (com/button-icon {} svg/refresh) + "Link new account")] + (when-not (:client request) + [:div.text-xs "Note: please select a specific customer to link a new account."])]]) :row-buttons (fn [request _] [ (com/button {:hx-put (bidi/path-for ssr-routes/only-routes @@ -194,9 +194,9 @@ fastlink.open({fastLinkURL: '%s', :name "Accounts" :show-starting "md" :render (fn [e] - [:ul - (for [a (:yodlee-provider-account/accounts e)] - [:li (:yodlee-account/name a) " - " (:yodlee-account/number a)])])}]})) + [:ul + (for [a (:yodlee-provider-account/accounts e)] + [:li (:yodlee-account/name a) " - " (:yodlee-account/number a)])])}]})) (def page (helper/page-route grid-page)) (def table (helper/table-route grid-page)) diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index d1e6a3e5..e9e62df9 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -21,6 +21,8 @@ (def a-icon-button buttons/a-icon-button-) (def button-group buttons/group-) (def button-group-button buttons/group-button-) +(def navigation-button-list buttons/navigation-button-list-) +(def navigation-button buttons/navigation-button-) (def modal dialog/modal-) (def modal-card dialog/modal-card-) (def modal-card-advanced dialog/modal-card-advanced-) @@ -53,7 +55,8 @@ (def navbar navbar/navbar-) (def page page/page-) -(def radio radio/radio-) +(def radio-card radio/radio-card-) +(def radio-list radio/radio-list-) (def pill tags/pill-) (def badge tags/badge-) diff --git a/src/clj/auto_ap/ssr/components/aside.clj b/src/clj/auto_ap/ssr/components/aside.clj index e4ec2bde..969fa46a 100644 --- a/src/clj/auto_ap/ssr/components/aside.clj +++ b/src/clj/auto_ap/ssr/components/aside.clj @@ -1,231 +1,351 @@ (ns auto-ap.ssr.components.aside - (:require [auto-ap.ssr.svg :as svg] - [hiccup2.core :as hiccup] - [bidi.bidi :as bidi] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.client-routes :as client-routes] - [auto-ap.ssr.hx :as hx] - [auto-ap.routes.admin.transaction-rules :as transaction-rules] - [auto-ap.ssr.hiccup-helper :as hh] - [auto-ap.routes.admin.import-batch :as ib-routes] + (:require [auto-ap.client-routes :as client-routes] + [auto-ap.permissions :refer [can?]] [auto-ap.routes.admin.clients :as ac-routes] [auto-ap.routes.admin.excel-invoices :as ei-routes] + [auto-ap.routes.admin.import-batch :as ib-routes] + [auto-ap.routes.admin.transaction-rules :as transaction-rules] [auto-ap.routes.admin.vendors :as v-routes] - [auto-ap.graphql.clients :as clients])) + [auto-ap.routes.invoice :as invoice-route] + [auto-ap.routes.outgoing-invoice :as oi-routes] + [auto-ap.routes.payments :as payment-routes] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.hiccup-helper :as hh] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg] + [bidi.bidi :as bidi] + [hiccup.util :as hu])) (defn menu-button- [params & children] [:div [:a (-> params (dissoc :icon) (assoc :type "button") - (update :class str " cursor-pointer flex items-center p-2 w-full text-xs text-gray-600 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700") + (update :class (fn [c] + (cond-> (or c "cursor-pointer flex items-center p-2 w-full text-sm rounded-lg transition duration-75 group hover:bg-gray-100 dark:hover:bg-gray-700 select-none") + (:active? params) (hh/add-class "text-blue-600 font-extrabold dark:text-blue-100 bg-gray-100") + (not (:active? params)) (hh/add-class "text-gray-600 dark:text-white")))) (assoc :hx-indicator "find .htmx-indicator") - (assoc :hx-boost "true") (assoc :hx-select "#app") (assoc :hx-target "#app") (assoc :hx-swap "innerHTML")) - (when (:icon params) [:span {:class "flex-shrink-0 w-6 h-6 text-gray-400 transition duration-75 group-hover:text-blue-500 dark:text-gray-400 group-hover:scale-110 dark:group-hover:text-white mr-3"} (:icon params)]) - (into [:span {:class "flex-1 text-left whitespace-nowrap text-gray-600 dark:text-white"}] children) - (when (get params "@click") + (into [:span {:class "flex-1 text-left whitespace-nowrap"}] children) + (when (get params "@click.prevent") [:svg {:aria-hidden "true", :class "w-6 h-6", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} [:path {:fill-rule "evenodd", :d "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", :clip-rule "evenodd"}]]) [:div.htmx-indicator.flex.items-center (svg/spinner-primary {:class "inline w-4 h-4 text-white"})]]]) (defn sub-menu- [params & children] - [:ul (update params - :class (fnil hh/add-class "")"py-2 space-y-1.5") + [:ul (cond-> (update params + :class (fnil hh/add-class "") "space-y-1.5 max-h-0 transition transition-all overflow-hidden") + true (assoc ":class" (format "selected == '%s' ? 'py-0.5' : 'py-0'" (:selector params)) + :x-ref "submenu" + :style (cond-> {} (:active? params) (assoc "max-height" "400px")) + ":style" (format "selected == '%s' ? 'max-height: ' + $refs.submenu.scrollHeight + 'px' : ''" (:selector params)))) (for [c children] [:li - (update-in c [1 1 :class ] str " flex items-center p-2 pl-11 w-full text-base font-normal text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")])]) + (update-in c [1 1 :class ] (fn [c] + (hh/add-class (or c "") " flex items-center p-2 pl-11 w-full text-base font-normal rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")))])]) (defn left-aside- [{:keys [nav page-specific]} & children] [:aside {:id "left-nav", - :class "fixed top-0 left-0 pt-16 z-20 w-64 h-screen transition-transform -translate-x-full lg:translate-x-0", + :class "fixed top-0 left-0 pt-16 z-20 w-64 h-screen transition-transform", "x-transition:enter" "transition duration-500" - "x-transition:enter-start" "lg:-translate-x-full" - "x-transition:enter-end" " lg:translate-x-0" + "x-transition:enter-start" "-translate-x-full" + "x-transition:enter-end" " translate-x-0" "x-transition:leave" "transition duration-500" - "x-transition:leave-start" "lg:translate-x-0" - "x-transition:leave-end" " lg:-translate-x-full" - + "x-transition:leave-start" "translate-x-0" + "x-transition:leave-end" " -translate-x-full" + :aria-labelledby "left-nav" :x-show "leftNavShow" ":aria-hidden" "leftNavShow ? 'false' : 'true'"} + [:template {:x-teleport "body"} + + [:div.fixed.inset-0.lg:hidden {:x-show "leftNavShow" :x-transition:enter "transition duration-500" :x-transition:enter-start "opacity-0" :x-transition:enter-end "opacity-100" + :x-transition:leave "transition duration-500" :x-transition:leave-start "opacity-100" :x-transition:leave-end "opacity-0" + "@click.capture.prevent" "leftNavShow=false"} + [:div.fixed.inset-0.bg-gray-800.z-10.opacity-70]]] + [:div {:class "overflow-y-auto py-5 px-3 h-full bg-gray-50 border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700"} nav - + (when page-specific [:div {:class " pt-5 mt-5 space-y-2 border-t border-gray-200 dark:border-gray-700"} - page-specific] - )]]) + page-specific])]]) -(defn main-aside-nav- [] - [:ul {:class "space-y-1"} +(defn main-aside-nav- [request] + (let [selected (cond + (#{::invoice-route/all-page ::invoice-route/unpaid-page ::invoice-route/voided-page ::invoice-route/paid-page ::oi-routes/new} (:matched-route request)) + "invoices" - [:li - (menu-button- {:icon svg/pie - :href "/"} - "Dashboard")] - [:li {:x-data (hx/json {:open false})} - (menu-button- {"@click" "open = !open" - :icon svg/accounting-invoice-mail} - "Invoices") - (sub-menu- (hx/alpine-appear {:x-show "open"}) - (menu-button- {:href (bidi/path-for client-routes/routes - :invoices)} - "All") - (menu-button- {:href (bidi/path-for client-routes/routes - :paid-invoices)} - "Paid") - (menu-button- {:href (bidi/path-for client-routes/routes - :unpaid-invoices)} - "Unpaid") - (menu-button- {:href (bidi/path-for client-routes/routes - :voided-invoices)} - "Voided"))] - [:li {:x-data (hx/json {:open false})} - (menu-button- {:icon svg/receipt-register-1 - "@click" "open = !open"} - "Sales") - (sub-menu- (hx/alpine-appear {:x-show "open"}) - (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes - :pos-sales) - "?date-range=week")} "Sales") - (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes - :pos-expected-deposits) - "?date-range=week")} "Expected Deposits") - (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes - :pos-tenders) - "?date-range=week")} "Tenders") + (#{:pos-sales :pos-expected-deposits :pos-tenders :pos-refunds :pos-cash-drawer-shifts} (:matched-route request)) + "sales" + (#{::payment-routes/all-page ::payment-routes/pending-page ::payment-routes/cleared-page ::payment-routes/voided-page } (:matched-route request)) + "payments" + :else + nil)] + [:ul {:class "space-y-1" + :x-data (hx/json {:selected selected})} - (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes - :pos-refunds) - "?date-range=week")} "Refunds") - (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes - :pos-cash-drawer-shifts) - "?date-range=week")} "Cash drawer shifts") - #_(menu-button- {:href "Sales"} "Cash Shifts") - #_(menu-button- {:href "Sales"} "Tenders"))] - [:li {:x-data (hx/json {:open false})} - (menu-button- {"@click" "open = !open" - :icon svg/payments} - "Payments") - (sub-menu- (hx/alpine-appear {:x-show "open"}) - (menu-button- {:href (bidi/path-for client-routes/routes - :payments)} "All") - (menu-button- {:href (bidi/path-for client-routes/routes - :payments)} "Pending") - (menu-button- {:href (bidi/path-for client-routes/routes - :payments)} "Cleared") - (menu-button- {:href (bidi/path-for client-routes/routes - :payments)} "Voided"))] + [:li + (menu-button- {:icon svg/pie + :href "/"} + "Dashboard")] - [:li {:x-data (hx/json {:open false})} - (menu-button- {"@click" "open = !open" - :icon svg/bank} - "Transactions") + (when (can? (:identity request) + {:subject :invoice-page}) + (list + (menu-button- {"@click.prevent" "if (selected == 'invoices') {selected = null } else { selected = 'invoices'} " + :icon svg/accounting-invoice-mail} + "Invoices") + (sub-menu- + {:selector "invoices" + :active? (= "invoices" selected)} + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::invoice-route/all-page) + {:date-range "month"}) + :active? (= ::invoice-route/all-page (:matched-route request)) + :hx-boost "true"} - (sub-menu- (hx/alpine-appear {:x-show "open"}) - (menu-button- {:href (bidi/path-for client-routes/routes - :transactions)} "All") - (menu-button- {:href (bidi/path-for client-routes/routes - :unapproved-transactions)} "Unapproved") - (menu-button- {:href (bidi/path-for client-routes/routes - :requires-feedback-transactions)} "Client Review") - (menu-button- {:href (bidi/path-for client-routes/routes - :approved-transactions)} "Approved") - (menu-button- {:href (bidi/path-for ssr-routes/only-routes - :transaction-insights)} "Insights"))] - [:li {:x-data (hx/json {:open false})} - (menu-button- {"@click" "open = !open" - :icon svg/receipt} - "Ledger") - (sub-menu- (hx/alpine-appear {:x-show "open"}) - (menu-button- {:href (bidi/path-for client-routes/routes - :ledger)} "Register") - (menu-button- {:href (bidi/path-for client-routes/routes - :profit-and-loss)} "Profit & Loss") - (menu-button- {:href (bidi/path-for client-routes/routes - :profit-and-loss-detail)} "Profit & Loss Detail") - (menu-button- {:href (bidi/path-for client-routes/routes - :cash-flows)} "Cash Flows") - (menu-button- {:href (bidi/path-for client-routes/routes - :balance-sheet)} "Balance Sheet") - (menu-button- {:href (bidi/path-for client-routes/routes - :external-import-ledger)} "External Ledger Import"))]]) + "All") + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::invoice-route/paid-page) + {:date-range "month"}) + :active? (= ::invoice-route/paid-page (:matched-route request)) + :hx-boost "true"} + "Paid") + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::invoice-route/unpaid-page) + {:date-range "month"}) + :active? (= ::invoice-route/unpaid-page (:matched-route request)) + :hx-boost "true"} + "Unpaid") + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::invoice-route/voided-page) + {:date-range "month"}) + :active? (= ::invoice-route/voided-page (:matched-route request)) + :hx-boost "true"} + "Voided") + (menu-button- {:href (bidi/path-for client-routes/routes + :import-invoices)} "Import") + (when (can? (:identity request) + {:subject :ar-invoice + :activity :read}) + (menu-button- {:href (bidi/path-for ssr-routes/only-routes + ::oi-routes/new) + :active? (= ::oi-routes/new (:matched-route request)) + :hx-boost "true"} + "Create outgoing"))))) + + (when + (can? (:identity request) {:subject :sales :activity :read}) + (list + (menu-button- {:icon svg/receipt-register-1 + + "@click.prevent" "if (selected == 'sales') {selected = null } else { selected = 'sales'} "} + "Sales") + (sub-menu- {:selector "sales" + :active? (= "sales" selected)} + (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes + :pos-sales) + "?date-range=week") + :active? (= :pos-sales (:matched-route request)) + :hx-boost "true"} + "Sales") + (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes + :pos-expected-deposits) + "?date-range=week") + :active? (= :pos-expected-deposits (:matched-route request)) + :hx-boost "true"} + "Expected Deposits") + (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes + :pos-tenders) + "?date-range=week") + :active? (= :pos-tenders (:matched-route request)) + :hx-boost "true"} + "Tenders") + + (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes + :pos-refunds) + "?date-range=week") + :active? (= :pos-refunds (:matched-route request)) + :hx-boost "true"} + + "Refunds") + (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes + :pos-cash-drawer-shifts) + "?date-range=week") + :active? (= :cash-drawer-shifts (:matched-route request)) + :hx-boost "true"} + "Cash drawer shifts")))) + + (menu-button- {"@click.prevent" "if (selected == 'payments') {selected = null } else { selected = 'payments'} " + :icon svg/payments} + "Payments") + (sub-menu- {:selector "payments" + :active? (= "payments" selected)} + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::payment-routes/all-page) + {:date-range "month"}) + :active? (= ::payment-routes/all-page (:matched-route request)) + :hx-boost "true"} + "All") + + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::payment-routes/pending-page) + {:date-range "month"}) + :active? (= ::payment-routes/pending-page (:matched-route request)) + :hx-boost "true"} + "Pending") + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::payment-routes/cleared-page) + {:date-range "month"}) + :active? (= ::payment-routes/cleared-page (:matched-route request)) + :hx-boost "true"} + "Cleared") + (menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes + ::payment-routes/voided-page) + {:date-range "month"}) + :active? (= ::payment-routes/voided-page (:matched-route request)) + :hx-boost "true"} + "Voided")) + + [:li {:x-data (hx/json {:open false})} + (menu-button- {"@click.prevent" "if (selected == 'transactions') {selected = null } else { selected = 'transactions'} " + :icon svg/bank} + "Transactions") + + (sub-menu- {:selector "transactions" + :active? (= "transactions" selected)} + (menu-button- {:href (bidi/path-for client-routes/routes + :transactions)} "All") + (menu-button- {:href (bidi/path-for client-routes/routes + :unapproved-transactions)} "Unapproved") + (menu-button- {:href (bidi/path-for client-routes/routes + :requires-feedback-transactions)} "Client Review") + (menu-button- {:href (bidi/path-for client-routes/routes + :approved-transactions)} "Approved") + (when (can? (:identity request) + {:subject :transaction :activity :insights}) + (menu-button- {:href (bidi/path-for ssr-routes/only-routes + :transaction-insights)} "Insights")))] -(defn company-aside-nav- [] + (when (can? (:identity request) + {:subject :ledger-page}) + (list + (menu-button- {"@click.prevent" "if (selected == 'ledger') {selected = null } else { selected = 'ledger'} " + :icon svg/receipt} + "Ledger") + (sub-menu- {:selector "ledger" + :active? (= "ledger" selected)} + (menu-button- {:href (bidi/path-for client-routes/routes + :ledger)} "Register") + (menu-button- {:href (bidi/path-for client-routes/routes + :profit-and-loss)} "Profit & Loss") + (menu-button- {:href (bidi/path-for client-routes/routes + :profit-and-loss-detail)} "Profit & Loss Detail") + (menu-button- {:href (bidi/path-for client-routes/routes + :cash-flows)} "Cash Flows") + (menu-button- {:href (bidi/path-for client-routes/routes + :balance-sheet)} "Balance Sheet") + (when (can? (:identity request) + {:subject :ledger + :activity :import}) + (menu-button- {:href (bidi/path-for client-routes/routes + :external-import-ledger)} "External Ledger Import")))))])) + + +(defn company-aside-nav- [_] [:ul {:class "space-y-2" :hx-boost "true"} [:li (menu-button- {:icon svg/vendors :href (bidi/path-for ssr-routes/only-routes - :company)} + :company) + :hx-boost true} "My Company")] [:li (menu-button- {:icon svg/report :href (bidi/path-for ssr-routes/only-routes - :company-reports)} + :company-reports) + :hx-boost true} "Reports")] [:li (menu-button- {:icon svg/bank :href (bidi/path-for ssr-routes/only-routes - :company-plaid)} + :company-plaid) + :hx-boost true} "Plaid Link")] [:li (menu-button- {:icon svg/bank :href (bidi/path-for ssr-routes/only-routes - :company-yodlee)} + :company-yodlee) + :hx-boost true} "Yodlee Link")] [:li (menu-button- {:icon svg/government-building :href (bidi/path-for ssr-routes/only-routes - :company-1099)} + :company-1099) + :hx-boost true} "1099 Vendor Info" )]]) -(defn admin-aside-nav- [] - [:ul {:class "space-y-2"} +(defn admin-aside-nav- [{:keys [matched-route] :as request}] + [:ul {:class "space-y-2" :x-data (hx/json {:selected "nil"})} [:li (menu-button- {:icon svg/dashboard - :href (bidi/path-for ssr-routes/only-routes :auto-ap.routes.admin/page)} + :active? (= :auto-ap.routes.admin/page matched-route) + :href (bidi/path-for ssr-routes/only-routes :auto-ap.routes.admin/page) + :hx-boost true} "Dashboard")] [:li (menu-button- {:icon svg/restaurant - :href (bidi/path-for ssr-routes/only-routes ::ac-routes/page) } + :active? (= ::ac-routes/page matched-route) + :href (bidi/path-for ssr-routes/only-routes ::ac-routes/page) + :hx-boost true} "Clients")] [:li (menu-button- {:icon svg/vendors + :active? (= ::v-routes/page matched-route) :href (bidi/path-for ssr-routes/only-routes - ::v-routes/page)} + ::v-routes/page) + :hx-boost true} "Vendors")] [:li (menu-button- {:icon svg/user + :active? (= :users matched-route) :href (bidi/path-for ssr-routes/only-routes - :users)} + :users) + :hx-boost true} "Users")] [:li (menu-button- {:icon svg/accounts + :active? (= :admin-accounts matched-route) :href (bidi/path-for ssr-routes/only-routes - :admin-accounts)} + :admin-accounts) + :hx-boost true} "Accounts")] [:li (menu-button- {:icon svg/cog - :href (bidi/path-for ssr-routes/only-routes ::transaction-rules/page)} + :active? (= ::transaction-rules/page matched-route) + :href (bidi/path-for ssr-routes/only-routes ::transaction-rules/page) + :hx-boost true} "Rules")] [:li (menu-button- {:icon svg/question + :active? (= :admin-rules matched-route) :href (bidi/path-for ssr-routes/only-routes :admin-history) :hx-boost "true"} @@ -233,20 +353,32 @@ [:li (menu-button- {:icon svg/rabbit + :active? (= :admin-jobs matched-route) :href (bidi/path-for ssr-routes/only-routes - :admin-jobs)} + :admin-jobs) + :hx-boost true} "Background Jobs")] - [:li {:x-data (hx/json {:open false})} - (menu-button- {:icon svg/arrow-in - "@click" "open = !open"} - "Import") - (sub-menu- (hx/alpine-appear - {:x-show "open"}) - (menu-button- {:href (bidi/path-for ssr-routes/only-routes - ::ei-routes/page)} "Excel Invoices") - (menu-button- {:href (bidi/path-for ssr-routes/only-routes - ::ib-routes/page)} "Import Batches") - (menu-button- {:href (bidi/path-for ssr-routes/only-routes - :admin-ezcater-xls) - :hx-boost "true"} "EZCater XLS Import"))]]) + + (when (can? (:identity request) {:subject :invoice :activity :import}) + (menu-button- {:icon svg/arrow-in + "@click.prevent" "if (selected == 'import') {selected = null } else { selected = 'import'} "} + "Import")) + + (sub-menu- {:selector "import"} + (menu-button- {:href (bidi/path-for ssr-routes/only-routes + ::ei-routes/page) + :active? (= ::ei-routes/page matched-route) + :hx-boost true} + + "Excel Invoices") + (menu-button- {:href (bidi/path-for ssr-routes/only-routes + ::ib-routes/page) + :active? (= ::ib-routes/page matched-route) + :hx-boost true} + "Import Batches") + (menu-button- {:href (bidi/path-for ssr-routes/only-routes + :admin-ezcater-xls) + :active? (= :admin-ezcater-xls matched-route) + :hx-boost "true"} + "EZCater XLS Import"))]) diff --git a/src/clj/auto_ap/ssr/components/bank_account_icon.clj b/src/clj/auto_ap/ssr/components/bank_account_icon.clj new file mode 100644 index 00000000..90cf3906 --- /dev/null +++ b/src/clj/auto_ap/ssr/components/bank_account_icon.clj @@ -0,0 +1,31 @@ +(ns auto-ap.ssr.components.bank-account-icon + (:require [auto-ap.ssr.hiccup-helper :as hh] + [auto-ap.ssr.svg :as svg])) + +(defmulti icon :bank-account/type) +(defmethod icon :bank-account-type/cash [_] + [:div.grow-0.flex.flex-col.justify-center + [:div.p-1.m-2.rounded-full + {:class + "bg-blue-50"} + [:div {:class + (hh/add-class "p-1.5 w-8 h-8" "text-green-600")} + svg/dollar]]]) + +(defmethod icon :bank-account-type/credit [_] + [:div.grow-0.flex.flex-col.justify-center + [:div.p-1.m-2.rounded-full + {:class + "bg-purple-50"} + [:div {:class + (hh/add-class "p-1.5 w-8 h-8" "text-purple-600")} + svg/credit-card]]]) + +(defmethod icon :bank-account-type/check [_] + [:div.grow-0.flex.flex-col.justify-center + [:div.p-1.m-2.rounded-full + {:class + "bg-blue-50"} + [:div {:class + (hh/add-class "p-1.5 w-8 h-8" "text-blue-600")} + svg/check]]]) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index 151ece2e..047b349b 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -11,30 +11,37 @@ (= :secondary color) "blue" + (= :red color) + "red" + (nil? color) "white" + (sequential? color) + (first color) + :else color) + base-weight (or (when (sequential? color) + (second color)) + 500) disabled-weight (when disabled 400)] - + (format " bg-%s-%d hover:bg-%s-%d focus:ring-%s-%d dark:bg-%s-%d dark:hover:bg-%s-%d " base-color - (or disabled-weight 500) + (or disabled-weight (+ base-weight 0)) base-color - (or disabled-weight 600) + (or disabled-weight (+ base-weight 100)) base-color - (or disabled-weight 200) + (or disabled-weight (int (* base-weight 0.5))) base-color - (or disabled-weight 600) + (or disabled-weight (+ base-weight 100)) base-color - (or disabled-weight 700) - - ))) + (or disabled-weight (+ base-weight 200))))) (defn dark-color-weight [disabled] (if disabled @@ -48,7 +55,7 @@ (for [color ["green" "blue" "white"] weight (range 100 900 100)] - (str "bg-" color "-" weight)) + (str "bg-" color "-" weight)) ;;ensuring these colors show up ;; => ("bg-green-100" ;; "bg-green-200" @@ -76,10 +83,10 @@ ;; "bg-white-800") (defn button- [params & children] - + [:button (update params :class #(cond-> % - true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center justify-center" + true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center relative justify-center" (bg-colors (:color params) (:disabled params))) (not (:disabled params)) @@ -93,10 +100,11 @@ (nil? (:color params)) (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700"))) - [:div.htmx-indicator.flex.items-center + [:div.htmx-indicator.flex.items-center.absolute.inset-0.justify-center (svg/spinner {:class "inline w-4 h-4 text-white"}) - [:div.ml-3 "Loading..."]] - (into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)]) + (when (not (:minimal-loading? params)) + [:div.ml-3 "Loading..."])] + (into [:div.htmx-indicator-invisible.inline-flex.gap-2.items-center.justify-center] children)]) (defn a-button- [params & children] [:a (-> params @@ -105,8 +113,7 @@ (= :secondary (:color params)) (str " text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700") (= :primary (:color params)) (str " text-white bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ") (nil? (:color params)) - (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700") - )) + (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700"))) (assoc :tabindex 0) (assoc :href (:href params "#"))) [:div.htmx-indicator.flex.items-center @@ -133,18 +140,17 @@ [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center (into [:div.h-4.w-4] children)]])) (defn a-icon-button- [params & children] - (into - [:a (-> params (update :class str " inline-flex items-center justify-center bg-white dark:bg-gray-600 items-center p-3 text-sm font-medium border border-gray-300 dark:border-gray-700 text-center text-gray-500 hover:text-gray-800 rounded-lg dark:text-gray-400 dark:hover:text-gray-100" - ) - (update :href #(or % ""))) - [:div.h-4.w-4 children]])) + (into + [:a (-> params (update :class str " inline-flex items-center justify-center bg-white dark:bg-gray-600 items-center p-3 text-sm font-medium border border-gray-300 dark:border-gray-700 text-center text-gray-500 hover:text-gray-800 rounded-lg dark:text-gray-400 dark:hover:text-gray-100") + (update :href #(or % ""))) + [:div.h-4.w-4 children]])) (defn save-button- [params & children] - [:button { :class "text-white bg-green-500 hover:bg-green-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800 inline-flex items-center hover:scale-105 transition duration-300"} + [:button {:class "text-white bg-green-500 hover:bg-green-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800 inline-flex items-center hover:scale-105 transition duration-300"} [:div.htmx-indicator.flex.items-center (svg/spinner {:class "inline w-4 h-4 text-white"}) [:div.ml-3 "Loading..."]] - (into [:div.htmx-indicator-hidden ] children)]) + (into [:div.htmx-indicator-hidden] children)]) @@ -159,10 +165,8 @@ (str " text-xs px-3 py-2") (= :normal size) - (str " text-sm px-4 py-2") - ) - )) - true (dissoc :size))] children )) + (str " text-sm px-4 py-2")))) + true (dissoc :size))] children)) (defn group- [{:keys [name]} & children] (let [children (-> children @@ -174,6 +178,49 @@ [:input {:type "hidden" :name name}]] children))) +(defn navigation-button- [{:keys [class next-arrow?] :or {next-arrow? true} :as params} & children] + [:button + (-> params + (update :class (fnil hh/add-class "") + "p-4 text-green-700 border border-gray-300 rounded-lg bg-gray-50 + dark:bg-gray-800 dark:border-green-800 dark:text-green-400 + focus:ring-green-400 focus:ring-2 + hover:border-green-300 hover:bg-green-200 hover:dark:bg-gray-800 hover:dark:border-green-800 + hover:dark:text-green-400") + (dissoc :next-arrow?)) + [:div + {:class "flex items-center justify-between"} + [:span {:class "sr-only"} children] + [:h3 {:class "font-medium"} children] + (when next-arrow? + [:div.w-4.h-4 + svg/arrow-right])]]) + +(defn navigation-button-list- [{:keys []} & children] + [:ol + {:class "space-y-4 w-72"} + (for [n children] + [:li n]) + + #_[:li + [:div + {:class + "w-full p-4 text-gray-900 bg-gray-100 border border-gray-300 rounded-lg dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400", + :role "alert"} + [:div + {:class "flex items-center justify-between"} + [:span {:class "sr-only"} "Review"] + [:h3 {:class "font-medium"} "4. Review"]]]] + #_[:li + [:div + {:class + "w-full p-4 text-gray-900 bg-gray-100 border border-gray-300 rounded-lg dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400", + :role "alert"} + [:div + {:class "flex items-center justify-between"} + [:span {:class "sr-only"} "Confirmation"] + [:h3 {:class "font-medium"} "5. Confirmation"]]]]]) + (defn validated-save-button- [{:keys [errors class] :as params} & children] (button- (-> {:color (or (:color params) :primary) diff --git a/src/clj/auto_ap/ssr/components/card.clj b/src/clj/auto_ap/ssr/components/card.clj index f8ef15f0..c6f49358 100644 --- a/src/clj/auto_ap/ssr/components/card.clj +++ b/src/clj/auto_ap/ssr/components/card.clj @@ -12,7 +12,7 @@ (defn content-card- [params & children] [:section (merge params {:class (hh/add-class " py-3 sm:py-5" (:class params))}) - [:div {:class "max-w-screen-2xl"} + [:div {:class (:max-w params "max-w-screen-2xl")} (into [:div {:class "relative overflow-hidden shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white"}] children)]]) diff --git a/src/clj/auto_ap/ssr/components/data_grid.clj b/src/clj/auto_ap/ssr/components/data_grid.clj index dd8a270b..eb86fa4a 100644 --- a/src/clj/auto_ap/ssr/components/data_grid.clj +++ b/src/clj/auto_ap/ssr/components/data_grid.clj @@ -38,11 +38,12 @@ (defn checkbox-header- [params & rest] [:th {:scope "col", :class "p-4"} [:div {:class "flex items-center"} - [:input {:id "checkbox-all", :type "checkbox", :class inputs/default-checkbox-classes :name (:name params) :value (:value params)}] + [:input (merge {:id "checkbox-all", :type "checkbox", :class inputs/default-checkbox-classes :name (:name params) :value (:value params)} params)] [:label {:for "checkbox-all", :class "sr-only"} "checkbox"]]]) -(defn data-grid- [{:keys [headers thead-params id]} & rest] - [:table {:class "w-full text-sm text-left text-gray-500 dark:text-gray-400" :id id} +(defn data-grid- [{:keys [headers thead-params id] :as params} & rest] + [:table (merge {:class "w-full text-sm text-left text-gray-500 dark:text-gray-400"} + (dissoc params :headers :thead-params)) [:thead (assoc thead-params :class "text-xs text-gray-800 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400") (into [:tr] @@ -70,7 +71,7 @@ [:div {:hx-get (bidi/path-for ssr-routes/only-routes route :request-method :get) - :hx-trigger "clientSelected from:body" + :hx-trigger "clientSelected from:body, invalidated from:body" :hx-swap "outerHTML swap:300ms" :id id} @@ -123,10 +124,11 @@ [:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" } [:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])]) -(defn new-row- [{:keys [index colspan tr-params] :as params} & content] +(defn new-row- [{:keys [index colspan tr-params row-offset] :as params} & content] (row- (merge {:class "new-row" - :x-data (hx/json {:newRowIndex index}) + :x-data (hx/json {:newRowIndex index + :offset (or row-offset 0)}) } tr-params) (cell- {:colspan colspan @@ -135,10 +137,10 @@ (a-button- (merge (dissoc params :index :colspan) { - "@click" "$dispatch('newRow', {index: newRowIndex++})" + "@click" "$dispatch('newRow', {index: (newRowIndex++)})" :color :secondary :hx-trigger "newRow" - :hx-vals (hiccup/raw "js:{index: event.detail.index}") + :hx-vals (hiccup/raw "js:{index: event.detail.index }") :hx-target "closest .new-row" :hx-swap "beforebegin"}) content)]))) diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index c630cd54..d01e8bf5 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -16,7 +16,7 @@ [:div (-> params (assoc "@click.outside" "open=false") (dissoc :handle-unexpected-error?) - (update :class (fnil hh/add-class "") "w-full h-full modal-stack")) + (update :class (fnil hh/add-class "") "")) children]) (defn modal-card- [params header content footer] @@ -47,11 +47,11 @@ children]) (defn modal-body- [params & children] - [:div {:class "px-6 py-2 space-y-6 overflow-y-scroll w-full shrink"} + [:div {:class "px-6 py-2 space-y-6 overflow-y-scroll w-full shrink grow"} children]) (defn modal-footer- [params & children] - [:div {:class "p-4"} + [:div {:class "p-4 border-t"} [:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex (hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"}) [:span {:class "w-2 h-2 bg-red-500 rounded-full"}] @@ -61,5 +61,5 @@ (defn modal-card-advanced- [params & children] [:div (merge params - {:class (hh/add-class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content flex flex-col h-full" (:class params "")) }) + {:class (hh/add-class "modal-card bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content flex flex-col max-h-screen max-w-screen" (:class params "")) }) children]) diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 3b9c7134..01f5531e 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -4,6 +4,7 @@ [auto-ap.ssr.hiccup-helper :as hh] [clojure.string :as str] [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.components.tags :as tags] [auto-ap.ssr.hx :as hx])) @@ -37,46 +38,59 @@ (defn typeahead- [params] - [:div {:x-data (hx/json {:open false - :baseUrl (if (str/includes? (:url params) "?") - (str (:url params) "&q=") - (str (:url params) "?q=")) - :value {:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))} - :search "" - :active -1 - :elements (if ((:value-fn params identity) (:value params)) - [{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}] - []) - :popper nil}) - :x-modelable "value.value" - :x-model (:x-model params) - :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed', modifiers: {name: 'offset', options: {offset: [0, 10]}}})" - } - [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) - (hh/add-class "cursor-pointer")) - "@click.prevent" "open = !open; popper.update()" - "@keydown.down.prevent.stop" "open = true; popper.update()" - "@keydown.backspace" "value = {value: '', label: '' }" - :tabindex 0 - :x-init (:x-init params) - :x-ref "input" - } - [:input (-> params - (dissoc :class) - (dissoc :value-fn) - (dissoc :content-fn) + [:div.relative {:x-data (hx/json {:open false + :baseUrl (if (str/includes? (:url params) "?") + (str (:url params) "&q=") + (str (:url params) "?q=")) + :value {:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))} + :search "" + :active -1 + :elements (if ((:value-fn params identity) (:value params)) + [{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}] + []) + :popper nil + :warning_badge nil}) + :x-modelable "value.value" + :x-model (:x-model params) + :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed', modifiers: {name: 'offset', options: {offset: [0, 10]}}}) + warning_badge = Popper.createPopper($refs.warning_badge, $refs.warning_pop, {placement: 'top', strategy: 'fixed', modifiers: {name: 'offset', options: {offset: [10,0 ]}}})"} + (if (:disabled params) + [:span {:x-text "value.label"}] + [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) + (hh/add-class "cursor-pointer")) + "@click.prevent" "open = !open; popper.update()" + "@keydown.down.prevent.stop" "open = true; popper.update()" + "@keydown.backspace" "value = {value: '', label: '' }" + :tabindex 0 + :x-init (:x-init params) + :x-ref "input"} + [:input (-> params + (dissoc :class) + (dissoc :value-fn) + (dissoc :content-fn) - (dissoc :placeholder) - (dissoc :x-model) - (assoc - "x-ref" "hidden" - :type "hidden" - ":value" "value.value" - :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] - [:div.flex.w-full.justify-items-stretch - [:span.flex-grow.text-left {"x-text" "value.label"}] - [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} - svg/drop-down]]] + (dissoc :placeholder) + (dissoc :x-model) + + (assoc + "x-ref" "hidden" + :type "hidden" + ":value" "value.value" + :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] + [:div.flex.w-full.justify-items-stretch + [:span.flex-grow.text-left {"x-text" "value.label"}] + [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} + svg/drop-down] + [:div {:x-show "value.warning" + :x-ref "warning_badge" + :x-effect "if (value.warning) { $nextTick(()=> warning_badge.update()) }"} + (tags/badge- {:class "peer"} "!") + + + [:div {:x-show "value.warning" + :x-ref "warning_pop" + :class "hidden peer-hover:block bg-red-50 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4" + :x-text "value.warning"}]]]]) [:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 ring-1" "x-ref" "dropdown" @@ -90,12 +104,12 @@ "x-show " "open" "x-trap" "open" "@click.outside" "open=false;"} - + [:input {:type "text" :class (-> (:class params) - (or "") - (hh/add-class default-input-classes) - (hh/replace-wildcard ["rounded" "border"] "border-bottom bg-gray-100 rounded-t-lg w-full")) + (or "") + (hh/add-class default-input-classes) + (hh/replace-wildcard ["rounded" "border"] "border-bottom bg-gray-100 rounded-t-lg w-full")) "x-model" "search" "placeholder" (:placeholder params) "@keydown.down.prevent" "active ++; active = active >= elements.length - 1 ? elements.length - 1 : active" @@ -113,8 +127,7 @@ "x-html" "element.label"}]]] [:template {:x-if "elements.length == 0"} [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs "} - "No results found"]]] - ]]) + "No results found"]]]]]) (defn use-size [size] @@ -156,12 +169,14 @@ (dissoc :size))]) (defn date-input- [{:keys [size] :as params}] - [:div.shrink - [:input + [:div.shrink {:x-data (hx/json {:value (:value params)})} + [:input (-> params (update :class (fnil hh/add-class "") default-input-classes) + (assoc :x-modelable "value") (assoc :type "text") (assoc "_" (hiccup/raw "init initDatepicker(me)")) + (assoc "@change" "value = $event.target.value; console.log(value)") (assoc "hx-on" (hiccup/raw "changeDate: htmx.trigger(this, \"change\") htmx:beforeCleanupElement: this.dp.destroy()")) (update :class #(str % (use-size size) " w-full")) @@ -201,8 +216,8 @@ rest (errors- {:errors (:errors params)}))) -(defn hidden- [{:keys [name value]}] - [:input {:type "hidden" :value value :name name}]) +(defn hidden- [{:keys [name value] :as params}] + [:input (merge {:type "hidden" :value value :name name} params)]) (defn checkbox- [params & rest] (if (seq rest) diff --git a/src/clj/auto_ap/ssr/components/link_dropdown.clj b/src/clj/auto_ap/ssr/components/link_dropdown.clj new file mode 100644 index 00000000..a4ad3d96 --- /dev/null +++ b/src/clj/auto_ap/ssr/components/link_dropdown.clj @@ -0,0 +1,25 @@ +(ns auto-ap.ssr.components.link-dropdown + (:require [auto-ap.ssr.components :as com] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg])) + +(defn link-dropdown [links] + (if (> (count links) 0) + + [:div {:x-data (hx/json {:popper nil + :show false}) + "@click.outside" "show=false" + + :x-init "popper = Popper.createPopper($refs.link, $refs.tooltip, {placement: 'bottom', strategy: 'fixed'})"} + + (com/a-icon-button {:x-ref "link" "@click.prevent" "show=!show; $nextTick(() => popper.update());" :class "relative"} + svg/paperclip + (com/badge {} (count links))) + [:div.divide-y.divide-gray-200.bg-white.rounded-lg.shadow.z-50 (hx/alpine-appear {:x-ref "tooltip" :x-show "show" :data-key "show"}) + [:div {:class "p-3 overflow-y-auto text-sm text-gray-700 dark:text-gray-200"} + [:div.flex.flex-col.gap-y-2 + (for [l links] + [:div.flex-initial + [:a {:href (:link l)} + (com/pill {:color (or (:color l) :primary) :class "truncate block shrink grow-0"} + (:content l))]])]]]])) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/components/multi_modal.clj b/src/clj/auto_ap/ssr/components/multi_modal.clj index f0866984..74c664c5 100644 --- a/src/clj/auto_ap/ssr/components/multi_modal.clj +++ b/src/clj/auto_ap/ssr/components/multi_modal.clj @@ -1,37 +1,26 @@ (ns auto-ap.ssr.components.multi-modal - (:require [auto-ap.ssr.components :as com] - [auto-ap.ssr.form-cursor :as fc] - - [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] - [auto-ap.ssr.utils - :refer [ html-response - assert-schema - main-transformer - modal-response - wrap-form-4xx-2 - wrap-schema-enforce]] + (:require [auto-ap.cursor :as cursor] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] [auto-ap.ssr.components.timeline :as timeline] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [assert-schema html-response main-transformer + modal-response wrap-form-4xx-2 wrap-schema-enforce]] [bidi.bidi :as bidi] [hiccup.util :as hu] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.hx :as hx] [malli.core :as mc] - [hiccup2.core :as hiccup2] - [hiccup2.core :as hiccup] - [auto-ap.cursor :as cursor] - [malli.core :as m] - [auto-ap.logging :as alog]) - (:import [auto_ap.cursor VecCursor])) + [malli.core :as m])) (def default-form-props {:hx-ext "response-targets" :hx-swap "outerHTML" :hx-target-400 "#form-errors .error-content" :hx-trigger "submit" - :hx-target "this" - "x-trap" "true" - :class "h-full w-full" }) + :hx-target "this" }) (defprotocol ModalWizardStep (step-key [this]) @@ -41,23 +30,20 @@ (step-name [this])) (defprotocol Initializable - (init-step-params [this request])) + (init-step-params [this multi-form-state request])) + +(defprotocol CustomNext + (custom-next-handler [this request])) (defprotocol Discardable (can-discard? [this step-params]) (discard-changes [this request])) - -(defn- init-step-params- [step request] - (if (satisfies? Initializable step) - (init-step-params step request) - {})) - (defprotocol LinearModalWizard (hydrate-from-request [this request]) (get-current-step [this]) (navigate [this step-key]) - + (form-schema [this]) (steps [this]) (get-step [this step-key]) @@ -86,6 +72,11 @@ :edit-path [] :step-params @cursor))) +(defn get-mfs-field [mfs k] + (or (get (:step-params mfs) k) + (get-in (:snapshot mfs) (conj (or (:edit-path mfs) []) + k)))) + (def step-key-schema (mc/schema [:orn {:decode/arbitrary clojure.edn/read-string :encode/arbitrary pr-str} [:sub-step [:cat :keyword [:or :int :string]]] @@ -114,12 +105,13 @@ :to (encode-step-key (step-key (get-step linear-wizard n)))})} (step-name (get-step linear-wizard n))]))))) (defn back-button [linear-wizard step validation-route] - [:a.cursor-pointer.whitespace-nowrap {:hx-put (hu/url (bidi/path-for ssr-routes/only-routes validation-route) - {:from (encode-step-key (step-key step)) - :to (encode-step-key (->> (partition-all 2 1 (steps linear-wizard)) - (filter (fn [[from to]] - (= to (step-key step)))) - ffirst))})} + [:a.cursor-pointer.whitespace-nowrap.font-medium.text-blue-600 {:hx-put (hu/url (bidi/path-for ssr-routes/only-routes validation-route) + {:from (encode-step-key (step-key step)) + :to (encode-step-key (->> (partition-all 2 1 (steps linear-wizard)) + (filter (fn [[from to]] + (= to (step-key step)))) + ffirst))}) + :class "dark:text-blue-500"} "Back"]) (defn default-next-button [linear-wizard step validation-route] @@ -146,7 +138,7 @@ [:div.w-5.h-5 svg/arrow-right])))) (defn default-step-body [params & children] - [:div.space-y-1 {:class "w-[600px] h-[700px]"} + [:div.space-y-1 {} children]) (defn default-step-footer [linear-wizard step & {:keys [validation-route @@ -173,12 +165,32 @@ (defn default-render-step [linear-wizard step & {:keys [head body footer validation-route discard-route]}] (let [is-last? (= (step-key step) (last (steps linear-wizard)))] (com/modal-card-advanced - {"@keydown.enter.prevent.stop" "$refs.next.click()" - :class (str (when is-last? "last-modal-step") - " transition duration-300 ease-in-out + {"@keydown.enter.prevent.stop" "if ($refs.next ) {$refs.next.click()}" + :class (str + "w-full h-full md:w-[750px] md:h-[600px] + group-[.forward]/transition:htmx-swapping:opacity-0 + group-[.forward]/transition:htmx-swapping:-translate-x-1/4 + group-[.forward]/transition:htmx-swapping:scale-75 + group-[.forward]/transition:htmx-swapping:ease-in + group-[.forward]/transition:htmx-added:opacity-0 + group-[.forward]/transition:htmx-added:scale-75 + group-[.forward]/transition:htmx-added:translate-x-1/4 + group-[.forward]/transition:htmx-added:ease-out + + group-[.backward]/transition:htmx-swapping:opacity-0 + group-[.backward]/transition:htmx-swapping:translate-x-1/4 + group-[.backward]/transition:htmx-swapping:scale-75 + group-[.backward]/transition:htmx-swapping:ease-in + group-[.backward]/transition:htmx-added:opacity-0 + group-[.backward]/transition:htmx-added:scale-75 + group-[.backward]/transition:htmx-added:-translate-x-1/4 + group-[.backward]/transition:htmx-added:ease-out + opacity-100 translate-x-0 scale-100" + (when is-last? "last-modal-step") + " transition duration-150 ") - ":class" (hiccup/raw "{ - \"htmx-swapping:-translate-x-2/3 htmx-swapping:opacity-0 htmx-swapping:scale-0 htmx-added:translate-x-2/3 htmx-added:opacity-0 htmx-added:scale-0 scale-100 translate-x-0 opacity-100\": $data.transitionType=='forward', + #_#_":class" (hiccup/raw "{ + \"htmx-added:opacity-0 opacity-100\": $data.transitionType=='forward', \"htmx-swapping:translate-x-2/3 htmx-swapping:opacity-0 htmx-swapping:scale-0 htmx-added:-translate-x-2/3 htmx-added:opacity-0 htmx-added:scale-0 scale-100 translate-x-0 opacity-100\": $data.transitionType=='backward' } ") @@ -186,8 +198,10 @@ (com/modal-header {} head) #_(com/modal-header-attachment {}) - [:div.flex.shrink - [:div.grow-0.pr-6.pt-2.bg-gray-100.self-stretch #_{:style "margin-left:-20px"} (render-timeline linear-wizard step validation-route)] + [:div.flex.shrink.overflow-auto.grow + (when (:render-timeline? linear-wizard) + [:div.grow-0.pr-6.pt-2.bg-gray-100.self-stretch.hidden.md:block #_{:style "margin-left:-20px"} + (render-timeline linear-wizard step validation-route)]) (com/modal-body {} body)] @@ -221,27 +235,36 @@ :else "forward"))) +(defn navigate-handler [{{:keys [wizard] :as request} :request to-step :to-step oob :oob}] + (let [current-step (get-current-step wizard) + wizard (navigate wizard to-step) + new-step (get-current-step wizard) + transition-type (get-transition-type wizard (step-key current-step) to-step)] + (html-response + (render-wizard wizard + (-> request + (assoc :multi-form-state (-> (:multi-form-state request) + (merge-multi-form-state) + (select-state (edit-path new-step request) {}) + (#(cond-> % + (satisfies? Initializable new-step) + (assoc :step-params + (init-step-params new-step % request)))))))) + :headers {"HX-reswap" (when transition-type "outerHTML swap:0.16s") + "x-transition-type" (or transition-type "none")} + :oob (or oob [])))) + (def next-handler (-> (fn [{:keys [wizard] :as request}] - (let [current-step (get-current-step wizard) - to-step (:to (:query-params request)) - wizard (navigate wizard to-step) - new-step (get-current-step wizard) - transition-type (get-transition-type wizard (step-key current-step) to-step)] - (html-response - (render-wizard wizard - (-> request - (assoc :multi-form-state (-> (:multi-form-state request) - (merge-multi-form-state) - (select-state - (edit-path new-step request) - (init-step-params- new-step request)))))) - :headers {"HX-reswap" (when transition-type "outerHTML swap:0.15s") - "x-transition-type" (or transition-type "none")}))) - (wrap-ensure-step) - (wrap-schema-enforce :query-schema - [:map - [:to step-key-schema]]))) + (let [current-step (get-current-step wizard)] + (if (satisfies? CustomNext current-step) + (custom-next-handler current-step request) + (navigate-handler {:request request + :to-step (:to (:query-params request))})))) + (wrap-ensure-step) + (wrap-schema-enforce :query-schema + [:map + [:to {:optional true} [:maybe step-key-schema]]]))) (def discard-handler (-> @@ -254,7 +277,7 @@ (render-wizard wizard (-> request (assoc :multi-form-state (discard-changes current-step multi-form-state)))) - :headers {"HX-reswap" (when transition-type "outerHTML swap:0.15s") + :headers {"HX-reswap" (when transition-type "outerHTML swap:0.16s") "x-transition-type" (or transition-type "none")}))) (wrap-schema-enforce :query-schema [:map @@ -263,11 +286,12 @@ (def submit-handler (-> (fn [{:keys [wizard multi-form-state] :as request}] (submit wizard (-> request - (assoc :multi-form-state (merge-multi-form-state multi-form-state))))) + (assoc :multi-form-state (merge-multi-form-state multi-form-state))))) (wrap-ensure-step))) -(defn default-render-wizard [linear-wizard {:keys [multi-form-state form-errors snapshot current-step] :as request} & {:keys [form-params]}] - (let [current-step (get-current-step linear-wizard) +(defn default-render-wizard [linear-wizard {:keys [multi-form-state form-errors snapshot current-step] :as request} & {:keys [form-params render-timeline?] + :or {render-timeline? true}}] + (let [current-step (get-current-step (assoc linear-wizard :render-timeline? render-timeline?)) edit-path (edit-path current-step request)] [:form#wizard-form form-params (fc/start-form multi-form-state (when form-errors {:step-params form-errors}) @@ -311,15 +335,24 @@ (handler (assoc request :wizard (hydrate-from-request linear-wizard request)))))) -(defn open-wizard-handler [{:keys [wizard current-step] :as request}] - (modal-response - [:div {:x-data (hx/json {"transitionType" "none" - - } - ) - "@htmx:after-request" "if(event.detail.xhr.getResponseHeader('x-transition-type')) { $data.transitionType = event.detail.xhr.getResponseHeader('x-transition-type');}" - } - (render-wizard wizard request)])) +(defn open-wizard-handler [{:keys [wizard current-step query-params] :as request}] + (cond-> + (modal-response + [:div#transitioner.flex-1 {:x-data (hx/json {"transitionType" "none"}) + :x-ref "transitioner" + :class "" + "@htmx:after-request" "if(event.detail.xhr.getResponseHeader('x-transition-type')) { + $refs.transitioner.classList.remove('forward') + $refs.transitioner.classList.remove('backward'); + $refs.transitioner.classList.add('group/transition') + $refs.transitioner.classList.add(event.detail.xhr.getResponseHeader('x-transition-type')); + } else { + + $refs.transitioner.classList.remove('group/transition') + } + "} + (render-wizard wizard request)]) + (get query-params :replace-modal) (assoc-in [:headers "hx-trigger"] "modalswap"))) @@ -346,4 +379,18 @@ [:maybe :any]]] (:form-params request) - main-transformer))))) \ No newline at end of file + main-transformer))))) + +#_(comment + (def f {"snapshot" + "{:invoices [{:invoice_id 17592297837035, :amount 23.0, :invoice {:db/id 17592297837035, :invoice/vendor {:db/id 17592186045722, :vendor/name \"Sysco\"}, :invoice/client {:db/id 17592232555238}, :invoice/outstanding-balance 23.0, :invoice/invoice-number \"702,34\"}} {:invoice_id 17592297837049, :amount 23.0, :invoice {:db/id 17592297837049, :invoice/vendor {:db/id 17592186045722, :vendor/name \"Sysco\"}, :invoice/client {:db/id 17592232555238}, :invoice/outstanding-balance 23.0, :invoice/invoice-number \"80[234234\"}}], :client 17592232555238}", + "edit-path" "[]", + "current-step" ":payment-details", + "mode" "advanced", + "step-params" + {"invoices" + {"0" {"invoice_id" "17592297837035", "amount" "1"}, + "1" {"invoice_id" "17592297837049", "amount" "23.00"}}}}) + (mc/decode [:map [:step-params {:optional true} [:maybe :any]]] + f + main-transformer)) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/components/navbar.clj b/src/clj/auto_ap/ssr/components/navbar.clj index 28672eb5..e5617063 100644 --- a/src/clj/auto_ap/ssr/components/navbar.clj +++ b/src/clj/auto_ap/ssr/components/navbar.clj @@ -8,7 +8,7 @@ [auto-ap.ssr.svg :as svg] [bidi.bidi :as bidi])) -(defn navbar- [{:keys [client-selection client identity clients]}] +(defn navbar- [{:keys [client-selection client identity clients dd-env]}] [:nav {:class "fixed z-30 w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700"} [:div {:class "px-3 py-3 lg:px-5 lg:pl-3"} [:div {:class "flex items-center justify-between"} @@ -18,8 +18,9 @@ [:span {:class "sr-only"} "Open sidebar"] [:svg {:class "w-6 h-6", :aria-hidden "true", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} [:path {:clip-rule "evenodd", :fill-rule "evenodd", :d "M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"}]]] - [:a {:href "/" :class "flex ml-2 md:mr-24"} - [:img {:src "/img/logo-big2.png", :class "h-10 mr-16", :alt "Integreat logo"}]]] + [:a {:href "/" :class "flex ml-2 hidden md:mr-24 sm:inline"} + [:img {:src "/img/logo-big2.png", :class "h-10", :alt "Integreat logo"}]] + (when-not (= "prod" dd-env) [:div.rounded-full.bg-yellow-200.text-lg.text-yellow-800.px-4.hidden.md:block.mr-8 "environment: " dd-env])] [:div {:class "flex items-center gap-4"} diff --git a/src/clj/auto_ap/ssr/components/page.clj b/src/clj/auto_ap/ssr/components/page.clj index de908372..6410af1f 100644 --- a/src/clj/auto_ap/ssr/components/page.clj +++ b/src/clj/auto_ap/ssr/components/page.clj @@ -1,12 +1,12 @@ (ns auto-ap.ssr.components.page - (:require - [auto-ap.ssr.components.aside :refer [left-aside-]] - [auto-ap.ssr.components.navbar :refer [navbar-]] - [hiccup2.core :as hiccup] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.hx :as hx])) + (:require [auto-ap.ssr.components.aside :refer [left-aside-]] + [auto-ap.ssr.components.navbar :refer [navbar-]] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg] + [config.core :refer [env]] + [hiccup2.core :as hiccup])) -(defn page- [{:keys [nav page-specific client clients client-selection identity app-params] :or {app-params {}}} & children] +(defn page- [{:keys [nav page-specific client clients client-selection identity app-params request] :or {app-params {}} } & children] [:div#app {"_" (hiccup/raw " on notification from body put event.detail.value into #notification-details then add .htmx-added to #notification-holder then remove .hidden from #notification-holder then wait 30ms then remove .htmx-added from #notification-holder on htmx:responseError put event.detail.xhr.response into #error-details then add .htmx-added to #error-holder then remove .hidden from #error-holder then wait 30ms then remove .htmx-added from #error-holder" @@ -15,11 +15,13 @@ (navbar- {:client-selection client-selection :clients clients :client client - :identity identity}) + :identity identity + :dd-env (:dd-env env)}) [:div#app-contents.flex.pt-16.overflow-hidden (assoc app-params :hx-disinherit "*" :x-init "leftNavShow = true") - (left-aside- {:nav nav + (left-aside- {:nav (when nav + (nav request)) :page-specific page-specific}) [:div#main-content {:class "relative w-full h-full overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content lg:pl-64" ":class" "leftNavShow ? 'lg:pl-64' : ''" diff --git a/src/clj/auto_ap/ssr/components/radio.clj b/src/clj/auto_ap/ssr/components/radio.clj index e02dc4d5..379d776e 100644 --- a/src/clj/auto_ap/ssr/components/radio.clj +++ b/src/clj/auto_ap/ssr/components/radio.clj @@ -2,7 +2,7 @@ (:require [auto-ap.ssr.hiccup-helper :as hh] [auto-ap.ssr.hx :as hx])) -(defn radio- [{:keys [options name title size orientation] :or {size :medium} selected-value :value}] +(defn radio-card- [{:keys [options name title size orientation] :or {size :medium} selected-value :value}] [:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title] [:ul {:class (cond-> "w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white" (= orientation :horizontal) (-> (hh/add-class "flex gap-2 flex-wrap") @@ -26,6 +26,42 @@ (str " " "text-sm"))} (= (cond-> selected-value (keyword? selected-value) clojure.core/name) value) (assoc :checked true))] [:label {:for (str "list-" name "-" value) + :class + (cond-> "w-full ml-2 font-medium text-gray-900 dark:text-gray-300" + (= size :small) + (str " " "text-xs py-2") + + (= size :medium) + (str " " "text-sm py-3") + + (= orientation :horizontal) + (hh/remove-class "w-full"))} content]]])]) + +(defn radio-list- [{:keys [options name x-model title size orientation] :or {size :medium} selected-value :value}] + [:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title] + [:ul {:class (cond-> "w-48 text-sm font-medium text-gray-900" + (= orientation :horizontal) (-> (hh/add-class "flex gap-2 flex-wrap") + (hh/remove-wildcard ["w-" "rounded-lg" "border" "bg-"])))} + (for [{:keys [value content]} options] + [:li {:class (cond-> "w-full" + (= orientation :horizontal) (-> (hh/remove-wildcard ["w-full" "rounded-"]) + (hh/add-class "w-auto shrink-0 block px-3")))} + [:div {:class (cond-> "flex items-center" + (not= orientation :horizontal) (hh/add-class "pl-3"))} + [:input (cond-> {:id (str "list-" name "-" value) + :x-model x-model + :type "radio", + :value value + :name name + :class + (cond-> "w-4 h-4 text-blue-600" + (= size :small) + (str " " "text-xs") + + (= size :medium) + (str " " "text-sm"))} + (= (cond-> selected-value (keyword? selected-value) clojure.core/name) value) (assoc :checked true))] + [:label {:for (str "list-" name "-" value) :class (cond-> "w-full ml-2 font-medium text-gray-900 dark:text-gray-300" (= size :small) diff --git a/src/clj/auto_ap/ssr/components/tags.clj b/src/clj/auto_ap/ssr/components/tags.clj index ea7b6269..da9ceba5 100644 --- a/src/clj/auto_ap/ssr/components/tags.clj +++ b/src/clj/auto_ap/ssr/components/tags.clj @@ -21,4 +21,4 @@ children)) (defn badge- [params & children] - [:div {:class (hh/add-class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-300 border-3 border-white rounded-full -top-2 -right-2 dark:border-gray-900" (:class params))} children]) + [:div {:class (hh/add-class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-black text-white bg-red-300 border-3 border-white rounded-full -top-2 -right-2 dark:border-gray-900" (:class params))} children]) diff --git a/src/clj/auto_ap/ssr/components/timeline.clj b/src/clj/auto_ap/ssr/components/timeline.clj index 61124ee6..1e78553f 100644 --- a/src/clj/auto_ap/ssr/components/timeline.clj +++ b/src/clj/auto_ap/ssr/components/timeline.clj @@ -40,7 +40,8 @@ children ])) (defn vertical-timeline [params & children] - [:ol {:class "flex flex-col items-start space-y-2 text-xs text-center text-gray-500 bg-gray-100 dark:text-gray-400 sm:text-base dark:bg-gray-800 sm:space-y-4 px-2"} + [:ol {:class (hh/add-class "flex flex-col items-start space-y-2 text-xs text-center text-gray-500 bg-gray-100 dark:text-gray-400 sm:text-base dark:bg-gray-800 sm:space-y-4 px-2" + (:class params))} children #_[:li {:class "flex items-center"} [:span {:class "flex items-center justify-center w-5 h-5 mr-2 text-xs border border-gray-500 rounded-full shrink-0 dark:border-gray-400"}]]]) diff --git a/src/clj/auto_ap/ssr/core.clj b/src/clj/auto_ap/ssr/core.clj index 724bffbc..b9f030c0 100644 --- a/src/clj/auto_ap/ssr/core.clj +++ b/src/clj/auto_ap/ssr/core.clj @@ -4,6 +4,7 @@ [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated wrap-secure]] [auto-ap.ssr.account :as account] + [auto-ap.ssr.payments :as payments] [auto-ap.ssr.admin :as admin] [auto-ap.ssr.admin.accounts :as admin-accounts] [auto-ap.ssr.admin.background-jobs :as admin-jobs] @@ -28,6 +29,8 @@ [auto-ap.ssr.pos.refunds :as pos-refunds] [auto-ap.ssr.pos.sales-orders :as pos-sales] [auto-ap.ssr.pos.tenders :as pos-tenders] + [auto-ap.ssr.invoices :as invoice] + [auto-ap.ssr.outgoing-invoice.new :as oin] [auto-ap.ssr.search :as search] [auto-ap.ssr.transaction.insights :as insights] [auto-ap.ssr.users :as users] @@ -81,6 +84,7 @@ :admin-ezcater-xls (wrap-client-redirect-unauthenticated (wrap-admin ezcater-xls/page)) :search (wrap-client-redirect-unauthenticated (wrap-secure search/dialog-contents))} (into company-1099/key->handler) + (into invoice/key->handler) (into import-batch/key->handler) (into pos-sales/key->handler) (into pos-expected-deposits/key->handler) @@ -96,6 +100,7 @@ (into admin-vendors/key->handler) (into admin-clients/key->handler) (into admin-rules/key->handler) - (into indicators/key->handler))) - + (into indicators/key->handler) + (into payments/key->handler) + (into oin/route->handler))) diff --git a/src/clj/auto_ap/ssr/grid_page_helper.clj b/src/clj/auto_ap/ssr/grid_page_helper.clj index 32ca519b..8aa1b87f 100644 --- a/src/clj/auto_ap/ssr/grid_page_helper.clj +++ b/src/clj/auto_ap/ssr/grid_page_helper.clj @@ -1,25 +1,32 @@ (ns auto-ap.ssr.grid-page-helper - (:require - [auto-ap.graphql.utils :refer [extract-client-ids]] - [auto-ap.query-params :as query-params] - [auto-ap.routes.utils - :refer [wrap-client-redirect-unauthenticated wrap-secure]] - [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.ssr.components :as com] - [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.ui :refer [base-page]] - [auto-ap.ssr.utils :refer [html-response]] - [auto-ap.time :as atime] - [malli.core :as m] - [bidi.bidi :as bidi] - [cemerick.url :as url] - [clojure.string :as str] - [hiccup2.core :as hiccup] - [malli.transform :as mt2] - [auto-ap.ssr.hiccup-helper :as hh])) + (:require [auto-ap.graphql.utils :refer [extract-client-ids]] + [auto-ap.logging :as alog] + [auto-ap.query-params :as query-params] + [auto-ap.routes.utils + :refer [wrap-client-redirect-unauthenticated wrap-secure]] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.hiccup-helper :as hh] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.ui :refer [base-page]] + [auto-ap.ssr.utils :refer [html-response main-transformer]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [cemerick.url :as url] + [clojure.string :as str] + [hiccup2.core :as hiccup] + [malli.core :as m] + [malli.transform :as mt2] + [malli.transform :as mt] + [taoensso.encore :refer [filter-vals]])) (defn row* [gridspec user entity {:keys [flash? delete-after-settle? request class] :as options}] - (let [cells (->> gridspec + (let [cells (if (:check-boxes? gridspec) + [(com/data-grid-cell {} (com/checkbox {:name "id" :value ((:id-fn gridspec) entity) + :x-model "selected"}))] + []) + cells (->> gridspec :headers (filter (fn [h] (if (and (:hide? h) @@ -30,14 +37,15 @@ (com/data-grid-cell {:class (if-let [show-starting (:show-starting header)] (format "hidden %s:table-cell" show-starting) (:class header))} - ((:render header) entity))))) + ((:render header) entity)))) + (into cells)) cells (conj cells (com/data-grid-right-stack-cell {} (into [:form.flex.space-x-2 [:input {:type :hidden :name "id" :value ((:id-fn gridspec) entity)}]] ((:row-buttons gridspec) request entity))))] ;; TODO double check usage of row buttons user and identity in callers - (apply com/data-grid-row + (apply com/data-grid-row {:class (cond-> (or class "") - flash? (hh/add-class "live-added")) + flash? (hh/add-class "live-added")) "_" (hiccup/raw (when delete-after-settle? " on htmx:afterSettle wait 400ms then remove me")) @@ -52,24 +60,18 @@ (defn sort-by-list [grid-spec sort] (if (seq sort) - (into - [:div.flex.gap-2.items-center - - "sorted by" + (into + [:div.flex.gap-2.items-center - ] - (for [{:keys [name sort-icon sort-key ]} sort] - [:div.py-1.px-3.text-sm.rounded.bg-gray-100.dark:bg-gray-600.flex.items-center.gap-2.relative name [:div.h-4.w-4.mr-3 sort-icon] - [:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white hover:scale-110 transition-all duration-300 bg-gray-400 border-2 border-white rounded-full -top-2 -right-2 dark:border-gray-900"} - [:a {:href (str (bidi/path-for ssr-routes/only-routes - (:route grid-spec)) "?remove-sort=" sort-key) - :hx-boost "true" - :hx-target (str "#" (:id grid-spec)) - - } - [:div.h-4.w-4 svg/x]] - ]] - )) + "sorted by"] + (for [{:keys [name sort-icon sort-key]} sort] + [:div.py-1.px-3.text-sm.rounded.bg-gray-100.dark:bg-gray-600.flex.items-center.gap-2.relative name [:div.h-4.w-4.mr-3 sort-icon] + [:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white hover:scale-110 transition-all duration-300 bg-gray-400 border-2 border-white rounded-full -top-2 -right-2 dark:border-gray-900"} + [:a {:hx-get (str (bidi/path-for ssr-routes/only-routes + (:route grid-spec)) "?remove-sort=" sort-key) + :href "#" + :hx-target (str "#" (:id grid-spec))} + [:div.h-4.w-4 svg/x]]]])) "default sort")) (defn table* [grid-spec user {{:keys [start per-page flash-id sort]} :parsed-query-params :as request}] @@ -79,7 +81,9 @@ request)] (com/data-grid-card {:id (:id grid-spec) - :title (:title grid-spec) + :title (if (string? (:title grid-spec)) + (:title grid-spec) + ((:title grid-spec) request)) :route (:route grid-spec) :start start :per-page per-page @@ -87,7 +91,18 @@ :subtitle [:div.flex.items-center.gap-2 [:span (format "Total %s: %d, " (:entity-name grid-spec) total)] (sort-by-list grid-spec sort)] - :action-buttons ((:action-buttons grid-spec) request) + :action-buttons (cond->> ((:action-buttons grid-spec) request) + (:check-boxes? grid-spec) (into [(com/pill {:color :primary + :x-show "selected.length > 0"} + [:div.flex.space-x-2.items-center + [:div + + [:span {:x-text "selected.length" :x-show "!all_selected"}] + [:span {:x-show "all_selected"} "All"] + " selected"] + [:div.w-3.h-3 + (com/link {"@click" "selected=[]; all_selected=false"} + svg/x)]])])) :rows (for [entity entities] (row* grid-spec user entity {:flash? (= flash-id ((:id-fn grid-spec) entity)) :request request})) :thead-params {:hx-get (bidi/path-for ssr-routes/only-routes @@ -97,37 +112,37 @@ :hx-trigger "sorted once" :hx-vals "js:{\"toggle-sort\": event.detail.key || \"\"}"} :headers - (conj - (->> grid-spec - :headers - (map - (fn [h] - (cond - (and (:hide? h) - ((:hide? h) request)) - nil + (conj + (->> grid-spec + :headers + (map + (fn [h] + (cond + (and (:hide? h) + ((:hide? h) request)) + nil - (:sort-key h) - (com/data-grid-sort-header {:class (if-let [show-starting (:show-starting h)] - (format "hidden %s:table-cell" show-starting) - (:class h)) - :sort-key (:sort-key h)} + (:sort-key h) + (com/data-grid-sort-header {:class (if-let [show-starting (:show-starting h)] + (format "hidden %s:table-cell" show-starting) + (:class h)) + :sort-key (:sort-key h)} - [:div.flex.gap-4.items-center - (:name h) - [:div.h-6.w-6.text-gray-400.dark:text-gray-500 (sort-icon sort (:sort-key h))]]) + [:div.flex.gap-4.items-center + (:name h) + [:div.h-6.w-6.text-gray-400.dark:text-gray-500 (sort-icon sort (:sort-key h))]]) - :else - (com/data-grid-header {:class (if-let [show-starting (:show-starting h)] - (format "hidden %s:table-cell" show-starting) - (:class h)) - :sort-key (:sort-key h)} - (:name h)) - - ))) - (filter identity) - (into [])) - (com/data-grid-header {}))}))) + :else + (com/data-grid-header {:class (if-let [show-starting (:show-starting h)] + (format "hidden %s:table-cell" show-starting) + (:class h)) + :sort-key (:sort-key h)} + (:name h))))) + (filter identity) + (into (if (:check-boxes? grid-spec) + [(com/data-grid-checkbox-header {:name "all" :value "all" :x-model "all_selected"})] + []))) + (com/data-grid-header {}))}))) (defn sort->query [s] @@ -137,47 +152,47 @@ s))) (defn default-unparse-query-params [query-params] - (reduce - (fn [query-params [k value]] - (assoc query-params k - (cond (= k :sort) - (sort->query value) + (reduce + (fn [query-params [k value]] + (assoc query-params k + (cond (= k :sort) + (sort->query value) - (instance? org.joda.time.base.AbstractInstant value) - (atime/unparse-local value atime/normal-date) + (instance? org.joda.time.base.AbstractInstant value) + (atime/unparse-local value atime/normal-date) - (instance? Long value) - (str value) + (instance? Long value) + (str value) - (instance? Double value) - (format "%.2f" value) + (instance? Double value) + (format "%.2f" value) - (instance? Float value) - (format "%.2f" value) + (instance? Float value) + (format "%.2f" value) - (keyword? value) - (name value) + (keyword? value) + (name value) - (and (map? value) - (:db/id value)) - (:db/id value) + (and (map? value) + (:db/id value)) + (:db/id value) - :else - value))) - query-params - query-params)) + :else + value))) + query-params + query-params)) (defn default-parse-query-params [grid-spec] (comp - (query-params/apply-remove-sort) - (query-params/apply-toggle-sort grid-spec) - (query-params/apply-date-range :date-range :start-date :end-date) - (query-params/parse-key :exact-match-id query-params/parse-long) - (query-params/parse-key :sort #(query-params/parse-sort grid-spec %)) - (query-params/parse-key :per-page query-params/parse-long) - (query-params/parse-key :start query-params/parse-long) - (query-params/parse-key :start-date query-params/parse-date) - (query-params/parse-key :end-date query-params/parse-date))) + (query-params/apply-remove-sort) + (query-params/apply-toggle-sort grid-spec) + (query-params/apply-date-range :date-range :start-date :end-date) + (query-params/parse-key :exact-match-id query-params/parse-long) + (query-params/parse-key :sort #(query-params/parse-sort grid-spec %)) + (query-params/parse-key :per-page query-params/parse-long) + (query-params/parse-key :start query-params/parse-long) + (query-params/parse-key :start-date query-params/parse-date) + (query-params/parse-key :end-date query-params/parse-date))) (defn wrap-trim-client-ids [handler] (fn trim-client-ids [request] @@ -196,10 +211,25 @@ (let [unparse-query-params (or (:unparse-query grid-spec) default-unparse-query-params)] (html-response (table* - grid-spec - identity - request) - :headers {"hx-push-url" (str "?" (url/map->query (unparse-query-params (:parsed-query-params request))))} + grid-spec + identity + request) + :headers {"hx-push-url" (str "?" (url/map->query + (dissoc (if (:query-schema grid-spec) + (do + (alog/peek ::setup4 + (pr-str (update (filter-vals #(not (nil? %)) + (m/encode (:query-schema grid-spec) + (:query-params request) + main-transformer)) + "sort" sort->query))) + (update (filter-vals #(not (nil? %)) + (m/encode (:query-schema grid-spec) + (:query-params request) + main-transformer)) + "sort" sort->query)) + (unparse-query-params (:parsed-query-params request))) + "selected" "all-selected")))} ;; TODO seems hacky to special case selected and all-selected here :oob (when-let [oob-render (:oob-render grid-spec)] (oob-render request))))) (wrap-trim-client-ids) @@ -208,22 +238,28 @@ (wrap-secure) (wrap-client-redirect-unauthenticated))) -(defn page-route [grid-spec ] +(defn page-route [grid-spec] (-> (fn page [{:keys [identity] :as request}] (base-page - request - (com/page {:nav (:nav grid-spec) - :page-specific (when-let [page-specific-nav (:page-specific-nav grid-spec)] - [:div#page-specific-nav (page-specific-nav request)]) - :client-selection (:client-selection (:session request)) - :clients (:clients request) - :client (:client request) - :identity (:identity request)} - (apply com/breadcrumbs {} (:breadcrumbs grid-spec)) + request + (com/page {:nav (:nav grid-spec) + :page-specific (when-let [page-specific-nav (:page-specific-nav grid-spec)] + [:div#page-specific-nav (page-specific-nav request)]) + :client-selection (:client-selection (:session request)) + :clients (:clients request) + :client (:client request) + :identity (:identity request) + :request request} + (apply com/breadcrumbs {} (:breadcrumbs grid-spec)) + [:div {:x-data (hx/json {:selected [] :all_selected false}) + "x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})" + :x-init "$watch('selected', s=> $dispatch('selectedChanged', {selected: s, all_selected: all_selected}) ); + $watch('all_selected', a=>$dispatch('selectedChanged', {selected: selected, all_selected: a}))"} + (table* grid-spec identity - request)) - (:title grid-spec))) + request)]) + (:title grid-spec))) (wrap-trim-client-ids) (query-params/wrap-parse-query-params (or (:parse-query-params grid-spec) (default-parse-query-params grid-spec))) @@ -235,12 +271,15 @@ (def header-spec (m/schema [:map [:key :string] [:name :string] + [:header-class {:optional true} [:maybe :string]] [:sort-key {:optional true} :string] [:render [:=> [:cat entity-spec] :any]] [:hide? {:optional true} [:=> [:cat entity-spec] :boolean]]])) (def grid-spec (m/schema [:map [:id :string] - [:nav vector?] + [:nav [:=> + [:cat request-spec] + vector?]] [:page-specific-nav {:optional true :default (fn [request])} @@ -264,10 +303,12 @@ {:optional true :default (fn [request])} [:=> - [:cat request-spec] - vector?]] + [:cat request-spec] + vector?]] [:breadcrumbs [:vector vector?]] - [:title :string] + [:title [:or :string + [:=> [:cat [:map-of :keyword :any]] + :string]]] [:entity-name :string] [:route :keyword] [:action-buttons @@ -290,4 +331,13 @@ (m/explain grid-spec grid-page)))) (m/decode grid-spec grid-page (mt2/default-value-transformer {::mt2/add-optional-keys true}))) +(defn wrap-apply-sort [handler grid-spec] + (fn apply-sort [request] + (handler (update request :query-params + (fn [qp] + ((comp + (query-params/apply-remove-sort) + (query-params/apply-toggle-sort grid-spec) + (query-params/parse-key :sort #(query-params/parse-sort grid-spec %))) + qp)))))) diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index 2e54080c..d8bda05b 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -20,13 +20,13 @@ (str/join ", " triggers)) (defn alpine-appear [m] - (assoc m - "x-transition:enter" "transition duration-500" + (assoc m + "x-transition:enter" "transition-opacity duration-500" "x-transition:enter-start" "opacity-0" "x-transition:enter-end" "opacity-100")) (defn alpine-disappear [m] - (assoc m + (assoc m "x-transition:leave" "transition duration-500" "x-transition:leave-start" "opacity-100" "x-transition:leave-end" "opacity-0")) @@ -41,12 +41,15 @@ (defn bind-alpine-vals [m field->alpine-field] (assoc m "x-bind:hx-vals" - + (format "JSON.stringify({%s})" (str/join ", " (map - (fn [[field alpine-field]] - (format "\"%s\": $data.%s || ''" field alpine-field)) + (fn [[field alpine-field]] + (format "\"%s\": $data.%s || ''" field alpine-field)) - field->alpine-field))))) + field->alpine-field))))) + +(defn trigger-click-or-enter [m] + (assoc m :hx-trigger "click, keyup[keyCode==13]")) diff --git a/src/clj/auto_ap/ssr/indicators.clj b/src/clj/auto_ap/ssr/indicators.clj index e9ef753e..9b6dea16 100644 --- a/src/clj/auto_ap/ssr/indicators.clj +++ b/src/clj/auto_ap/ssr/indicators.clj @@ -1,8 +1,8 @@ (ns auto-ap.ssr.indicators (:require [auto-ap.routes.indicators :as route] [auto-ap.ssr.components :as com] - [auto-ap.ssr.utils :refer [html-response wrap-schema-enforce]] - [auto-ap.time :as atime] + [auto-ap.ssr.utils :refer [clj-date-schema html-response + wrap-schema-enforce]] [clj-time.coerce :as c] [clj-time.core :as t])) @@ -32,9 +32,5 @@ (def key->handler {::route/days-ago (wrap-schema-enforce days-ago :query-schema - [:map [:date {:optional false - :decode/arbitrary (fn [m] - (if (string? m) - (c/to-date (atime/parse m atime/normal-date)) - m))} - inst?]])}) \ No newline at end of file + [:map [:date {:optional false} + clj-date-schema ]])}) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/invoice/common.clj b/src/clj/auto_ap/ssr/invoice/common.clj new file mode 100644 index 00000000..382b3808 --- /dev/null +++ b/src/clj/auto_ap/ssr/invoice/common.clj @@ -0,0 +1,25 @@ +(ns auto-ap.ssr.invoice.common) + +(def default-read '[:db/id + :invoice/invoice-number + :invoice/total + :invoice/outstanding-balance + :invoice/source-url + + + [:invoice/date :xform clj-time.coerce/from-date] + [:invoice/due :xform clj-time.coerce/from-date] + [:invoice/scheduled-payment :xform clj-time.coerce/from-date] + {:invoice/client [:client/code :db/id :client/name] + :invoice/expense-accounts [* {:invoice-expense-account/account [:account/name :db/id + :account/location + {:account/client-overrides [:account-client-override/name + {:account-client-override/client [:db/id]}]}]}] + [:transaction/_invoices :as :invoice/transaction] [:db/id] + [:journal-entry/_original-entity :as :invoice/journal-entry] [:db/id] + [:payment/_invoices :as :invoice/payments] [:db/id :payment/date :payment/amount + + {[:transaction/_payment :as :payment/transaction] [:db/id] + [:payment/status :xform iol-ion.query/ident] [:db/ident]}] + [:invoice/status :xform iol-ion.query/ident] [:db/ident] + :invoice/vendor [:vendor/name :db/id]}]) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/invoice/glimpse.clj b/src/clj/auto_ap/ssr/invoice/glimpse.clj index e37320a0..87f5580e 100644 --- a/src/clj/auto_ap/ssr/invoice/glimpse.clj +++ b/src/clj/auto_ap/ssr/invoice/glimpse.clj @@ -420,7 +420,7 @@ invoice_dropzone = new Dropzone(\"#invoice\", { :method request-method) (base-page request - (com/page {:nav (com/admin-aside-nav) + (com/page {:nav com/admin-aside-nav :client-selection (:client-selection (:session request)) :client (:client request) :identity (:identity request) diff --git a/src/clj/auto_ap/ssr/invoice/new_invoice_wizard.clj b/src/clj/auto_ap/ssr/invoice/new_invoice_wizard.clj new file mode 100644 index 00000000..1de76014 --- /dev/null +++ b/src/clj/auto_ap/ssr/invoice/new_invoice_wizard.clj @@ -0,0 +1,843 @@ +(ns auto-ap.ssr.invoice.new-invoice-wizard + (:require [auto-ap.datomic + :refer [audit-transact conn pull-attr]] + [auto-ap.datomic.accounts :as d-accounts] + [auto-ap.datomic.invoices :as d-invoices] + [auto-ap.graphql.utils :refer [assert-can-see-client + assert-not-locked exception->4xx]] + [auto-ap.logging :as alog] + [auto-ap.routes.invoice :as route] + [auto-ap.routes.utils + :refer [wrap-client-redirect-unauthenticated]] + [auto-ap.rule-matching :as rm] + [auto-ap.solr :as solr] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.common-handlers :refer [add-new-entity-handler]] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.multi-modal :as mm] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.invoice.common :refer [default-read]] + [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [->db-id apply-middleware-to-all-handlers clj-date-schema + entity-id form-validation-error html-response money strip + wrap-schema-enforce]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clj-time.coerce :as coerce] + [clj-time.core :as time] + [datomic.api :as dc] + [hiccup.util :as hu] + [iol-ion.query :refer [dollars=]] + [iol-ion.utils :refer [random-tempid]] + [malli.core :as mc] + [malli.util :as mut])) + +(defn get-vendor [vendor-id] + (dc/pull + (dc/db conn) + [:vendor/terms + :vendor/automatically-paid-when-due + {:vendor/default-account d-accounts/default-read + :vendor/account-overrides + [:vendor-account-override/client + {:vendor-account-override/account d-accounts/default-read}]} + {:vendor/terms-overrides + [:vendor-terms-override/client :vendor-terms-override/terms]}] + vendor-id)) + +(defn check-invoice-expense-account-location [iea] + (let [account-location (pull-attr (dc/db conn) :account/location (:invoice-expense-account/account iea))] + (when (and (seq account-location) + (not= (:invoice-expense-account/location iea) + account-location)) + (throw (ex-info "Exception." {:type (str "expected " account-location)}))) + (when (and (empty? account-location) + (= "A" (:invoice-expense-account/location iea))) + + (throw (ex-info "Exception." {:type "'A' not allowed"}))) + true)) + +(defn check-allowance [account-id] + (let [allowance (:account/invoice-allowance (dc/pull (dc/db conn) '[{[:account/invoice-allowance :xform iol-ion.query/ident] + [:db/ident]}] + account-id))] + (not= :allowance/denied + allowance))) + +(defn check-vendor-default-account [vendor-id] + (some? (:vendor/default-account (get-vendor vendor-id)))) + +(def new-form-schema + [:map + [:db/id {:optional true} [:maybe entity-id]] + [:customize-due-and-scheduled? {:optional true :default false :decode/arbitrary (fn [x] (if (= "" x) + false + x))} [:maybe :boolean]] + [:customize-accounts {:optional true :default :default} [:enum :default :customize]] + + [:invoice/client {:optional true} [:maybe entity-id]] + [:invoice/date clj-date-schema] + [:invoice/due {:optional true} [:maybe clj-date-schema]] + [:invoice/scheduled-payment {:optional true} [:maybe clj-date-schema]] + [:invoice/vendor {:optional true} + [:and entity-id + [:fn {:error/message "Vendor is missing default expense account"} + check-vendor-default-account]]] + [:invoice/invoice-number {:optional true} [:string {:min 1 :decode/string strip}]] + [:invoice/total money] + [:invoice/expense-accounts + [:vector {:coerce? true} + [:and + [:map + [:invoice-expense-account/account [:and entity-id + [:fn {:error/message "Not an allowed account."} + check-allowance]]] + [:invoice-expense-account/location :string] + [:invoice-expense-account/amount :double]] + [:fn {:error/fn (fn [r x] (:type r)) + :error/path [:invoice-expense-account/location]} check-invoice-expense-account-location]]]]]) + +(defn wrap-schema [s] + [:and s + [:fn (fn [{:keys [:db/id :invoice/invoice-number :invoice/vendor :invoice/client] :as z}] + (if id + true + (and invoice-number vendor client)))]]) + + +(defn clientize-vendor [{:vendor/keys [terms-overrides automatically-paid-when-due default-account account-overrides] :as vendor} client-id] + (if (nil? vendor) + nil + (let [terms-override (->> terms-overrides + (filter (fn [to] + (= (->db-id (:vendor-terms-override/client to)) + client-id))) + (map :vendor-terms-override/terms) + first) + account (or (->> account-overrides + (filter (fn [to] + (= (->db-id (:vendor-account-override/client to)) + client-id))) + (map :vendor-account-override/account) + first) + default-account) + account (d-accounts/clientize account client-id) + + automatically-paid-when-due (->> automatically-paid-when-due + (filter (fn [to] + (= (->db-id to) + client-id))) + seq + boolean) + vendor (cond-> vendor + terms-override (assoc :vendor/terms terms-override) + true (assoc :vendor/automatically-paid-when-due automatically-paid-when-due + :vendor/default-account account) + true (dissoc :vendor/account-overrides :vendor/terms-overrides))] + vendor))) + +(defn account-prediction* [{:keys [multi-form-state]}] + (let [vendor (clientize-vendor (get-vendor (:invoice/vendor (:step-params multi-form-state))) + (->db-id (:invoice/client (:step-params multi-form-state)))) + account-name (:account/name (:vendor/default-account vendor)) + value (mm/get-mfs-field multi-form-state :customize-accounts)] + (when vendor + (com/radio-list {:name "step-params[customize-accounts]" + + :value (name value) + :options (filter identity + [(when account-name {:value (name :default) + :content (com/pill {:color :primary} account-name)}) + {:value (name :customize) + :content [:div "Customize accounts"]}])})))) + + +(defrecord BasicDetailsStep [linear-wizard] + mm/ModalWizardStep + (step-name [_] + "Basic Details") + (step-key [_] + :basic-details) + + (edit-path [_ _] + []) + + (step-schema [_] + (wrap-schema (mut/select-keys (mm/form-schema linear-wizard) #{:invoice/client :invoice/vendor :invoice/date :invoice/due :invoice/scheduled-payment :invoice/total :invoice/invoice-number :db/id :customize-due-and-scheduled? :customize-accounts}))) + + (render-step + [this {:keys [multi-form-state] :as request}] + (let [extant? (mm/get-mfs-field multi-form-state :db/id)] + (mm/default-render-step + linear-wizard this + :head [:div.p-2 (if extant? + "Edit invoice" + "New invoice")] + :body (mm/default-step-body + {} + [:div {:x-data (hx/json {:clientId (or (fc/field-value (:invoice/client fc/*current*)) + (:db/id (:client request))) + :vendorId (fc/field-value (:invoice/vendor fc/*current*)) + :date (-> (fc/field-value (:invoice/date fc/*current*)) + (atime/unparse-local atime/normal-date)) + :due (some-> (fc/field-value (:invoice/due fc/*current*)) + (atime/unparse-local atime/normal-date)) + :scheduledPayment (some-> (fc/field-value (:invoice/scheduled-payment fc/*current*)) + (atime/unparse-local atime/normal-date)) + :customizeDueAndScheduled (fc/field-value (:customize-due-and-scheduled? fc/*current*))})} + (fc/with-field :db/id + (when extant? + (com/hidden {:name (fc/field-name) + :value (fc/field-value)}))) + + + (fc/with-field :customize-due-and-scheduled? + (com/hidden {:name (fc/field-name) + :value (fc/field-value) + :x-model "customizeDueAndScheduled"})) + (fc/with-field :invoice/client + (if (or (:client request) extant?) + (com/hidden {:name (fc/field-name) + :value (or (mm/get-mfs-field multi-form-state :invoice/client) + (:db/id (:client request)))}) + (com/validated-field + {:label "Client" + :errors (fc/field-errors)} + [:div.w-96 + (com/typeahead {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :value (fc/field-value) + :content-fn (fn [c] (pull-attr (dc/db conn) :client/name c)) + :x-model "clientId"})]))) + (fc/with-field :invoice/vendor + (com/validated-field + {:label "Vendor" + :errors (fc/field-errors)} + [:div.w-96 + (com/typeahead {:name (fc/field-name) + :error? (fc/error?) + :disabled (boolean (-> request :multi-form-state :snapshot :db/id)) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :value (fc/field-value) + :content-fn (fn [c] (pull-attr (dc/db conn) :vendor/name c)) + :x-model "vendorId"})])) + + + [:div.flex.items-center.gap-2 + (fc/with-field :invoice/date + (com/validated-field + {:label "Date" + :errors (fc/field-errors)} + [:div {:class "w-24"} + (com/date-input {:value (some-> (fc/field-value) + (atime/unparse-local atime/normal-date)) + :name (fc/field-name) + :error? (fc/field-errors) + :x-model "date" + :placeholder "1/1/2024"})])) + [:div {:x-show "!customizeDueAndScheduled"} + (com/link {"@click" "customizeDueAndScheduled=true" + :x-show "!due && !scheduledPayment"} + "Add due / scheduled payment date") + (com/link {"@click" "customizeDueAndScheduled=true" + :x-show "due || scheduledPayment"} + "Change due / scheduled payment date")]] + (fc/with-field :invoice/due + (com/validated-field + (hx/alpine-appear {:label "Due (optional)" + :errors (fc/field-errors) + :x-show "customizeDueAndScheduled"}) + [:div {:class "w-24" + :hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/due-date) + :x-dispatch:changed "[clientId, vendorId, date]" + :hx-trigger "changed" + :hx-target "this" + :hx-swap "innerHTML"} + (com/date-input {:value (some-> (fc/field-value) + (atime/unparse-local atime/normal-date)) + :name (fc/field-name) + :x-model "due" + + :error? (fc/field-errors) + :placeholder "1/1/2024"})])) + (fc/with-field :invoice/scheduled-payment + (com/validated-field + (hx/alpine-appear {:label "Scheduled payment (optional)" + :errors (fc/field-errors) + :x-show "customizeDueAndScheduled"}) + [:div {:class "w-24"} + [:div {:class "w-24" + + :hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/scheduled-payment-date) + :x-dispatch:changed "[clientId, vendorId, due]" + :hx-trigger "changed" + :hx-target "this" + :hx-swap "innerHTML"} + (com/date-input {:value (some-> (fc/field-value) + (atime/unparse-local atime/normal-date)) + :name (fc/field-name) + :error? (fc/field-errors) + :placeholder "1/1/2024"})]])) + + (fc/with-field :invoice/invoice-number + (com/validated-field + {:label "Invoice Number" + :errors (fc/field-errors)} + [:div {:class "w-24"} + (com/text-input {:value (-> (fc/field-value)) + :disabled (boolean (-> request :multi-form-state :snapshot :db/id)) + :name (fc/field-name) + :error? (fc/field-errors) + :placeholder "HA-123"})])) + (fc/with-field :invoice/total + (com/validated-field + {:label "Total" + :errors (fc/field-errors)} + [:div {:class "w-16"} + (com/money-input {:value (-> (fc/field-value)) + :name (fc/field-name) + :class "w-24" + :error? (fc/field-errors) + :placeholder "212.44"})])) + + [:div#expense-account-prediction + (hx/alpine-appear + {:x-dispatch:bryce "[vendorId]" + :hx-trigger "bryce" + :hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/account-prediction) + :hx-target "this" + :hx-swap "innerHTML"}) + (account-prediction* request)]]) + + :footer + (mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate + :next-button (com/button {:color :primary :x-ref "next" :class "w-32" + :hx-put (bidi.bidi/path-for ssr-routes/only-routes + ::route/new-wizard-navigate)} "Save")) + :validation-route ::route/new-wizard-navigate))) + + mm/CustomNext + (custom-next-handler + [_ request] + (if (= (get-in request [:multi-form-state :step-params :customize-accounts]) + :customize) + (mm/navigate-handler {:request request + :to-step :accounts}) + + (html-response [:div] + :headers {"location" (bidi.bidi/path-for ssr-routes/only-routes ::route/new-invoice-submit)} + :status 308) + #_(mm/navigate-handler {:request request + :to-step :next-steps})))) + + +(defn- location-select* + [{:keys [name account-location client-locations value]}] + (let [options (into (cond account-location + [[account-location account-location]] + + (seq client-locations) + (into [["Shared" "Shared"]] + (for [cl client-locations] + [cl cl])) + :else + [["Shared" "Shared"]]))] + (com/select {:options options + :name name + :value (ffirst options) + :class "w-full"}))) + +(defn- account-typeahead* + [{:keys [name value client-id x-model]}] + [:div.flex.flex-col + (com/typeahead {:name name + :placeholder "Search..." + :url (hu/url (bidi/path-for ssr-routes/only-routes :account-search) + {:client-id client-id + :purpose "invoice"}) + :id name + :x-model x-model + :value value + :content-fn (fn [value] + (:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value) + client-id)))})]) + +(defn- invoice-expense-account-row* + [{:keys [value client-id]}] + (com/data-grid-row + (-> {:x-data (hx/json {:show (boolean (not (fc/field-value (:new? value)))) + :accountId (fc/field-value (:invoice-expense-account/account value))}) + :data-key "show" + :x-ref "p"} + hx/alpine-mount-then-appear) + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (fc/with-field :invoice-expense-account/account + (com/data-grid-cell + {} + (com/validated-field + {:errors (fc/field-errors)} + (account-typeahead* {:value (fc/field-value) + :client-id client-id + :name (fc/field-name) + :x-model "accountId"})))) + (fc/with-field :invoice-expense-account/location + (com/data-grid-cell + {} + (com/validated-field + {:errors (fc/field-errors) + :x-hx-val:account-id "accountId" + :hx-vals (hx/json {:name (fc/field-name) + :client-id client-id}) + :x-dispatch:changed "accountId" + :hx-trigger "changed" + :hx-get (bidi/path-for ssr-routes/only-routes ::route/location-select) + :hx-target "find *" + :hx-swap "outerHTML"} + (location-select* {:name (fc/field-name) + :account-location (:account/location (cond->> (:invoice-expense-account/account @value) + (nat-int? (:invoice-expense-account/account @value)) (dc/pull (dc/db conn) + '[:account/location]))) + :client-locations (pull-attr (dc/db conn) :client/locations client-id) + :value (fc/field-value)})))) + (fc/with-field :invoice-expense-account/amount + (com/data-grid-cell + {} + (com/validated-field + {:errors (fc/field-errors)} + (com/money-input {:name (fc/field-name) + :class "w-16 amount-field" + :value (fc/field-value)})))) + (com/data-grid-cell {:class "align-top"} + (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) + +(defn invoice-expense-account-total* [request] + (format "$%,.2f" (->> (-> request + :multi-form-state + :step-params + :invoice/expense-accounts) + (map (fnil :invoice-expense-account/amount 0.0)) + (filter number?) + (reduce + 0.0)))) + +(defn invoice-expense-account-total [request] + (html-response (invoice-expense-account-total* request))) + +(defrecord AccountsStep [linear-wizard] + mm/ModalWizardStep + (step-name [_] + "Expense Accounts") + (step-key [_] + :accounts) + + (edit-path [_ _] + []) + + (step-schema [_] + (mut/select-keys (mm/form-schema linear-wizard) #{:invoice/expense-accounts})) + + (render-step [this {{:keys [snapshot] :as multi-form-state} :multi-form-state :as request}] + (mm/default-render-step + linear-wizard this + :head [:div.p-2 "Invoice accounts "] + :body (mm/default-step-body + {} + [:div {} + (pull-attr (dc/db conn) :client/name (:invoice/client snapshot)) + (fc/with-field :invoice/expense-accounts + (com/validated-field + {:errors (fc/field-errors)} + (com/data-grid {:headers [(com/data-grid-header {} "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "$") + (com/data-grid-header {:class "w-16"})]} + (fc/cursor-map #(invoice-expense-account-row* {:value % + :client-id (:invoice/client snapshot)})) + + (com/data-grid-new-row {:colspan 4 + :hx-get (bidi/path-for ssr-routes/only-routes + ::route/new-wizard-new-account) + :row-offset 0 + :index (count (fc/field-value)) + :tr-params {:hx-vals (hx/json {:client-id (:invoice/client snapshot)})}} + "New account") + (com/data-grid-row {} + (com/data-grid-cell {}) + (com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TOTAL"]) + (com/data-grid-cell {:id "total" + :class "text-right" + :hx-trigger "change from:closest form target:.amount-field" + :hx-put (bidi.bidi/path-for ssr-routes/only-routes ::route/expense-account-total) + :hx-target "this" + :hx-swap "innerHTML"} + (invoice-expense-account-total* request)) + (com/data-grid-cell {})) + (com/data-grid-row {} + + (com/data-grid-cell {}) + (com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "INVOICE TOTAL"]) + (com/data-grid-cell {:class "text-right"} + (format "$%,.2f" (:invoice/total snapshot))) + (com/data-grid-cell {})))))]) + :footer + (mm/default-step-footer linear-wizard this :validation-route ::route/new-wizard-navigate + :next-button (com/button {:color :primary :x-ref "next" :class "w-32"} "Save")) + :validation-route ::route/new-wizard-navigate)) + mm/Initializable + (init-step-params + [_ current request] + (if (not (seq (:invoice/expense-accounts (:step-params current)))) + (assoc (:step-params current) :invoice/expense-accounts [{:db/id "123" + :invoice-expense-account/location "Shared" + :invoice-expense-account/account (:db/id (:vendor/default-account (clientize-vendor (get-vendor (->db-id (:invoice/vendor (:snapshot current)))) + (->db-id (:invoice/client (:snapshot current)))))) + :invoice-expense-account/amount (:invoice/total (:step-params current))}]) + (:step-params current)))) + +(defrecord NextSteps [linear-wizard] + mm/ModalWizardStep + (step-name [_] + "Next Steps") + (step-key [_] + :next-steps) + + (edit-path [_ _] + []) + + (step-schema [_] + (mut/select-keys (mm/form-schema linear-wizard) #{})) + + (render-step [this {{:keys [snapshot] :as multi-form-state} :multi-form-state :as request}] + + (mm/default-render-step + linear-wizard this + :head [:div.p-2 "Invoice accounts "] + :body (mm/default-step-body + {} + [:p.text-lg "Would you like to pay this invoice now?"] + + (com/navigation-button-list {} + (com/navigation-button (-> {:class "w-48" + :hx-get (hu/url (bidi.bidi/path-for ssr-routes/only-routes ::route/pay-wizard) + {:selected (:db/id snapshot) + :replace-modal true})} + hx/trigger-click-or-enter) "Pay now") + (com/navigation-button (-> {:class "w-48" + :hx-get (hu/url (bidi.bidi/path-for ssr-routes/only-routes ::route/new-wizard) + {:replace-modal true})} + hx/trigger-click-or-enter) "Add another") + (com/navigation-button {:class "w-48" :next-arrow? false + "@click" "$dispatch('modalclose') " + "@keyup.enter.stop" "$dispatch('modalclose')"} + "Close"))) + :footer + nil + :validation-route ::route/new-wizard-navigate))) + + +(defn assert-no-conflicting [{:invoice/keys [invoice-number client vendor]}] + (when (seq (d-invoices/find-conflicting {:invoice/invoice-number invoice-number + :invoice/vendor (->db-id vendor) + :invoice/client (->db-id client)})) + (form-validation-error (str "Invoice '" invoice-number "' already exists.")))) + + +(defn assert-invoice-amounts-add-up [{:keys [:invoice/expense-accounts :invoice/total]}] + (let [expense-account-total (reduce + 0 (map (fn [x] (:invoice-expense-account/amount x)) expense-accounts))] + (when-not (dollars= total expense-account-total) + (form-validation-error (str "Expense account total (" expense-account-total ") does not equal invoice total (" total ")"))))) + + +(defn- calculate-spread + "Helper function to calculate the amount to be assigned to each location" + [shared-amount total-locations] + (let [base-amount (int (/ shared-amount total-locations)) + remainder (- shared-amount (* base-amount total-locations))] + {:base-amount base-amount + :remainder remainder})) + + +(defn- spread-expense-account + "Spreads the expense account amount across the given locations" + [locations expense-account] + (if (= "Shared" (:invoice-expense-account/location expense-account)) + (let [{:keys [base-amount remainder]} (calculate-spread (:invoice-expense-account/amount expense-account) (count locations))] + (map-indexed (fn [idx _] + (assoc expense-account + :invoice-expense-account/amount (+ base-amount (if (< idx remainder) 1 0)) + :invoice-expense-account/location (nth locations idx))) + locations)) + [expense-account])) + +(defn $->cents [x] + (int + (let [result (* 100M (bigdec x))] + (.setScale result 0 java.math.BigDecimal/ROUND_HALF_UP)))) + +(defn cents->$ [x] + (double + (let [result (* 0.01M (bigdec x))] + (.setScale result 2 java.math.BigDecimal/ROUND_HALF_UP)))) + +(defn- apply-total-delta-to-account [invoice-total eas] + (when (seq eas) + (let [leftover (- invoice-total (reduce + 0 (map :invoice-expense-account/amount eas))) + leftover-beyond-a-single-cent? (or (< leftover -1) + (> leftover 1)) + leftover (if leftover-beyond-a-single-cent? + 0 + leftover) + [first-eas & rest] eas] + (cons + (update first-eas :invoice-expense-account/amount #(+ % leftover)) + rest)))) + + +(defn maybe-spread-locations + "Converts any expense account for a \"Shared\" location into a separate expense account for all valid locations for that client" + ([invoice] + (maybe-spread-locations invoice (pull-attr (dc/db conn) :client/locations (:invoice/client invoice)))) + ([invoice locations] + (update-in invoice + [:invoice/expense-accounts] + (fn [expense-accounts] + (->> expense-accounts + (map (fn [ea] (update ea :invoice-expense-account/amount $->cents))) + (mapcat (partial spread-expense-account locations)) + (apply-total-delta-to-account ($->cents (:invoice/total invoice))) + (map (fn [ea] (update ea :invoice-expense-account/amount cents->$)))))))) + + + +(defrecord NewWizard2 [_ current-step] + mm/LinearModalWizard + (hydrate-from-request + [this request] + this) + (navigate [this step-key] + (assoc this :current-step step-key)) + (get-current-step [this] + (if current-step + (mm/get-step this current-step) + (mm/get-step this :basic-details))) + (render-wizard [this {:keys [multi-form-state] :as request}] + (mm/default-render-wizard + this request + :form-params + (-> mm/default-form-props + (assoc :hx-post + (str (bidi/path-for ssr-routes/only-routes ::route/new-invoice-submit)))) + :render-timeline? false)) + (steps [_] + [:basic-details + :accounts + :next-steps]) + (get-step [this step-key] + (let [step-key-result (mc/parse mm/step-key-schema step-key) + [step-key-type step-key] step-key-result] + (get {:basic-details (->BasicDetailsStep this) + :accounts (->AccountsStep this) + :next-steps (->NextSteps this)} + step-key))) + (form-schema [_] + new-form-schema) + (submit [this {:keys [multi-form-state request-method identity] :as request}] + (let [invoice (:snapshot multi-form-state) + + _ (alog/peek invoice) + extant? (:db/id invoice) + client-id (->db-id (:invoice/client invoice)) + vendor-id (->db-id (:invoice/vendor invoice)) + paid-amount (if-let [outstanding-balance + (and extant? + (- + (pull-attr (dc/db conn) + :invoice/total + (:db/id invoice)) + (pull-attr (dc/db conn) + :invoice/outstanding-balance + (:db/id invoice))))] + outstanding-balance + 0.0) + outstanding-balance (- (or + (:invoice/total (:step-params multi-form-state)) + (:invoice/total (:snapshot multi-form-state))) + paid-amount) + + transaction [:upsert-invoice (-> multi-form-state + :snapshot + (assoc :db/id (or (:db/id invoice) "invoice")) + (dissoc :customize-due-and-scheduled? :invoice/journal-entry :invoice/payments :customize-accounts) + (assoc :invoice/expense-accounts (if (= :customize (:customize-accounts invoice)) + (-> multi-form-state :step-params :invoice/expense-accounts) + [{:db/id "123" + :invoice-expense-account/location "Shared" + :invoice-expense-account/account (:db/id (:vendor/default-account (clientize-vendor (get-vendor vendor-id) + client-id))) + :invoice-expense-account/amount (or (:invoice/total (:step-params multi-form-state)) + (:invoice/total (:snapshot multi-form-state)))}])) + (assoc + :invoice/outstanding-balance outstanding-balance + :invoice/import-status :import-status/imported + :invoice/status (if (dollars= 0.0 outstanding-balance) + :invoice-status/paid + :invoice-status/unpaid)) + (maybe-spread-locations) + (update :invoice/date coerce/to-date) + (update :invoice/due coerce/to-date) + (update :invoice/scheduled-payment coerce/to-date))]] + (assert-invoice-amounts-add-up (second transaction)) + (when-not extant? + (assert-no-conflicting invoice)) + (exception->4xx #(assert-can-see-client (:identity request) client-id)) + + (exception->4xx #(assert-not-locked client-id (:invoice/date invoice))) + (let [transaction-result (audit-transact [transaction] (:identity request))] + (solr/touch-with-ledger (get-in transaction-result [:tempids "invoice"])) + (if extant? + + (html-response + (@(resolve 'auto-ap.ssr.invoices/row*) identity (dc/pull (dc/db conn) default-read (:db/id invoice)) {:flash? true + :request request}) + :headers (cond-> {"hx-trigger" "modalclose" + "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id invoice)) + "hx-reswap" "outerHTML"})) + + (assoc-in (mm/navigate-handler {:request (assoc-in request [:multi-form-state :snapshot :db/id] (get-in transaction-result [:tempids "invoice"])) + :to-step :next-steps}) + [:headers "hx-trigger"] "invalidated")))))) + +(def new-wizard (->NewWizard2 nil nil)) + + +(defn initial-new-wizard-state [request] + (mm/->MultiStepFormState {:invoice/date (time/now) + :customize-accounts :default} + [] + {:invoice/date (time/now) + :customize-accounts :default})) + + + + +(defn initial-edit-wizard-state [request] + (let [entity (dc/pull (dc/db conn) default-read (:db/id (:route-params request))) + entity (select-keys entity (mut/keys new-form-schema))] + + (mm/->MultiStepFormState (assoc entity + :customize-accounts :customize) + [] + (assoc entity + :customize-accounts :customize)))) + +(defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}] + (html-response (location-select* {:name name + :value value + :account-location (some->> account-id + (pull-attr (dc/db conn) :account/location)) + :client-locations (some->> client-id + (pull-attr (dc/db conn) :client/locations))}))) + + +(defn due-date [{:keys [multi-form-state]}] + (let [vendor (clientize-vendor (get-vendor (:invoice/vendor (:step-params multi-form-state))) + (->db-id (:invoice/client (:step-params multi-form-state)))) + good-date + (or (when (and (:invoice/date (:step-params multi-form-state)) + (-> vendor :vendor/terms)) + (time/plus (:invoice/date (:step-params multi-form-state)) + (time/days (-> vendor :vendor/terms)))) + (:invoice/due (:step-params multi-form-state)))] + + (html-response + (com/date-input {:value (some-> good-date + (atime/unparse-local atime/normal-date)) + :name "step-params[invoice/due]" + :x-init (format "due='%s'" (some-> good-date + (atime/unparse-local atime/normal-date))) + :x-model "due" + :error? false + :placeholder "1/1/2024"})))) + +(defn scheduled-payment-date [{:keys [multi-form-state]}] + (let [vendor (clientize-vendor (get-vendor (:invoice/vendor (:step-params multi-form-state))) + (->db-id (:invoice/client (:step-params multi-form-state)))) + good-date + (when (and (:invoice/due (:step-params multi-form-state)) + (:vendor/automatically-paid-when-due vendor)) + + (:invoice/due (:step-params multi-form-state)))] + + (html-response + (com/date-input {:value (some-> good-date + (atime/unparse-local atime/normal-date)) + :name "step-params[invoice/scheduled-payment]" + :error? false + :placeholder "1/1/2024"})))) + + +(defn account-prediction [{:keys [multi-form-state form-errors] :as request}] + (html-response + (account-prediction* request))) + +(def key->handler + (apply-middleware-to-all-handlers + {::route/new-wizard (-> mm/open-wizard-handler + (mm/wrap-wizard new-wizard) + (mm/wrap-init-multi-form-state initial-new-wizard-state)) + ::route/edit-wizard (-> mm/open-wizard-handler + (mm/wrap-wizard new-wizard) + (mm/wrap-init-multi-form-state initial-edit-wizard-state) + (wrap-schema-enforce :route-schema [:map [:db/id entity-id]])) + ::route/due-date (-> due-date + (mm/wrap-wizard new-wizard) + (mm/wrap-decode-multi-form-state) + (wrap-nested-form-params)) + ::route/account-prediction (-> account-prediction + (mm/wrap-wizard new-wizard) + (mm/wrap-decode-multi-form-state) + (wrap-nested-form-params)) + ::route/scheduled-payment-date (-> scheduled-payment-date + (mm/wrap-wizard new-wizard) + (mm/wrap-decode-multi-form-state) + (wrap-nested-form-params)) + ::route/expense-account-total (-> invoice-expense-account-total + (mm/wrap-wizard new-wizard) + (mm/wrap-decode-multi-form-state)) + ::route/location-select (-> location-select + (wrap-schema-enforce :query-schema [:map + [:name :string] + [:client-id {:optional true} + [:maybe entity-id]] + [:account-id {:optional true} + [:maybe entity-id]]])) + + ::route/new-invoice-submit (-> mm/submit-handler + (mm/wrap-wizard new-wizard) + (mm/wrap-decode-multi-form-state)) + ::route/new-wizard-navigate (-> mm/next-handler + (mm/wrap-wizard new-wizard) + (mm/wrap-decode-multi-form-state)) + ::route/new-wizard-new-account (-> + (add-new-entity-handler [:step-params :invoice/expense-accounts] + (fn render [cursor request] + (invoice-expense-account-row* + {:value cursor + :client-id (:client-id (:query-params request))})) + (fn build-new-row [base _] + (assoc base :invoice-expense-account/location "Shared"))) + (wrap-schema-enforce :query-schema [:map + [:client-id {:optional true} + [:maybe entity-id]]]))} + (fn [h] + (-> h + (wrap-client-redirect-unauthenticated))))) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/invoices.clj b/src/clj/auto_ap/ssr/invoices.clj new file mode 100644 index 00000000..dd0087cd --- /dev/null +++ b/src/clj/auto_ap/ssr/invoices.clj @@ -0,0 +1,1222 @@ +(ns auto-ap.ssr.invoices + (:require [auto-ap.client-routes :as client-routes] + [auto-ap.datomic + :refer [add-sorter-fields apply-pagination apply-sort-3 + audit-transact conn merge-query observable-query + pull-many]] + [auto-ap.datomic.accounts :as d-accounts] + [auto-ap.datomic.bank-accounts :as d-bank-accounts] + [auto-ap.datomic.invoices :as d-invoices] + [auto-ap.graphql.checks :as gq-checks :refer [base-payment + invoice-payments + print-checks-internal + validate-belonging]] + [auto-ap.graphql.utils :refer [assert-can-see-client + assert-not-locked exception->4xx + exception->notification + extract-client-ids notify-if-locked]] + [auto-ap.logging :as alog] + [auto-ap.permissions :refer [can?]] + [auto-ap.routes.invoice :as route] + [auto-ap.routes.payments :as payment-route] + [auto-ap.routes.utils + :refer [wrap-admin wrap-client-redirect-unauthenticated]] + [auto-ap.solr :as solr] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.link-dropdown :refer [link-dropdown]] + [auto-ap.ssr.components.multi-modal :as mm] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.hiccup-helper :as hh] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.invoice.common :refer [default-read]] + [auto-ap.ssr.invoice.new-invoice-wizard :as new-invoice-wizard] + [auto-ap.ssr.pos.common :refer [date-range-field*]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [apply-middleware-to-all-handlers clj-date-schema + dissoc-nil-transformer entity-id html-response + main-transformer modal-response money ref->enum-schema + round-money strip wrap-entity wrap-implied-route-param + wrap-merge-prior-hx wrap-schema-enforce form-validation-error assert-schema]] + [auto-ap.time :as atime] + [auto-ap.utils :refer [by dollars=]] + [bidi.bidi :as bidi] + [clj-time.coerce :as coerce] + [clj-time.core :as time] + [clojure.string :as str] + [datomic.api :as dc] + [hiccup.util :as hu] + [malli.core :as mc] + [malli.transform :as mt] + [malli.util :as mut])) + + +(defn exact-match-id* [request] + (if (nat-int? (:exact-match-id (:query-params request))) + [:div {:x-data (hx/json {:exact_match (:exact-match-id (:query-params request))}) :id "exact-match-id-tag"} + (com/hidden {:name "exact-match-id" + "x-model" "exact_match"}) + (com/pill {:color :primary} + [:span.inline-flex.space-x-2.items-center + [:div "exact match"] + [:div.w-3.h-3 + (com/link {"@click" "exact_match=null; $nextTick(() => $dispatch('change'))"} + svg/x)]])] + [:div {:id "exact-match-id-tag"}])) + +(defn filters [request] + [:form#invoice-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" + "hx-get" (bidi/path-for ssr-routes/only-routes + ::route/table) + "hx-target" "#entity-table" + "hx-indicator" "#entity-table"} + + (com/hidden {:name "status" + :value (some-> (:status (:query-params request)) name)}) + [:fieldset.space-y-6 + (com/field {:label "Vendor"} + (com/typeahead {:name "vendor" + :id "vendor" + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :value (:vendor (:query-params request)) + :value-fn :db/id + :content-fn :vendor/name})) + (date-range-field* request) + (com/field {:label "Check #"} + (com/text-input {:name "check-number" + :id "check-number" + :class "hot-filter" + :value (:check-number (:query-params request)) + :placeholder "10001" + :size :small})) + (com/field {:label "Invoice #"} + (com/text-input {:name "invoice-number" + :id "invoice-number" + :class "hot-filter" + :value (:invoice-number (:query-params request)) + :placeholder "10001" + :size :small})) + + (com/field {:label "Amount"} + [:div.flex.space-x-4.items-baseline + (com/money-input {:name "amount-gte" + :id "amount-gte" + :hx-preserve "true" + :class "hot-filter w-20" + :value (:amount-gte (:query-params request)) + :placeholder "0.01" + :size :small}) + [:div.align-baseline + "to"] + (com/money-input {:name "amount-lte" + :hx-preserve "true" + :id "amount-lte" + :class "hot-filter w-20" + :value (:amount-lte (:query-params request)) + :placeholder "9999.34" + :size :small})]) + (exact-match-id* request)]]) + + + + +(defn fetch-ids [db {:keys [query-params route-params] :as request}] + (let [valid-clients (extract-client-ids (:clients request) + (:client-id request) + (when (:client-code request) + [:client/code (:client-code request)])) + query + (if (:exact-match-id query-params) + {:query {:find '[?e] + :in '[$ ?e [?c ...]] + :where '[[?e :invoice/client ?c]]} + :args [db + (:exact-match-id query-params) + valid-clients]} + (cond-> {:query {:find [] + :in '[$ [?clients ?start ?end]] + :where '[[(iol-ion.query/scan-invoices $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]]} + :args [db + [valid-clients + (some-> (:start-date query-params) coerce/to-date) + (some-> (:end-date query-params) coerce/to-date)]]} + + + (:client-id query-params) + (merge-query {:query {:in ['?client-id] + :where ['[?e :invoice/client ?client-id]]} + :args [(:client-id query-params)]}) + + (:client-code query-params) + (merge-query {:query {:in ['?client-code] + :where ['[?e :invoice/client ?client-id] + '[?client-id :client/code ?client-code]]} + :args [(:client-code query-params)]}) + + + (:start (:due-range query-params)) (merge-query {:query {:in '[?start-due] + :where ['[?e :invoice/due ?due] + '[(>= ?due ?start-due)]]} + :args [(coerce/to-date (:start (:due-range query-params)))]}) + + (:end (:due-range query-params)) (merge-query {:query {:in '[?end-due] + :where ['[?e :invoice/due ?due] + '[(<= ?due ?end-due)]]} + :args [(coerce/to-date (:end (:due-range query-params)))]}) + + + (:import-status query-params) + (merge-query {:query {:in ['?import-status] + :where ['[?e :invoice/import-status ?import-status]]} + :args [(:import-status query-params)]}) + (:status route-params) + (merge-query {:query {:in ['?status] + :where ['[?e :invoice/status ?status]]} + :args [(:status route-params)]}) + (:vendor query-params) + (merge-query {:query {:in ['?vendor-id] + :where ['[?e :invoice/vendor ?vendor-id]]} + :args [(:db/id (:vendor query-params))]}) + + (:account-id query-params) + (merge-query {:query {:in ['?account-id] + :where ['[?e :invoice/expense-accounts ?iea ?] + '[?iea :invoice-expense-account/account ?account-id]]} + :args [(:account-id query-params)]}) + + (:amount-gte query-params) + (merge-query {:query {:in ['?amount-gte] + :where ['[?e :invoice/total ?total-filter] + '[(>= ?total-filter ?amount-gte)]]} + :args [(:amount-gte query-params)]}) + + (:amount-lte query-params) + (merge-query {:query {:in ['?amount-lte] + :where ['[?e :invoice/total ?total-filter] + '[(<= ?total-filter ?amount-lte)]]} + :args [(:amount-lte query-params)]}) + + (not-empty (:invoice-number query-params)) + (merge-query {:query {:in ['?invoice-number-like] + :where ['[?e :invoice/invoice-number ?invoice-number] + '[(.contains ^String ?invoice-number ?invoice-number-like)]]} + :args [(:invoice-number query-params)]}) + + (:scheduled-payments query-params) + (merge-query {:query {:in [] + :where ['[?e :invoice/scheduled-payment]]} + :args []}) + + (:unresolved query-params) + (merge-query {:query {:in [] + :where ['(or-join [?e] + (not [?e :invoice/expense-accounts]) + (and [?e :invoice/expense-accounts ?ea] + (not [?ea :invoice-expense-account/account])))]} + :args []}) + + (seq (:location query-params)) + (merge-query {:query {:in ['?location] + :where ['[?e :invoice/expense-accounts ?eas] + '[?eas :invoice-expense-account/location ?location]]} + :args [(:location query-params)]}) + + (:sort query-params) (add-sorter-fields {"client" ['[?e :invoice/client ?c] + '[?c :client/name ?sort-client]] + "vendor" ['[?e :invoice/vendor ?v] + '[?v :vendor/name ?sort-vendor]] + "description-original" ['[?e :transaction/description-original ?sort-description-original]] + "location" ['[?e :invoice/expense-accounts ?iea] + '[?iea :invoice-expense-account/location ?sort-location]] + "date" ['[?e :invoice/date ?sort-date]] + "due" ['[(get-else $ ?e :invoice/due #inst "2050-01-01") ?sort-due]] + "invoice-number" ['[?e :invoice/invoice-number ?sort-invoice-number]] + "total" ['[?e :invoice/total ?sort-total]] + "outstanding-balance" ['[?e :invoice/outstanding-balance ?sort-outstanding-balance]]} + query-params) + true + (merge-query {:query {:find ['?sort-default '?e]}})))] + (->> (observable-query query) + (apply-sort-3 (assoc query-params :default-asc? false)) + (apply-pagination query-params)))) + + +(defn hydrate-results [ids db _] + (let [results (->> (pull-many db default-read ids) + (group-by :db/id)) + refunds (->> ids + (map results) + (map first))] + refunds)) + +(defn fetch-page [request] + (let [db (dc/db conn) + {ids-to-retrieve :ids matching-count :count} (fetch-ids db request)] + + [(->> (hydrate-results ids-to-retrieve db request)) + matching-count])) + +(def query-schema (mc/schema + [:maybe [:map {:date-range [:date-range :start-date :end-date]} + [:sort {:optional true} [:maybe [:any]]] + [:per-page {:optional true :default 25} [:maybe :int]] + [:start {:optional true :default 0} [:maybe :int]] + [:amount-gte {:optional true} [:maybe :double]] + [:amount-lte {:optional true} [:maybe :double]] + [:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]] + [:check-number {:optional true} [:maybe [:string {:decode/string strip}]]] + [:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]] + [:status {:optional true} [:maybe (ref->enum-schema "invoice-status")]] + [:exact-match-id {:optional true} [:maybe entity-id]] + [:all-selected {:optional true :default nil} [:maybe :boolean]] + [:selected {:optional true :default nil} [:maybe [:vector {:coerce? true} + entity-id]]] + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]]]])) + +(comment + (mc/decode query-schema + {:start " "} + main-transformer)) + +(defn selected->ids [request params] + (let [all-selected (:all-selected params) + selected (:selected params) + ids (cond + all-selected + (:ids (fetch-ids (dc/db conn) (-> request + (assoc :query-params params) + (assoc-in [:query-params :start] 0) + (assoc-in [:query-params :per-page] 250)))) + + + :else + selected)] + ids)) + +(defn pay-button* [params] + (let [ids (:ids params) + selected-client-count (if (seq ids) + (ffirst + (dc/q '[:find (count ?c) + :in $ [?i ...] + :where [?i :invoice/client ?c]] + (dc/db conn) + ids)) + + 0) + vendor-totals (if (seq ids) + (->> + (dc/q '[:find ?i ?v ?ob + :in $ [?i ...] + :where [?i :invoice/vendor ?v] + [?i :invoice/outstanding-balance ?ob]] + (dc/db conn) + ids) + (reduce (fn [acc [_ v ob]] + (update acc v (fnil + 0) ob)) + {}) + (vals))) + all-credits-or-debits (or (every? #(<= % 0.0) vendor-totals) + (every? #(>= % 0.0) vendor-totals))] + + + [:div {:hx-target "this" + :hx-get (bidi/path-for ssr-routes/only-routes + ::route/pay-wizard) + :hx-trigger "click from:#pay-button" + :x-data (hx/json {:popper nil + :hovering false}) + "x-init" "popper = Popper.createPopper($refs.button, $refs.tooltip, {placement: 'bottom', strategy: 'fixed', modifiers: [{name: 'preventOverflow'}, {name: 'offset', options: {offset: [0, 10]}}]});"} + (com/button {:color :primary + :id "pay-button" + :disabled (or (= (count (:ids params)) 0) + (not= 1 selected-client-count) + (not all-credits-or-debits)) + "x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})" + "hx-include" "#invoice-filters" + :hx-get (bidi/path-for ssr-routes/only-routes ::route/pay-button) + :hx-swap "outerHTML" + :hx-trigger "selectedChanged from:body, htmx:afterSwap from:#entity-table" + "@mouseover" "hovering=true; $nextTick(() => popper.update())" + "@mouseout" "hovering=false;" + :x-ref "button" + :minimal-loading? true + :class "relative"} + (if (> (count (:ids params)) 0) + + (str "Pay " (count (:ids params)) " invoices") + "Pay") + (when (or (= 0 (count ids)) + (> selected-client-count 1)) + (com/badge {} "!"))) + [:div (hx/alpine-appear {:x-ref "tooltip" + + :x-show "hovering" + :class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4"}) + (cond + (not all-credits-or-debits) + [:div "All vendor totals must be either positive or negative."] + (= 0 (count ids)) + [:div "Please select some invoices to pay"] + (> selected-client-count 1) + [:div "Can only pay for one client at a time"] + :else + [:div "Click to choose a bank account"])]])) + + +(defn pay-button [request] + (html-response + (pay-button* {:ids (selected->ids request + (:query-params request))}))) + + + +;; TODO test as a real user +(def grid-page + (helper/build {:id "entity-table" + :nav com/main-aside-nav + :check-boxes? true + :page-specific-nav filters + :fetch-page fetch-page + :oob-render + (fn [request] + [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true) + (assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)]) + :query-schema query-schema + :parse-query-params (fn [p] + (mc/decode query-schema p main-transformer)) + :action-buttons (fn [request] + [(when (can? (:identity request) {:subject :invoice :activity :bulk-delete}) + (com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/bulk-delete)) + "x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})" + "hx-include" "#invoice-filters" + :color :red} + "Void selected")) + (when (can? (:identity request) {:subject :invoice :activity :pay}) + (pay-button* {:ids (selected->ids request + (:query-params request))})) + (when (can? (:identity request) {:subject :invoice :activity :create}) + (com/button {:hx-get (bidi/path-for ssr-routes/only-routes ::route/new-wizard)} + "New invoice"))]) + :row-buttons (fn [request entity] + [(when (and (= :invoice-status/unpaid (:invoice/status entity)) + (can? (:identity request) {:subject :invoice :activity :delete})) + (com/icon-button {:hx-delete (bidi/path-for ssr-routes/only-routes + ::route/delete + :db/id (:db/id entity)) + :hx-confirm "Are you sure you want to void this invoice?"} + svg/trash)) + (when (and (can? (:identity request) {:subject :invoice :activity :edit}) + (#{:invoice-status/unpaid :invoice-status/paid} (:invoice/status entity))) + (com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes + ::route/edit-wizard + :db/id (:db/id entity))} + svg/pencil)) + (when (and (can? (:identity request) {:subject :invoice :activity :edit}) + (#{:invoice-status/voided} (:invoice/status entity))) + (com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes + ::route/unvoid + :db/id (:db/id entity))} + svg/undo))]) + + :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)} + "Invoices"]] + :title (fn [r] + (str + (some-> r :route-params :status name str/capitalize (str " ")) + "Invoices")) + :entity-name "invoices" + :route ::route/table + :headers [{:key "client" + :name "Client" + :sort-key "client" + :hide? (fn [args] + (= (count (:clients args)) 1)) + :render #(-> % :invoice/client :client/name)} + {:key "vendor" + :name "Vendor" + :sort-key "vendor" + :render #(-> % :invoice/vendor :vendor/name)} + {:key "invoice-number" + :name "Invoice number" + :sort-key "invoice-number" + :render :invoice/invoice-number} + {:key "date" + :sort-key "date" + :name "Date" + :show-starting "lg" + :render (fn [{:invoice/keys [date]}] + (some-> date (atime/unparse-local atime/normal-date)))} + {:key "status" + :name "Status" + :render (fn [{:invoice/keys [status]}] + (condp = status + :invoice-status/paid + (com/pill {:color :primary} "Paid") + + :invoice-status/unpaid + (com/pill {:color :secondary} "Unpaid") + :invoice-status/voided + (com/pill {:color :red} "Voided") + nil + ""))} + {:key "accounts" + :name "Account" + :show-starting "lg" + :render (fn [{:invoice/keys [expense-accounts client]}] + [:div.flex.flex-col.gap-y-2 + (when (first expense-accounts) + [:div.flex-initial + (com/pill {:color :primary} + (:account/name + (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read (:db/id (:invoice-expense-account/account (first expense-accounts)))) + + (:db/id client))))]) + (when (> (count expense-accounts) 1) + [:div.flex-initial + (com/pill {:color :secondary} + "+ " (dec (count expense-accounts)) " more")])])} + + {:key "outstanding" + :name "Outstanding" + :sort-key "outstanding-balance" + :class "text-right" + :render (fn [{:invoice/keys [outstanding-balance total]}] + [:div + (some->> outstanding-balance (format "$%,.2f")) + (when-not (dollars= outstanding-balance total) + [:div.text-xs.text-gray-400 (format "of $%,.2f" total)])])} + {:key "links" + :name "Links" + :show-starting "lg" + :class "w-8" + :render (fn [i] + (link-dropdown + (concat (->> i + :invoice/payments + (filter (fn [p] + (not= :payment-status/voided + (:payment/status p)))) + (mapcat (fn [p] + (cond-> [{:link (hu/url (bidi/path-for ssr-routes/only-routes + ::payment-route/all-page) + {:exact-match-id (:db/id p)}) + :content (str (format "$%,.2f" (:payment/amount p)) + (some-> (:payment/date p) coerce/to-date-time (atime/unparse-local atime/normal-date) (#(str " payment on " %))))}] + (:payment/transaction p) (conj {:link (hu/url (bidi/path-for client-routes/routes :transactions) + {:exact-match-id (:db/id (first (:payment/transaction p)))}) + :color :secondary + :content "Transaction"}))))) + (when (:invoice/journal-entry i) + [{:link (hu/url (bidi/path-for client-routes/routes :ledger) + {:exact-match-id (:db/id (first (:invoice/journal-entry i)))}) + :color :yellow + :content "Ledger entry"}]) + (when (:invoice/source-url i) + [{:link (:invoice/source-url i) + :color :secondary + :content "File"}]))))}]})) + +(def row* (partial helper/row* grid-page)) + +(defn unvoid-invoice [{:as request :keys [identity entity]}] + (let [invoice entity + id (:db/id entity) + _ (assert-can-see-client identity (:db/id (:invoice/client invoice))) + _ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) + history (dc/history (dc/db conn)) + txs (dc/q {:find ['?tx '?e '?original-status '?original-outstanding '?total '?ea '?ea-amount] + :where ['[?e :invoice/status :invoice-status/voided ?tx true] + '[?e :invoice/status ?original-status ?tx false] + '[?e :invoice/outstanding-balance ?original-outstanding ?tx false] + '[?e :invoice/total ?total ?tx false] + '[?ea :invoice-expense-account/amount ?ea-amount ?tx false]] + :in ['$ '?e]} + history id) + [last-transaction] (->> txs (sort-by first) (last)) + tx [[:upsert-invoice + (->> txs + (filter (fn [[tx]] (= tx last-transaction))) + (reduce (fn [new-transaction [_ entity original-status original-outstanding total expense-account expense-account-amount]] + (-> new-transaction + (assoc :db/id entity + :invoice/total total + :invoice/status original-status + :invoice/outstanding-balance original-outstanding) + (update :invoice/expense-accounts (fnil conj []) {:db/id expense-account :invoice-expense-account/amount expense-account-amount}))) + {}))]] + _ (audit-transact tx identity)] + (alog/info ::unvoiding-invoice :transaction :tx) + (html-response + (row* identity (dc/pull (dc/db conn) default-read id) {:flash? true + :request request}) + :headers (cond-> {"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" id) + "hx-reswap" "outerHTML"})))) + +(defn delete [{invoice :entity :as request identity :identity}] + (exception->notification + #(when-not (= :invoice-status/unpaid (:invoice/status invoice)) + (throw (ex-info "Cannot void an invoice if it is paid. First void the payment." {})))) + + (when (->> invoice :invoice/payments + (filter (fn [p] + (not= :payment-status/voided + (:payment/status p)))) + seq) + (throw (ex-info "This invoice has linked payments. Void the payments first." {:type :notification}))) + + (exception->notification + #(assert-can-see-client identity (:db/id (:invoice/client invoice)))) + (notify-if-locked (:db/id (:invoice/client invoice)) + (:invoice/date invoice)) + (audit-transact [[:upsert-invoice {:db/id (:db/id invoice) + :invoice/total 0.0 + :invoice/outstanding-balance 0.0 + :invoice/status :invoice-status/voided + :invoice/expense-accounts (map (fn [ea] {:db/id (:db/id ea) + :invoice-expense-account/amount 0.0}) + (:invoice/expense-accounts invoice))}]] + identity) + + (html-response (row* (:identity request) (dc/pull (dc/db conn) default-read (:db/id invoice)) + {:class "live-removed"}) + :headers {"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id invoice))})) + +(defn bulk-delete-dialog [request] + (let [all-selected (:all-selected (:query-params request)) + selected (:selected (:query-params request)) + ids (cond + all-selected + (:ids (fetch-ids (dc/db conn) (-> request + (assoc-in [:query-params :start] 0) + (assoc-in [:query-params :per-page] 250)))) + :else + selected)] + (modal-response + (com/modal {} + (com/modal-card-advanced + {} + + (com/modal-body {} + [:div.flex.flex-col.mt-4.space-y-4.items-center + [:div.w-24.h-24.bg-red-50.rounded-full.p-4.text-red-300 + + svg/alert] + [:div "You are about to void " (count ids) " invoices. Are you sure you want to do this?"]]) + (com/modal-footer {} [:div.flex.justify-end (com/button {:color :primary + :hx-vals (hx/json (mc/encode + query-schema + (dissoc (:query-params request) :sort) + (mt/transformer + main-transformer + dissoc-nil-transformer + mt/strip-extra-keys-transformer))) + :hx-delete (hu/url (bidi/path-for ssr-routes/only-routes + ::route/bulk-delete-confirm))} + "Void invoices")]))) + :headers (-> {} + (assoc "hx-retarget" ".modal-stack") + (assoc "hx-reswap" "beforeend"))))) + +(defn void-invoices-internal [all-ids id] + (let [all-ids (->> all-ids + (dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}]) + :in $ [?i ...] + :where (not [_ :invoice-payment/invoice ?i]) + [?i :invoice/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?i :invoice/date ?d] + [(>= ?d ?lu)]] + (dc/db conn))) + voidable-cash-payments (->> (dc/q '[:find ?p + :in $ [?i ...] + :where [?ip :invoice-payment/invoice ?i] + [?ip :invoice-payment/payment ?p] + [?p :payment/type :payment-type/cash] + [?i :invoice/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?i :invoice/date ?d] + [(>= ?d ?lu)]] + (dc/db conn) + (map :db/id all-ids)) + (map first))] + (alog/info ::void-payments :count (count voidable-cash-payments)) + (gq-checks/void-payments-internal voidable-cash-payments id) + + (alog/info ::voiding-invoices :count (count all-ids)) + (audit-transact + (->> all-ids + (map + (fn [[i]] + [:upsert-invoice {:db/id (:db/id i) + :invoice/total 0.0 + :invoice/outstanding-balance 0.0 + :invoice/status :invoice-status/voided + :invoice/expense-accounts (mapv + (fn [iea] + {:db/id (:db/id iea) + :invoice-expense-account/amount 0.0}) + (:invoice/expense-accounts i))}]))) + id) + (count all-ids))) + + + +(defn bulk-delete-dialog-confirm [request] + (alog/peek (:form-params request)) + (let [ids (selected->ids request (:form-params request)) + updated-count (void-invoices-internal ids (:identity request))] + + (html-response [:div] + :headers {"hx-trigger" (hx/json {:modalclose "" + :notification (format "Successfully voided %d of %d invoices." + updated-count + (count ids))})}))) + +;; TODO +;; Allow for paying balances from set of invoices for one vendor + +(defn does-amount-exceed-outstanding? [amount outstanding-balance] + (let [outstanding-balance (round-money outstanding-balance) + amount (round-money amount)] + (or (and (> outstanding-balance 0) + (> amount outstanding-balance)) + (and (> outstanding-balance 0) + (<= amount 0)) + (and (< outstanding-balance 0) + (< amount outstanding-balance)) + (and (< outstanding-balance 0) + (>= amount 0)) + (and (= outstanding-balance 0.0) + (not= amount 0.0))))) + +(def payment-form-schema + (mc/schema + [:map + [:client entity-id] + [:invoices [:and + [:vector {:coerce? true} + [:map + [:invoice-id entity-id] + [:amount money]]] + [:fn {:error/message "All payments must not exceed their outstanding balance."} + (fn [invoices] + (let [outstanding-balances (->> (dc/q '[:find ?i ?ob + :in $ [?i ...] + :where [?i :invoice/outstanding-balance ?ob]] + (dc/db conn) + (map :invoice-id invoices)) + (into {}))] + (every? (fn [%] + (println "TEST" (:amount %) (outstanding-balances (:invoice-id %))) + (not (does-amount-exceed-outstanding? (:amount %) (outstanding-balances (:invoice-id %))))) + invoices)))]]] + [:has-warning? :boolean] + [:bank-account entity-id] + [:check-number {:optional true} :int] + [:handwritten-date {:optional true} [:maybe clj-date-schema]] + [:mode [:enum :simple :advanced]] + [:method [:enum :debit :print-check :cash :handwrite-check :credit]]])) + +(defn bank-account-card-base [{:keys [bg-color text-color icon bank-account can-handwrite? credit-only?]}] + [:div {:class "w-[30em]"} + (com/card {:class "w-full"} + [:div.flex.items-stretch {:x-data (hx/json {:chosen false + :popper nil}) + "x-init" "popper = Popper.createPopper($refs.button, $refs.tooltip, {placement: 'bottom', strategy: 'fixed', modifiers: [{name: 'preventOverflow'}, {name: 'offset', options: {offset: [0, 10]}}]});"} + (com/hidden {:name "item" + :value (:db/id bank-account)}) + [:div.grow-0.flex.flex-col.justify-center + [:div.p-1.m-2.rounded-full + {:class + bg-color} + [:div {:class + (hh/add-class "p-1.5 w-8 h-8" text-color)} + icon]]] + [:div.flex.flex-col.grow.m-2 + [:div.font-medium.text-gray-700 (:bank-account/name bank-account)] + [:div.font-light.text-gray-600 (:bank-account/bank-name bank-account)]] + [:div.grow-0.m-2.self-center + (if credit-only? + (com/button {:color :primary + :minimal-loading? true + :hx-vals (hx/json {"step-params[bank-account]" (:db/id bank-account) + "step-params[method]" "credit"}) + :hx-put (hu/url (bidi/path-for ssr-routes/only-routes ::route/pay-wizard-navigate) + {:from (mm/encode-step-key :choose-method) + :to (mm/encode-step-key :payment-details)})} + "Credit") + (com/button {:x-ref "button" + "@click.prevent.capture" "chosen=true; $nextTick(() => popper.update())"} + "Pay")) + [:div.flex.flex-col.gap-2 (hx/alpine-appear {:x-show "chosen" :x-ref "tooltip" + :data-key "vis" + :class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4" + "@click.outside" "chosen=false"}) + (when (= :bank-account-type/check + (:bank-account/type bank-account)) + (com/button {:color :primary + :minimal-loading? true + :hx-vals (hx/json {"step-params[bank-account]" (:db/id bank-account) + "step-params[method]" "print-check"}) + :hx-put (hu/url (bidi/path-for ssr-routes/only-routes ::route/pay-wizard-navigate) + {:from (mm/encode-step-key :choose-method) + :to (mm/encode-step-key :payment-details)})} + "Print check")) + (when (= :bank-account-type/cash + (:bank-account/type bank-account)) + (com/button {:minimal-loading? true + :hx-vals (hx/json {"step-params[bank-account]" (:db/id bank-account) + "step-params[method]" "cash"}) + :hx-put (hu/url (bidi/path-for ssr-routes/only-routes ::route/pay-wizard-navigate) + {:from (mm/encode-step-key :choose-method) + :to (mm/encode-step-key :payment-details)})} + "With cash")) + (when (not= :bank-account-type/cash + (:bank-account/type bank-account)) + (com/button {:color (when (= :bank-account-type/credit + (:bank-account/type bank-account)) + :primary) + :minimal-loading? true + :hx-vals (hx/json {"step-params[bank-account]" (:db/id bank-account) + "step-params[method]" "debit"}) + :hx-put (hu/url (bidi/path-for ssr-routes/only-routes ::route/pay-wizard-navigate) + {:from (mm/encode-step-key :choose-method) + :to (mm/encode-step-key :payment-details)})} + "Debit")) + (when (and (= :bank-account-type/check (:bank-account/type bank-account)) + can-handwrite?) + (com/button {:minimal-loading? true + :hx-vals (hx/json {"step-params[bank-account]" (:db/id bank-account) + "step-params[method]" "handwrite-check"}) + :hx-put (hu/url (bidi/path-for ssr-routes/only-routes ::route/pay-wizard-navigate) + {:from (mm/encode-step-key :choose-method) + :to (mm/encode-step-key :payment-details)})} + "Handwrite check"))]]])]) + +(defmulti bank-account-card (fn [ba _ _] + (:bank-account/type ba))) +(defmethod bank-account-card :bank-account-type/cash [bank-account can-handwrite? credit-only?] + (bank-account-card-base {:bg-color "bg-green-50" + :text-color "text-green-600" + :icon svg/dollar + :bank-account bank-account + :can-handwrite? can-handwrite? + :credit-only? credit-only?})) + +(defmethod bank-account-card + :bank-account-type/credit + [bank-account can-handwrite? credit-only?] + (bank-account-card-base {:bg-color "bg-purple-50" + :text-color "text-purple-600" + :icon svg/credit-card + :bank-account bank-account + :can-handwrite? can-handwrite? + :credit-only? credit-only?})) + +(defmethod bank-account-card + :bank-account-type/check [bank-account can-handwrite? credit-only?] + (bank-account-card-base {:bg-color "bg-blue-50" + :text-color "text-blue-600" + :icon svg/check + :bank-account bank-account + :can-handwrite? can-handwrite? + :credit-only? credit-only?})) + + +(defn can-handwrite? [invoices] + (let [selected-vendors (set (map (comp :db/id :invoice/vendor) invoices))] + (and + (= 1 (count selected-vendors)) + (> (reduce + 0 (map :invoice/outstanding-balance invoices)) 0.0)))) + +(defn credit-only? [invoices] + (->> invoices + (group-by :invoice/vendor) + vals + (map (fn [is] + (alog/peek ::invoices is) + (reduce + 0.0 (map :invoice/outstanding-balance is)))) + (every? #(< % 0.0)))) + + +(defrecord ChoosePaymentMethodModal [linear-wizard] + mm/ModalWizardStep + (step-name [_] + "Payment method") + (step-key [_] + :choose-method) + + (edit-path [_ _] + []) + + (step-schema [_] + (mut/select-keys (mm/form-schema linear-wizard) #{:bank-account :method})) + + (render-step + [this request] + (let [invoices (:invoices (:snapshot (:multi-form-state request))) + can-handwrite? (can-handwrite? (map (comp (:invoice-by-id linear-wizard) :invoice-id) invoices)) + credit-only? (credit-only? (map (comp (:invoice-by-id linear-wizard) :invoice-id) invoices))] + (mm/default-render-step + linear-wizard this + :head [:div.p-2.inline-flex.gap-2.items-center "Pay " (count invoices) " invoices" + (when (:has-warning? (:snapshot (:multi-form-state request))) + (com/pill {:color :yellow} + "Some of the selected invoices may be locked or paid."))] + :body (mm/default-step-body + {} + [:div.flex.flex-col.space-y-2 + (for [ba (:bank-accounts linear-wizard)] + (bank-account-card ba can-handwrite? credit-only?))]) + :footer + nil + :validation-route ::route/pay-wizard-navigate)))) + +(defrecord PaymentDetailsStep [linear-wizard] + mm/ModalWizardStep + (step-name [_] + "Details") + (step-key [_] + :payment-details) + + (edit-path [_ _] + []) + + (step-schema [_] + (mut/select-keys (mm/form-schema linear-wizard) #{:invoices :check-number :handwritten-date :mode})) + + (render-step [this request] + (mm/default-render-step + linear-wizard this + :head [:div.p-2 "Pay " (count (:invoices (:snapshot (:multi-form-state request)))) " invoices"] + :body (mm/default-step-body + {} + [:div {} + (when (= :handwrite-check (:method (:snapshot (:multi-form-state request)))) + (fc/with-field :check-number + (com/validated-field + {:errors (fc/field-errors) + :label "Check number"} + (com/int-input {:value (fc/field-value) + :name (fc/field-name) + :error? (fc/field-errors) + :placeholder "10001"})))) + (when (= :handwrite-check (:method (:snapshot (:multi-form-state request)))) + (fc/with-field :handwritten-date + (com/validated-field + {:errors (fc/field-errors) + :label "Date"} + (com/date-input {:value (-> (fc/field-value) + (atime/unparse-local atime/normal-date)) + :name (fc/field-name) + :error? (fc/field-errors) + :placeholder "1/1/2020"})))) + (com/radio-list {:x-model "mode" + :name "step-params[mode]" + :options [{:value "simple" + :content (let [total (reduce + 0.0 + (map (comp :invoice/outstanding-balance (:invoice-by-id linear-wizard) :invoice-id) + (:invoices (:snapshot (:multi-form-state request)))))] + (if (< total 0) + (format "Credit in full ($%,.2f)" total) + (format "Pay in full ($%,.2f)" total)))} + {:value "advanced" + :content "Customize payments"}]}) + [:div.space-y-4 + (fc/with-field :invoices + (com/validated-field + {:errors (fc/field-errors)} + (com/data-grid + (hx/alpine-appear {:headers [(com/data-grid-header {} "Vendor") + (com/data-grid-header {} "Invoice Number") + (com/data-grid-header {:class "text-right"} "Total") + (com/data-grid-header {:class "text-right"} "Pay")] + :x-show "mode==\"advanced\""}) + (fc/cursor-map + (fn [i] + (com/data-grid-row + {} + (com/data-grid-cell + {} + + (-> (fc/field-value) :invoice :invoice/vendor :vendor/name)) + (com/data-grid-cell + {} + (fc/with-field :invoice-id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (-> (fc/field-value) :invoice :invoice/invoice-number)) + (com/data-grid-cell + {:class "text-right"} + [:span.inline-flex.gap-2 + (format "$%,.2f" (-> (fc/field-value) :invoice :invoice/outstanding-balance))]) + (com/data-grid-cell + {:class "w-20"} + (fc/with-field :amount + (com/validated-field {:errors (fc/field-errors)} + (com/money-input {:value (format "%.2f" (fc/field-value)) :class "w-20" + :name (fc/field-name) + :error? (fc/error?)}))))))))))]]) + :footer + (mm/default-step-footer linear-wizard this :validation-route ::route/pay-wizard-navigate) + :validation-route ::route/pay-wizard-navigate))) + +(defn add-handwritten-check [request wizard snapshot] + (let [invoices (d-invoices/get-multi (map :invoice-id (:invoices snapshot))) + bank-account-id (:bank-account snapshot) + bank-account (d-bank-accounts/get-by-id bank-account-id) + _ (when-not (= 1 (count (set (map (comp :db/id :invoice/vendor) invoices)))) + (throw (ex-info "Can only write a handwritten check for a single vendor." {:type :form-validation}))) + _ (doseq [invoice invoices] + (assert-can-see-client (:identity request) (:invoice/client invoice))) + client-id (:db/id (:invoice/client (first invoices))) + _ (validate-belonging (:db/id (:client/_bank-accounts bank-account)) invoices bank-account) + _ (assert-not-locked client-id (:handwritten-date snapshot)) + invoice-payment-lookup (by :invoice-id :amount (:invoices snapshot)) + base-payment (base-payment invoices + (:invoice/vendor (first invoices)) + (:invoice/client (first invoices)) + bank-account + :payment-type/check + 0 + invoice-payment-lookup)] + (let [result (audit-transact + (into [(assoc base-payment + :payment/type :payment-type/check + :payment/status :payment-status/pending + :payment/check-number (:check-number snapshot) + :payment/date (coerce/to-date (:handwritten-date snapshot)))] + (invoice-payments invoices invoice-payment-lookup)) + (:identity request))] + (doseq [[_ i] (:tempids result)] + (solr/touch-with-ledger i))))) + +;; TODO support crediting from balance +(defrecord PayWizard [form-params current-step invoice-by-id] + mm/LinearModalWizard + (hydrate-from-request + [this request] + (let [invoices (->> (dc/q '[:find (pull ?i [{:invoice/vendor [:vendor/name :db/id] + :invoice/client [:db/id]} + :invoice/outstanding-balance + :invoice/invoice-number + :db/id]) + :in $ [?i ...]] + (dc/db conn) + (map :invoice-id (get-in request [:multi-form-state :snapshot :invoices]))) + (map first) + (sort-by (juxt (comp :invoice/vendor :vendor/name) + :invoice/invoice-number)))] + (assoc this :invoice-by-id (by :db/id invoices) + :bank-accounts (->> (dc/q '[:find (pull ?ba [:bank-account/name :bank-account/sort-order :bank-account/visible + :bank-account/bank-name + :db/id + {[:bank-account/type :xform iol-ion.query/ident] [:db/ident]}]) + :in $ ?c + :where [?c :client/bank-accounts ?ba]] + (dc/db conn) + (:client (:snapshot (:multi-form-state request)))) + (map first) + (sort-by :bank-account/sort-order))))) + (navigate [this step-key] + (assoc this :current-step step-key)) + (get-current-step [this] + (if current-step + (mm/get-step this current-step) + (mm/get-step this :choose-method))) + (render-wizard [this {:keys [multi-form-state] :as request}] + (let [request (update-in request [:multi-form-state :step-params :invoices] + (fn [form-invoices] + (->> form-invoices + (map (fn [form-invoice] + (assoc form-invoice :invoice ((:invoice-by-id this) (:invoice-id form-invoice))))) + (sort-by + (juxt (comp :vendor/name :invoice/vendor :invoice) + (comp :invoice/invoice-number :invoice))) + (into []))))] + (mm/default-render-wizard + this request + :form-params + (-> mm/default-form-props + (assoc :hx-post + (str (bidi/path-for ssr-routes/only-routes ::route/pay-submit))) + (assoc :x-data (hx/json {:mode (some-> multi-form-state + :step-params + :mode + name)})))))) + + (steps [_] + [:choose-method + :payment-details]) + + (get-step [this step-key] + (let [step-key-result (mc/parse mm/step-key-schema step-key) + [step-key-type step-key] step-key-result] + (if (= :step step-key-type) + (get {:choose-method (->ChoosePaymentMethodModal this) + :payment-details (->PaymentDetailsStep this)} + step-key) + + (get {:bank-account (->ChoosePaymentMethodModal this)} + (first step-key))))) + (form-schema [_] payment-form-schema) + (submit [this {:keys [multi-form-state request-method identity] :as request}] + (let [snapshot (mc/decode + payment-form-schema + (:snapshot multi-form-state) + mt/strip-extra-keys-transformer) + + + _ (assert-schema payment-form-schema snapshot) + + _ (exception->4xx + #(if (= :handwrite-check (:method snapshot)) + (when (or (not (some? (:check-number snapshot))) + (= "" (:check-number snapshot))) + (throw (Exception. "Check number is required"))) + true)) + result (exception->4xx + #(if (= :handwrite-check (:method snapshot)) + (add-handwritten-check request this snapshot) + (print-checks-internal (map (fn [i] {:invoice-id (:invoice-id i) + :amount (:amount i)}) + (:invoices snapshot)) + (:client snapshot) + (:bank-account snapshot) + (cond (= :print-check (:method snapshot)) + :payment-type/check + (= :debit (:method snapshot)) + :payment-type/debit + (= :cash (:method snapshot)) + :payment-type/cash + (= :credit (:method snapshot)) + :payment-type/credit + :else :payment-type/debit) + identity)))] + (modal-response + (com/modal {} + (com/modal-card-advanced + {:class "transition duration-300 ease-in-out htmx-swapping:-translate-x-2/3 htmx-swapping:opacity-0 htmx-swapping:scale-0 htmx-added:translate-x-2/3 htmx-added:opacity-0 htmx-added:scale-0 scale-100 translate-x-0 opacity-100"} + (com/modal-body {} + [:div.flex.flex-col.mt-4.space-y-4.items-center + [:div.w-24.h-24.bg-green-50.rounded-full.p-4.text-green-300.animate-gg + svg/thumbs-up] + (when-not (:pdf-url result) + [:div "That's a wrap. Your payment is complete."]) + (when (:pdf-url result) + [:div "Your checks are ready. Click " + (com/link {:href (:pdf-url result) :target "_new"} "here") + " to download and print."]) + (when (:pdf-url result) + [:div.text-xs.italic [:em "Remember to turn off all scaling and margins."]])]))) + :headers {"hx-trigger" "invalidated"})))) + +(def pay-wizard + (->PayWizard nil nil nil)) + +(defn wrap-status-from-source [handler] + (fn [{:keys [matched-current-page-route] :as request}] + (let [request (cond-> request + (= ::route/paid-page matched-current-page-route) (assoc-in [:route-params :status] :invoice-status/paid) + (= ::route/unpaid-page matched-current-page-route) (assoc-in [:route-params :status] :invoice-status/unpaid) + (= ::route/voided-page matched-current-page-route) (assoc-in [:route-params :status] :invoice-status/voided) + (= ::route/all-page matched-current-page-route) (assoc-in [:route-params :status] nil))] + (handler request)))) + +(defn payable-ids [ids] + (->> (dc/q '[:find ?i + :in $ [?i ...] + :where [?i :invoice/status :invoice-status/unpaid] + [?i :invoice/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?i :invoice/date ?d] + [(>= ?d ?lu)]] + (dc/db conn) + ids) + (map first))) + +(defn initial-pay-wizard-state [request] + (exception->notification + #(let [selected-ids (selected->ids request (:query-params request)) + selected-ids (payable-ids selected-ids) + _ (when (= 0 (count selected-ids)) + (throw (ex-info "No selected invoices are applicable for payment" {:type :notification}))) + + has-warning? (and (:selected (:query-params request)) + (not= (count selected-ids) + (count (:selected (:query-params request))))) + invoices (->> (dc/q '[:find (pull ?i [{:invoice/vendor [:vendor/name :db/id] + :invoice/client [:db/id]} + :invoice/outstanding-balance + :invoice/invoice-number + :db/id]) + :in $ [?i ...]] + (dc/db conn) + selected-ids) + (map first) + (sort-by (juxt (comp :invoice/vendor :vendor/name) + :invoice/invoice-number)))] + (mm/->MultiStepFormState {:invoices (mapv (fn [i] {:invoice-id (:db/id i) + :amount (:invoice/outstanding-balance i)}) + invoices) + :mode :simple + :client (-> invoices first :invoice/client :db/id) + :has-warning? (boolean has-warning?) + :handwritten-date (time/now)} + [] + {:mode :simple + :has-warning? (boolean has-warning?)})))) + +(def key->handler + (apply-middleware-to-all-handlers + (-> + {::route/all-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status nil)) + ::route/paid-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status :invoice-status/paid)) + ::route/unpaid-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status :invoice-status/unpaid)) + ::route/voided-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status :invoice-status/voided)) + ::route/unvoid (-> unvoid-invoice + (wrap-entity [:route-params :db/id] default-read) + (wrap-schema-enforce :route-params [:map [:db/id entity-id]])) + ::route/pay-button (-> pay-button + (wrap-schema-enforce :query-schema query-schema)) + ::route/delete (-> delete + (wrap-entity [:route-params :db/id] default-read) + (wrap-schema-enforce :route-params [:map [:db/id entity-id]])) + ::route/bulk-delete-confirm (-> bulk-delete-dialog-confirm + (wrap-schema-enforce :form-schema query-schema) + (wrap-admin)) + ::route/bulk-delete (-> bulk-delete-dialog + (wrap-admin)) + ::route/pay-wizard (-> mm/open-wizard-handler + + (mm/wrap-wizard pay-wizard) + (mm/wrap-init-multi-form-state initial-pay-wizard-state)) + + ::route/pay-submit (-> mm/submit-handler + + (mm/wrap-wizard pay-wizard) + (mm/wrap-decode-multi-form-state)) + ::route/pay-wizard-navigate + (-> mm/next-handler + (mm/wrap-wizard pay-wizard) + (mm/wrap-decode-multi-form-state)) + + ::route/table (helper/table-route grid-page)} + (merge new-invoice-wizard/key->handler)) + (fn [h] + (-> h + (wrap-status-from-source) + (wrap-apply-sort grid-page) + (wrap-schema-enforce :query-schema query-schema) + (wrap-merge-prior-hx) + (wrap-client-redirect-unauthenticated))))) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/outgoing_invoice/new.clj b/src/clj/auto_ap/ssr/outgoing_invoice/new.clj new file mode 100644 index 00000000..790c1372 --- /dev/null +++ b/src/clj/auto_ap/ssr/outgoing_invoice/new.clj @@ -0,0 +1,285 @@ +(ns auto-ap.ssr.outgoing-invoice.new + (:require [amazonica.aws.lambda :as lambda] + [auto-ap.datomic :refer [conn pull-attr]] + [auto-ap.routes.invoice :as invoice-route] + [auto-ap.routes.outgoing-invoice :as route] + [auto-ap.routes.utils :refer [wrap-client-redirect-unauthenticated + wrap-secure]] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.common-handlers :refer [add-new-entity-handler]] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] + [auto-ap.ssr.grid-page-helper :refer [wrap-trim-client-ids]] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.ui :refer [base-page]] + [auto-ap.ssr.utils :refer [clj-date-schema modal-response money + percentage strip wrap-schema-decode]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clojure.data.json :as json] + [datomic.api :as dc] + [malli.core :as mc])) + +(def form-schema (mc/schema [:map + [:outgoing-invoice/client [:entity-map {:pull '[:client/name {:client/address [*]}]}]] + [:outgoing-invoice/date clj-date-schema] + [:outgoing-invoice/to :string] + [:outgoing-invoice/invoice-number :string] + [:outgoing-invoice/tax percentage] + [:outgoing-invoice/to-address [:map + [:street1 :string] + [:street2 {:optional true} [:maybe [:string {:decode/string strip}]]] + [:city :string] + [:state :string] + [:zip :string]]] + [:outgoing-invoice/line-items + [:vector {:coerce? true} + [:map + [:outgoing-invoice-line-item/description :string] + [:outgoing-invoice-line-item/unit-price money] + [:outgoing-invoice-line-item/quantity money]]]]])) + +(defn line-item [z] + (com/data-grid-row + (hx/alpine-mount-then-appear {:x-data (hx/json {:show false}) + :data-key "show" + :x-ref "p"}) + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (com/data-grid-cell + {} + (fc/with-field :outgoing-invoice-line-item/description + (com/text-input {:name (fc/field-name) + :value (fc/field-value) + :class "w-full" + :placeholder "Catered sandwiches"}))) + (com/data-grid-cell + {:class "w-8"} + (fc/with-field :outgoing-invoice-line-item/quantity + (com/money-input {:name (fc/field-name) + :value (fc/field-value) + :class "w-24" + :placeholder "20"}))) + (com/data-grid-cell + {} + (fc/with-field :outgoing-invoice-line-item/unit-price + (com/money-input {:name (fc/field-name) + :value (fc/field-value) + :class "w-24" + :placeholder "23.50"}))) + (com/data-grid-cell {:class "align-top"} + (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) + +(defn form* [{:keys [form-params form-errors]}] + + (fc/start-form + form-params + form-errors + [:form.flex.gap-4 {:hx-post (bidi.bidi/path-for ssr-routes/only-routes + ::route/new-submit)} + + (com/content-card {:max-w "max-w-screen-lg"} + [:div {:class "flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"} + [:div + [:h1.text-2xl.mb-3.font-bold "New outgoing invoice"]] + [:div {:class "flex flex-col flex-shrink-0 space-y-3 md:flex-row md:items-center lg:justify-end md:space-y-0 md:space-x-3"}]] + [:div.p-4 + (fc/with-field :outgoing-invoice/client + (com/validated-field {:errors (fc/field-errors) + :label "From (client)"} + [:div.w-96 + (com/typeahead {:name (fc/field-name) + :error? (fc/error?) + :autofocus true + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :value (fc/field-value) + :content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))})])) + + (fc/with-field :outgoing-invoice/invoice-number + (com/validated-field {:errors (fc/field-errors) + :label "Invoice #"} + [:div.w-96 + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "10000" + :value (fc/field-value)})])) + (fc/with-field :outgoing-invoice/date + (com/validated-field {:errors (fc/field-errors) + :label "Date"} + [:div.w-96 + (com/date-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "10000" + :value (-> (fc/field-value) + (atime/unparse-local atime/normal-date))})])) + + + + (fc/with-field-default :outgoing-invoice/line-items [{:db/id "first"}] + (com/validated-field {:errors (fc/field-errors) + :label "Line items"} + (com/data-grid {:headers [(com/data-grid-header {} "Description") + (com/data-grid-header {} "Quantity") + (com/data-grid-header {} "Unit Price") + (com/data-grid-header {} "")]} + (fc/cursor-map line-item) + (com/data-grid-new-row {:colspan 4 + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes + + ::route/new-line-item)} "Add line")))) + + (fc/with-field-default :outgoing-invoice/tax 10.0 + + (com/validated-field {:errors (fc/field-errors) + :label "Tax %"} + (com/money-input {:name (fc/field-name) + :value (fc/field-value)}))) + + [:div.flex.flex-row-reverse (com/button {:color :primary :class "w-24"} "Generate")]]) + (com/content-card {:max-w "max-w-24"} + [:div.p-4 + [:h3.text-lg "Recipient details"] + [:div.flex.flex-col.gap-2 + (fc/with-field :outgoing-invoice/to + (com/validated-field {:errors (fc/field-errors) + :label "To"} + [:div.w-96 + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "Hello Company" + :value (fc/field-value)})])) + + (fc/with-field-default :outgoing-invoice/to-address {} + (list + (fc/with-field :address/street1 + (com/validated-field {:label "Address" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-full" + :placeholder "1200 Pennsylvania Avenue" + :value (fc/field-value)}))) + (fc/with-field :address/street2 + (com/validated-field {:errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-full" + :placeholder "Suite 300" + :value (fc/field-value)}))) + [:div.flex.w-full.space-x-4 + (fc/with-field :address/city + (com/validated-field {:errors (fc/field-errors) + :class "w-full grow shrink"} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-full" + :placeholder "Cupertino" + :value (fc/field-value)}))) + (fc/with-field :address/state + (com/validated-field {:errors (fc/field-errors) + :class "w-16 shrink-0"} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :class "w-full" + :placeholder "CA" + :value (fc/field-value)}))) + (fc/with-field :address/zip + (com/validated-field {:errors (fc/field-errors) + :class "w-24 shrink-0"} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :placeholder "98101" + :class "w-full" + :value (fc/field-value)})))]))]])])) + +(defn- fmt-money [total] + (format "$%,.2f" (or total 0))) + +(defn submit [{:keys [form-params]}] + (let [line-items (->> form-params + :outgoing-invoice/line-items + (filter (fn [li] (not-empty (:outgoing-invoice-line-item/description li)))) + (mapv + #(assoc % :outgoing-invoice-line-item/total (* (:outgoing-invoice-line-item/unit-price %) + (:outgoing-invoice-line-item/quantity %))))) + + subtotal (reduce + 0.0 (map :outgoing-invoice-line-item/total line-items)) + tax (* subtotal (:outgoing-invoice/tax form-params)) + total (+ subtotal tax) + final-outgoing-invoice (-> form-params + (assoc :outgoing-invoice/line-items + line-items + :outgoing-invoice/total total + :outgoing-invoice/tax tax)) + result + + (-> (lambda/invoke {:function-name "genpdf" :payload + (json/write-str + (-> final-outgoing-invoice + (update :outgoing-invoice/total fmt-money) + (update :outgoing-invoice/tax fmt-money) + (update :outgoing-invoice/line-items + (fn [lis] + (mapv + #(-> % + (update :outgoing-invoice-line-item/total fmt-money) + (update :outgoing-invoice-line-item/unit-price fmt-money)) + lis))) + (update :outgoing-invoice/date + #(some-> % (atime/unparse-local atime/normal-date)))))}) + :payload + slurp + json/read-str)] + (modal-response + (com/modal {} + (com/modal-card {} [:div "Download your invoice"] [:div + "click " + (com/link {:href (str "https://data.prod.app.integreatconsult.com/" result)} + "here") + " to download"] [:div]))))) + +(def page (-> (fn page [{:keys [identity] :as request}] + (base-page + request + (com/page {:nav com/main-aside-nav + :client-selection (:client-selection (:session request)) + :clients (:clients request) + :client (:client request) + :identity (:identity request) + :request request} + (apply com/breadcrumbs {} [[:a {:href (bidi/path-for ssr-routes/only-routes + ::invoice-route/all-page)} + "Invoices"] + [:a {:href "#"} ;; TODO + "Outgoing"] + [:a {:href (bidi/path-for ssr-routes/only-routes + ::route/new)} + "New"]]) + (form* request)) + "New outgoing invoice")) + (wrap-trim-client-ids) + (wrap-secure) + (wrap-client-redirect-unauthenticated))) + +(def route->handler + {::route/new page + ::route/new-submit (-> submit + (wrap-schema-decode :form-schema form-schema) + (wrap-nested-form-params)) + ::route/new-line-item (-> + + (add-new-entity-handler [:outgoing-invoice/line-items] + (fn render [cursor request] + (line-item + {:value cursor })) + (fn build-new-row [base _] + base)))}) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/payments.clj b/src/clj/auto_ap/ssr/payments.clj new file mode 100644 index 00000000..12082e50 --- /dev/null +++ b/src/clj/auto_ap/ssr/payments.clj @@ -0,0 +1,559 @@ +(ns auto-ap.ssr.payments + (:require [auto-ap.client-routes :as client-routes] + [auto-ap.datomic + :refer [add-sorter-fields apply-pagination apply-sort-3 + audit-transact conn merge-query observable-query + pull-many]] + [auto-ap.graphql.utils :refer [assert-can-see-client + exception->notification + extract-client-ids notify-if-locked]] + [auto-ap.logging :as alog] + [auto-ap.permissions :refer [can?]] + [auto-ap.routes.invoice :as invoice-route] + [auto-ap.routes.payments :as route] + [auto-ap.routes.utils + :refer [wrap-admin wrap-client-redirect-unauthenticated]] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.bank-account-icon :as bank-account-icon] + [auto-ap.ssr.components.link-dropdown :refer [link-dropdown]] + [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.pos.common :refer [date-range-field*]] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.utils + :refer [apply-middleware-to-all-handlers clj-date-schema + dissoc-nil-transformer entity-id html-response + main-transformer modal-response ref->enum-schema strip + wrap-entity wrap-implied-route-param wrap-merge-prior-hx + wrap-schema-enforce]] + [auto-ap.time :as atime] + [bidi.bidi :as bidi] + [clj-time.coerce :as coerce] + [clojure.string :as str] + [datomic.api :as dc] + [hiccup.util :as hu] + [iol-ion.query :refer [dollars-0?]] + [malli.core :as mc] + [malli.transform :as mt])) + +(defn exact-match-id* [request] + (if (nat-int? (:exact-match-id (:parsed-query-params request))) + [:div {:x-data (hx/json {:exact_match (:exact-match-id (:parsed-query-params request))}) :id "exact-match-id-tag"} + (com/hidden {:name "exact-match-id" + "x-model" "exact_match"}) + (com/pill {:color :primary} + [:span.inline-flex.space-x-2.items-center + [:div "exact match"] + [:div.w-3.h-3 + (com/link {"@click" "exact_match=null; $nextTick(() => $dispatch('change'))"} + svg/x)]])] + [:div {:id "exact-match-id-tag"}])) + +;; TODO use query-params instead of parsed-query-params +(defn filters [request] + [:form#payment-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" + "hx-get" (bidi/path-for ssr-routes/only-routes + ::route/table) + "hx-target" "#entity-table" + "hx-indicator" "#entity-table"} + + (com/hidden {:name "status" + :value (some-> (:status (:query-params request)) name)}) + [:fieldset.space-y-6 + (com/field {:label "Vendor"} + (com/typeahead {:name "vendor" + :id "vendor" + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :value (:vendor (:query-params request)) + :value-fn :db/id + :content-fn :vendor/name})) + (date-range-field* request) + (com/field {:label "Check #"} + (com/text-input {:name "check-number" + :id "check-number" + :class "hot-filter" + :value (:check-number (:query-params request)) + :placeholder "10001" + :size :small})) + (com/field {:label "Invoice #"} + (com/text-input {:name "invoice-number" + :id "invoice-number" + :class "hot-filter" + :value (:invoice-number (:query-params request)) + :placeholder "10001" + :size :small})) + + (com/field {:label "Amount"} + [:div.flex.space-x-4.items-baseline + (com/money-input {:name "amount-gte" + :id "amount-gte" + :hx-preserve "true" + :class "hot-filter w-20" + :value (:amount-gte (:query-params request)) + :placeholder "0.01" + :size :small}) + [:div.align-baseline + "to"] + (com/money-input {:name "amount-lte" + :hx-preserve "true" + :id "amount-lte" + :class "hot-filter w-20" + :value (:amount-lte (:query-params request)) + :placeholder "9999.34" + :size :small})]) + (com/field {:label "Payment Type"} + (com/radio-card {:size :small + :name "payment-type" + :value (:payment-type (:query-params request)) + :options [{:value "" + :content "All"} + {:value "cash" + :content "Cash"} + {:value "check" + :content "Check"} + {:value "debit" + :content "Debit"}]})) + (exact-match-id* request)]]) + + +(def default-read '[* + [:payment/date :xform clj-time.coerce/from-date] + {:invoice-payment/_payment [* {:invoice-payment/invoice [*]}]} + {:payment/client [:client/name :db/id :client/code]} + {:payment/bank-account [* {[:bank-account/type :xform iol-ion.query/ident] [:db/ident]}]} + {:payment/invoices [:db/id :invoice/invoice-number]} + {:payment/vendor [:vendor/name {:vendor/default-account + [:account/name :account/numeric-code :db/id]} :db/id {:vendor/primary-contact [*]} {:vendor/address [*]}]} + {[:payment/status :xform iol-ion.query/ident] [:db/ident]} + {[:payment/type :xform iol-ion.query/ident] [:db/ident]} + {:transaction/_payment [:db/id :transaction/date]}]) + +(defn fetch-ids [db {:keys [query-params route-params] :as request}] + (let [ valid-clients (extract-client-ids (:clients request) + (:client request) + (:client-id query-params) + (when (:client-code query-params) + [:client/code (:client-code query-params)])) + + check-number-like (try (Long/parseLong (:check-number query-params)) (catch Exception _ nil)) + query (if (:exact-match-id query-params) + {:query {:find '[?e] + :in '[$ ?e [?c ...]] + :where '[[?e :payment/client ?c]]} + :args [db + (:exact-match-id query-params) + valid-clients]} + (cond-> {:query {:find [] + :in '[$ [?clients ?start ?end]] + :where '[[(iol-ion.query/scan-payments $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]]} + :args [db + [valid-clients + (some-> (:start-date query-params) coerce/to-date) + (some-> (:end-date query-params) coerce/to-date)]]} + (:sort query-params) (add-sorter-fields {"client" ['[?e :payment/client ?c] + '[?c :client/name ?sort-client]] + "vendor" ['[?e :payment/vendor ?v] + '[?v :vendor/name ?sort-vendor]] + "bank-account" ['[?e :payment/bank-account ?ba] + '[?ba :bank-account/name ?sort-bank-account]] + "check-number" ['[(get-else $ ?e :payment/check-number 0) ?sort-check-number]] + "date" ['[?e :payment/date ?sort-date]] + "amount" ['[?e :payment/amount ?sort-amount]] + "status" ['[?e :payment/status ?sort-status]]} + query-params) + (:exact-match-id query-params) + (merge-query {:query {:in ['?e] + :where []} + :args [(:exact-match-id query-params)]}) + + (:vendor query-params) + (merge-query {:query {:in ['?vendor-id] + :where ['[?e :payment/vendor ?vendor-id]]} + :args [(:db/id (:vendor query-params))]}) + + (:original-id query-params) + (merge-query {:query {:in ['?original-id] + :where ['[?e :payment/client ?c] + '[?c :client/original-id ?original-id]]} + :args [(:original-id query-params)]}) + + (:check-number-like query-params) + (merge-query {:query {:in ['?check-number] + :where ['[?e :payment/check-number ?check-number]]} + :args [(:check-number-like query-params)]}) + + (not-empty (:invoice-number query-params)) + (merge-query {:query {:in ['?invoice-number] + :where ['[?e :payment/invoices ?i] + '[?i :invoice/invoice-number ?invoice-number]]} + :args [(:invoice-number query-params)]}) + + (:bank-account-id query-params) + (merge-query {:query {:in ['?bank-account-id] + :where ['[?e :payment/bank-account ?bank-account-id]]} + :args [(:bank-account-id query-params)]}) + + (:amount-gte query-params) + (merge-query {:query {:in ['?amount-gte] + :where ['[?e :payment/amount ?a] + '[(>= ?a ?amount-gte)]]} + :args [(:amount-gte query-params)]}) + + (:amount-lte query-params) + (merge-query {:query {:in ['?amount-lte] + :where ['[?e :payment/amount ?a] + '[(<= ?a ?amount-lte)]]} + :args [(:amount-lte query-params)]}) + + (:amount query-params) + (merge-query {:query {:in ['?amount] + :where ['[?e :payment/amount ?transaction-amount] + '[(iol-ion.query/dollars= ?transaction-amount ?amount)]]} + :args [(:amount query-params)]}) + + + (:status route-params) + (merge-query {:query {:in ['?status] + :where ['[?e :payment/status ?status]]} + :args [(:status route-params)]}) + + (:payment-type query-params) + (merge-query {:query {:in '[?payment-type] + :where ['[?e :payment/type ?payment-type]]} + :args [(:payment-type query-params)]}) + + check-number-like + (merge-query {:query {:in '[?check-number-like] + :where ['[?e :payment/check-number ?check-number-like]]} + :args [check-number-like]}) + + true + (merge-query {:query {:find ['?sort-default '?e]}})))] + (cond->> (observable-query query) + true (apply-sort-3 query-params) + true (apply-pagination query-params)))) + +(defn hydrate-results [ids db _] + (let [results (->> (pull-many db default-read ids) + (group-by :db/id)) + refunds (->> ids + (map results) + (map first))] + refunds)) + +(defn fetch-page [request] + (let [db (dc/db conn) + {ids-to-retrieve :ids matching-count :count} (fetch-ids db request)] + + [(->> (hydrate-results ids-to-retrieve db request)) + matching-count])) + +(def query-schema (mc/schema + [:maybe [:map {:date-range [:date-range :start-date :end-date]} + [:sort {:optional true} [:maybe [:any]]] + [:per-page {:optional true :default 25} [:maybe :int]] + [:start {:optional true :default 0} [:maybe :int]] + [:amount-gte {:optional true} [:maybe :double]] + [:amount-lte {:optional true} [:maybe :double]] + [:payment-type {:optional true} [:maybe (ref->enum-schema "payment-type")]] + [:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]] + [:check-number {:optional true} [:maybe [:string {:decode/string strip}]]] + [:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]] + [:status {:optional true} [:maybe (ref->enum-schema "payment-status")]] + [:exact-match-id {:optional true} [:maybe entity-id]] + [:all-selected {:optional true :default nil} [:maybe :boolean]] + [:selected {:optional true :default nil} [:maybe [:vector {:coerce? true} + entity-id]]] + [:start-date {:optional true} + [:maybe clj-date-schema]] + [:end-date {:optional true} + [:maybe clj-date-schema]]]])) + +(comment + (mc/decode query-schema + {:start " "} + main-transformer)) + +;; TODO fix parsing of query params +(def grid-page + (helper/build {:id "entity-table" + :nav com/main-aside-nav + :check-boxes? true + :page-specific-nav filters + :fetch-page fetch-page + :oob-render + (fn [request] + [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true) + (assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)]) + :query-schema query-schema + :parse-query-params (fn [p] + (mc/decode query-schema p main-transformer)) + :action-buttons (fn [request] + [(when (can? (:identity request) {:subject :payment :activity :bulk-delete}) + (com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/bulk-delete)) + "x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})" + "hx-include" "#payment-filters" + :color :red} + "Void selected"))]) + :row-buttons (fn [_ entity] + [(when (not= :payment-status/voided (:payment/status entity)) + (com/icon-button {:hx-delete (bidi/path-for ssr-routes/only-routes + ::route/delete + :db/id (:db/id entity)) + :hx-confirm "Are you sure you want to void this payment?"} + svg/trash))]) + :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)} + "Payments"]] + :title (fn [r] + (str + (some-> r :rout-params :status name str/capitalize (str " ")) + "Payments")) + :entity-name "payments" + :route ::route/table + :headers [{:key "client" + :name "Client" + :sort-key "client" + :hide? (fn [args] + (= (count (:clients args)) 1)) + :render #(-> % :payment/client :client/code)} + {:key "vendor" + :name "Vendor" + :sort-key "vendor" + :render #(-> % :payment/vendor :vendor/name)} + {:key "bank-account" + :name "Bank account" + :sort-key "bank-account" + :show-starting "xl" + :render (fn [p] + [:div.flex.items-center + (when (:payment/bank-account p) + (bank-account-icon/icon (:payment/bank-account p))) + [:div (-> p :payment/bank-account :bank-account/name)]])} + {:key "check-number" + :name "Check #" + :sort-key "check-number" + :render (fn [{:payment/keys [s3-url check-number]}] + (if s3-url + (com/link {:href s3-url :target "_new"} [:div.flex.items-center.gap-x-2 check-number [:div.w-4.h-4 svg/external-link]]) + check-number))} + {:key "status" + :name "Status" + :render (fn [{:payment/keys [status]}] + (condp = status + :payment-status/cleared + (com/pill {:color :primary} "cleared") + + :payment-status/pending + (com/pill {:color :secondary} "pending") + :payment-status/voided + (com/pill {:color :red} "voided") + nil + ""))} + {:key "date" + :name "Date" + :show-starting "lg" + :render (fn [{:payment/keys [date]}] + (some-> date (atime/unparse-local atime/normal-date)))} + {:key "amount" + :name "Amount" + :render (fn [{:payment/keys [amount]}] + (some->> amount (format "$%.2f")))} + {:key "links" + :name "Links" + :class "w-8" + :render (fn [p] + (link-dropdown (concat (->> p :payment/invoices (map (fn [invoice] + {:link (hu/url (bidi/path-for ssr-routes/only-routes + ::invoice-route/all-page) + {:exact-match-id (:db/id invoice)}) + :content (str "Inv. " (:invoice/invoice-number invoice))}))) + (some-> p :transaction/_payment ((fn [t] + [{:link (hu/url (bidi/path-for client-routes/routes + :transactions) + {:exact-match-id (:db/id (first t))}) + :color :secondary + :content "Transaction"}]))))))}]})) + +(def row* (partial helper/row* grid-page)) + + + +(comment + (mc/decode query-schema {"exact-match-id" "123"} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + (mc/decode query-schema {} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + (mc/decode query-schema {"exact-match-id" nil} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + (mc/decode query-schema {"exact-match-id" ""} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + (mc/decode query-schema {"start-date" "12/21/2023"} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + (mc/decode query-schema {"payment-type" "food"} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + (mc/decode query-schema {"vendor" "87"} (mt/transformer main-transformer mt/strip-extra-keys-transformer)) + + + (mc/decode query-schema {"start-date" #inst "2023-12-21T08:00:00.000-00:00"} (mt/transformer main-transformer mt/strip-extra-keys-transformer))) + +(defn delete [{check :entity :as request identity :identity}] + (alog/peek ::check-type check) + (exception->notification + #(when-not (or (= :payment-status/pending (:payment/status check)) + (#{:payment-type/cash :payment-type/debit :payment-type/balance-credit} (:payment/type check))) + (throw (ex-info "Payment must be pending." {})))) + + (exception->notification + #(assert-can-see-client identity (:db/id (:payment/client check)))) + (notify-if-locked (:db/id (:payment/client check)) + (:payment/date check)) + (let [removing-payments (mapcat (fn [x] + (let [invoice (:invoice-payment/invoice x) + new-balance (+ (:invoice/outstanding-balance invoice) + (:invoice-payment/amount x))] + [[:db/retractEntity (:db/id x)] + [:upsert-invoice {:db/id (:db/id invoice) + :invoice/outstanding-balance new-balance + :invoice/status (if (dollars-0? new-balance) + (:invoice/status invoice) + :invoice-status/unpaid)}]])) + (:invoice-payment/_payment check)) + updated-payment {:db/id (:db/id check) + :payment/amount 0.0 + :payment/status :payment-status/voided}] + (audit-transact (conj removing-payments updated-payment) + identity) + + (html-response (row* (:identity request) updated-payment {:delete-after-settle? true :class "live-removed"}) + :headers {"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id check))}))) + +;; TODO use decoding here +(defn bulk-delete-dialog [request] + (alog/peek :selected (pr-str (:selected (:query-params request)))) + (let [all-selected (:all-selected (:query-params request)) + selected (:selected (:query-params request)) + ids (cond + all-selected + (:ids (fetch-ids (dc/db conn) (-> request + (assoc-in [:query-params :start] 0) + (assoc-in [:query-params :per-page] 250)))) + :else + selected)] + (modal-response + (com/modal {} + (com/modal-card-advanced + {} + + (com/modal-body {} + [:div.flex.flex-col.mt-4.space-y-4.items-center + [:div.w-24.h-24.bg-red-50.rounded-full.p-4.text-red-300 + + svg/alert] + [:div "You are about to void " (count ids) " payments. Are you sure you want to do this?"]]) + (com/modal-footer {} [:div.flex.justify-end (com/button {:color :primary + :hx-vals (hx/json (mc/encode + query-schema + (dissoc (:query-params request) :sort) + (mt/transformer + main-transformer + dissoc-nil-transformer + mt/strip-extra-keys-transformer))) + :hx-delete (hu/url (bidi/path-for ssr-routes/only-routes + ::route/bulk-delete-confirm))} + "Void payments")]))) + :headers (-> {} + (assoc "hx-retarget" ".modal-stack") + (assoc "hx-reswap" "beforeend"))))) + +(defn void-payments-internal [all-ids id] + (let [payments-to-update (->> all-ids + (dc/q '[:find (pull ?p [:db/id + {:invoice-payment/_payment [:invoice-payment/amount + :db/id + {:invoice-payment/invoice [:db/id :invoice/outstanding-balance]}]}]) + :in $ [?p ...] + :where + (not [_ :transaction/payment ?p]) + (not [?p :payment/status :payment-status/voided]) + [?p :payment/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?p :payment/date ?d] + [(>= ?d ?lu)]] + (dc/db conn)) + (map first))] + (audit-transact (->> payments-to-update + (mapcat (fn [{:keys [:db/id] + invoices :invoice-payment/_payment}] + (into + [{:db/id id + :payment/amount 0.0 + :payment/status :payment-status/voided}] + (->> invoices + (mapcat (fn [{:keys [:invoice-payment/invoice :db/id :invoice-payment/amount]}] + (let [new-balance (+ (:invoice/outstanding-balance invoice) + amount)] + [[:db.fn/retractEntity id] + [:upsert-invoice {:db/id (:db/id invoice) + :invoice/outstanding-balance new-balance + :invoice/status (if (dollars-0? new-balance) + (:invoice/status invoice) + :invoice-status/unpaid)}]])))))))) + id) + (count payments-to-update))) + +(defn bulk-delete-dialog-confirm [request] + (alog/peek (:form-params request)) + (let [all-selected (:all-selected (:form-params request)) + selected (:selected (:form-params request)) + ids (cond + all-selected + (:ids (fetch-ids (dc/db conn) (-> request + (assoc :query-params (:form-params request)) + (assoc-in [:query-params :start] 0) + (assoc-in [:query-params :per-page] 250)))) + + + :else + selected) + updated-count (void-payments-internal ids (:identity request))] + + (html-response [:div] + :headers {"hx-trigger" (hx/json {:modalclose "" + :notification (format "Successfully voided %d of %d payments." + updated-count + (count ids))})}))) + +(defn wrap-status-from-source [handler] + (fn [{:keys [matched-current-page-route] :as request}] + (let [ request (cond-> request + (= ::route/cleared-page matched-current-page-route) (assoc-in [:route-params :status] :payment-status/cleared) + (= ::route/pending-page matched-current-page-route) (assoc-in [:route-params :status] :payment-status/pending) + (= ::route/voided-page matched-current-page-route) (assoc-in [:route-params :status] :payment-status/voided) + (= ::route/all-page matched-current-page-route) (assoc-in [:route-params :status] nil))] + (handler request)))) + +(def key->handler + (apply-middleware-to-all-handlers + {::route/cleared-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status :payment-status/cleared)) + ::route/pending-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status :payment-status/pending)) + ::route/voided-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status :payment-status/voided)) + ::route/all-page (-> (helper/page-route grid-page) + (wrap-implied-route-param :status nil)) + + ::route/delete (-> delete + (wrap-entity [:route-params :db/id] default-read) + (wrap-schema-enforce :route-params [:map [:db/id entity-id]])) + ::route/bulk-delete-confirm (-> bulk-delete-dialog-confirm + (wrap-schema-enforce :form-schema query-schema) + (wrap-admin)) + ::route/bulk-delete (-> bulk-delete-dialog + (wrap-admin)) + + + ::route/table (helper/table-route grid-page)} + (fn [h] + (-> h + (wrap-apply-sort grid-page) + (wrap-merge-prior-hx) + (wrap-status-from-source) + (wrap-schema-enforce :query-schema query-schema) + (wrap-schema-enforce :hx-schema query-schema) + (wrap-client-redirect-unauthenticated))))) \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj b/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj index c99eb9ba..8c27993b 100644 --- a/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj +++ b/src/clj/auto_ap/ssr/pos/cash_drawer_shifts.clj @@ -84,10 +84,9 @@ matching-count])) (def grid-page - {} - #_(helper/build + (helper/build {:id "cash-drawer-shift-table" - :nav (com/main-aside-nav) + :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page :oob-render diff --git a/src/clj/auto_ap/ssr/pos/common.clj b/src/clj/auto_ap/ssr/pos/common.clj index 1d35d806..2419c223 100644 --- a/src/clj/auto_ap/ssr/pos/common.clj +++ b/src/clj/auto_ap/ssr/pos/common.clj @@ -10,7 +10,7 @@ (defn processor-field* [request] (com/field {:label "Processor"} - (com/radio {:size :small + (com/radio-card {:size :small :name "processor" :value (:processor (:parsed-query-params request)) :options [{:value "" diff --git a/src/clj/auto_ap/ssr/pos/expected_deposits.clj b/src/clj/auto_ap/ssr/pos/expected_deposits.clj index a11b17bc..e821b827 100644 --- a/src/clj/auto_ap/ssr/pos/expected_deposits.clj +++ b/src/clj/auto_ap/ssr/pos/expected_deposits.clj @@ -136,23 +136,23 @@ (def grid-page (helper/build {:id "expected-deposit-table" - :nav (com/main-aside-nav) + :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) + (query-params/parse-key :total-gte query-params/parse-double) + (query-params/parse-key :total-lte query-params/parse-double) + (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :company)} - "POS"] + "POS"] [:a {:href (bidi/path-for ssr-routes/only-routes :pos-expected-deposits)} - "Expected deposits"]] + "Expected deposits"]] :title "Expected deposits" :entity-name "Expected deposit" :route :pos-expected-deposit-table @@ -170,7 +170,7 @@ :name "Client" :sort-key "client" :hide? (fn [args] - (= (count (:clients args)) 1)) + (= (count (:clients args)) 1)) :render #(-> % :expected-deposit/client :client/code)} {:key "date" :name "Date" diff --git a/src/clj/auto_ap/ssr/pos/refunds.clj b/src/clj/auto_ap/ssr/pos/refunds.clj index 2651307e..60a4c6e3 100644 --- a/src/clj/auto_ap/ssr/pos/refunds.clj +++ b/src/clj/auto_ap/ssr/pos/refunds.clj @@ -95,23 +95,23 @@ (def grid-page (helper/build {:id "refund-table" - :nav (com/main-aside-nav) + :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) + (query-params/parse-key :total-gte query-params/parse-double) + (query-params/parse-key :total-lte query-params/parse-double) + (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :company)} - "POS"] + "POS"] [:a {:href (bidi/path-for ssr-routes/only-routes :pos-refunds)} - "Refunds"]] + "Refunds"]] :title "Refunds" :entity-name "Refund" :route :pos-refund-table @@ -119,7 +119,7 @@ :name "Client" :sort-key "client" :hide? (fn [args] - (= (count (:clients args)) 1)) + (= (count (:clients args)) 1)) :render #(-> % :sales-refund/client :client/code)} {:key "date" :name "Date" diff --git a/src/clj/auto_ap/ssr/pos/sales_orders.clj b/src/clj/auto_ap/ssr/pos/sales_orders.clj index 4c23bdbd..85573751 100644 --- a/src/clj/auto_ap/ssr/pos/sales_orders.clj +++ b/src/clj/auto_ap/ssr/pos/sales_orders.clj @@ -34,7 +34,7 @@ (total-field* request) [:div (com/field {:label "Payment Method"} - (com/radio {:size :small + (com/radio-card {:size :small :name "payment-method" :options [{:value "" :content "All"} @@ -169,14 +169,14 @@ (def grid-page (helper/build {:id "sales-table" - :nav (com/main-aside-nav) + :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp - (query-params/parse-key :processor #(query-params/parse-keyword "ccp-processor" %)) - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) + (query-params/parse-key :processor #(query-params/parse-keyword "ccp-processor" %)) + (query-params/parse-key :total-gte query-params/parse-double) + (query-params/parse-key :total-lte query-params/parse-double) + (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) diff --git a/src/clj/auto_ap/ssr/pos/tenders.clj b/src/clj/auto_ap/ssr/pos/tenders.clj index 27c4de7e..bfad7d53 100644 --- a/src/clj/auto_ap/ssr/pos/tenders.clj +++ b/src/clj/auto_ap/ssr/pos/tenders.clj @@ -112,14 +112,14 @@ (def grid-page (helper/build {:id "tender-table" - :nav (com/main-aside-nav) + :nav com/main-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp - (query-params/parse-key :processor #(query-params/parse-keyword "ccp-processor" %)) - (query-params/parse-key :total-gte query-params/parse-double) - (query-params/parse-key :total-lte query-params/parse-double) - (helper/default-parse-query-params grid-page)) + (query-params/parse-key :processor #(query-params/parse-keyword "ccp-processor" %)) + (query-params/parse-key :total-gte query-params/parse-double) + (query-params/parse-key :total-lte query-params/parse-double) + (helper/default-parse-query-params grid-page)) :oob-render (fn [request] [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)]) diff --git a/src/clj/auto_ap/ssr/svg.clj b/src/clj/auto_ap/ssr/svg.clj index 36026612..a35139bf 100644 --- a/src/clj/auto_ap/ssr/svg.clj +++ b/src/clj/auto_ap/ssr/svg.clj @@ -96,6 +96,14 @@ [:svg {:fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} [:path {:d "M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"}]]) +(def three-dots + [:svg {:xmlns "http://www.w3.org/2000/svg", :viewbox "0 0 24 24"} + [:defs] + [:title "navigation-menu-horizontal"] + [:path {:d "M0.5 12a2.5 2.5 0 1 0 5 0 2.5 2.5 0 1 0 -5 0", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}] + [:path {:d "M9.5 12a2.5 2.5 0 1 0 5 0 2.5 2.5 0 1 0 -5 0", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}] + [:path {:d "M18.5 12a2.5 2.5 0 1 0 5 0 2.5 2.5 0 1 0 -5 0", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}]]) + (def breadcrumb-component [:svg {:fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} [:path {:fill-rule "evenodd", :d "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", :clip-rule "evenodd"}]]) @@ -487,4 +495,28 @@ [:path {:d "m19.025 2.677 1.293 -1.293", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}] [:path {:d "M6.5 9.616H1a0.5 0.5 0 0 0 -0.5 0.5v12a0.5 0.5 0 0 0 0.5 0.5h22a0.5 0.5 0 0 0 0.5 -0.5v-12a0.5 0.5 0 0 0 -0.5 -0.5h-5", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}] [:path {:d "M17.004 12.616h3s0.5 0 0.5 0.5v2s0 0.5 -0.5 0.5h-3s-0.5 0 -0.5 -0.5v-2s0 -0.5 0.5 -0.5", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}] - [:path {:d "m16.757 2.823 -0.8 -0.8a1 1 0 0 0 -1.414 0L12.5 4.07", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}]]) \ No newline at end of file + [:path {:d "m16.757 2.823 -0.8 -0.8a1 1 0 0 0 -1.414 0L12.5 4.07", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}]]) + +(def paperclip + [:svg + {:xmlns "http://www.w3.org/2000/svg", + :viewBox "0 0 24 24", + :id "Attachment--Streamline-Streamline--3.0"} + [:desc "Attachment Streamline Icon: https://streamlinehq.com"] + [:defs] + [:title "attachment"] + [:path + {:d + "m7.618 15.345 8.666 -8.666a2.039 2.039 0 1 1 2.883 2.883L7.461 21.305a4.078 4.078 0 0 1 -5.767 -5.768L13.928 3.305a5.606 5.606 0 0 1 7.929 7.928L13.192 19.9", + :fill "none", + :stroke "currentcolor", + :stroke-linecap "round", + :stroke-linejoin "round", + :stroke-width "1"}]]) + +(def undo + [:svg {:xmlns "http://www.w3.org/2000/svg", :viewbox "0 0 24 24", :id "Undo--Streamline-Streamline--3.0"} + [:defs] + [:title "undo"] + [:path {:d "m1.5 0.498 0 7 7 0", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}] + [:path {:d "M1.5 7.5a11.656 11.656 0 0 1 16.179 -2.647 11.508 11.508 0 0 1 0.11 18.645", :fill "none", :stroke "currentcolor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "1"}]]) diff --git a/src/clj/auto_ap/ssr/transaction/insights.clj b/src/clj/auto_ap/ssr/transaction/insights.clj index 3515306f..18f9f1a1 100644 --- a/src/clj/auto_ap/ssr/transaction/insights.clj +++ b/src/clj/auto_ap/ssr/transaction/insights.clj @@ -317,7 +317,7 @@ (defn page [{:keys [identity matched-route session clients] :as request}] (base-page request - (com/page {:nav (com/main-aside-nav) + (com/page {:nav com/main-aside-nav :client-selection (:client-selection (:session request)) :client (:client request) :identity (:identity request) @@ -325,7 +325,8 @@ :transaction-insights) :hx-trigger "clientSelected from:body" :hx-select "#app-contents" - :hx-swap "outerHTML swap:300ms"}} + :hx-swap "outerHTML swap:300ms"} + :request request} (com/breadcrumbs {} [:a {:href (bidi/path-for client-routes/routes :transactions)} diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index aad7f05b..89f83ca8 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -45,7 +45,6 @@ [:script {:src "/js/htmx-disable.js"}] [:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async"}]] [:link {:rel "stylesheet" :href "https://cdn.jsdelivr.net/npm/vanillajs-datepicker@1.1.4/dist/css/datepicker.min.css"}] - [:script {:type "text/javascript" :src "https://cdn.jsdelivr.net/npm/vanillajs-datepicker@1.1.4/dist/js/datepicker-full.min.js"}] [:link {:rel "stylesheet" :href "https://cdn.jsdelivr.net/npm/choices.js@9.0.1/public/assets/styles/choices.min.css"}] @@ -54,6 +53,7 @@ [:script {:src "https://unpkg.com/dropzone@5.9.3/dist/min/dropzone.min.js"}] [:link {:rel "stylesheet" :href "https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" :type "text/css"}] + [:script {:defer true :src "/js/alpine-vals.js"}] [:script {:defer true :src "https://cdn.jsdelivr.net/npm/@alpinejs/focus@3.x.x/dist/cdn.min.js"}] [:script {:defer true :src "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"}] [:script {:src "https://cdn.jsdelivr.net/npm/signature_pad@4.1.7/dist/signature_pad.umd.min.js"}] @@ -81,14 +81,16 @@ input[type=number] { "x-show" "open" ":aria-hidden" "!open" "x-data" (hx/json {"open" false + "forceBackground" false "unexpectedError" false}) "x-on:htmx:response-error" "unexpectedError=true;" "x-on:htmx:before-request" "unexpectedError=false" "@modalopen.document" "open=true; unexpectedError=null" - "@modalclose.document" "open=false"} + "@modalclose.document" "open=false" + "@modalswap.document" "forceBackground=true; open=false; setTimeout(() => {open=true;forceBackground=false;}, 100)"} [:div {:class "bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40 md:p-12" - "x-show" "open" + "x-show" "open || forceBackground" ":aria-hidden" "!open" "x-transition:enter" "duration-300" "x-transition:enter-start" "!bg-opacity-0" @@ -108,7 +110,4 @@ input[type=number] { "x-transition:leave-start" "!opacity-100 !translate-y-0" "x-transition:leave-end" "!opacity-0 !translate-y-32"} - [:div.flex.items-center.justify-center.max-w-6xl {:class "min-w-[700px] max-h-full "} - - [:div#modal-content.flex.flex-col.self-stretch {:class "min-w-[700px] md:p-12"} ;;.overflow-scroll - ]]]]]]])) + [:div#modal-content.flex.items-center.justify-center {:class "md:p-12"}]]]]]])) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 9e4ca3f0..4c8e7d6d 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -66,7 +66,7 @@ :size :small})) (com/field {:label "Role"} - (com/radio {:size :small + (com/radio-card {:size :small :name "role" :options [{:value "" :content "All"} @@ -205,20 +205,20 @@ (def grid-page (helper/build {:id "user-table" - :nav (com/admin-aside-nav) + :nav com/admin-aside-nav :page-specific-nav filters :fetch-page fetch-page :parse-query-params (comp - (query-params/parse-key :role #(query-params/parse-keyword "user-role" %)) - (query-params/parse-key :client parse-client) - (helper/default-parse-query-params grid-page)) + (query-params/parse-key :role #(query-params/parse-keyword "user-role" %)) + (query-params/parse-key :client parse-client) + (helper/default-parse-query-params grid-page)) :row-buttons (fn [request entity] [(com/button {:hx-post (str (bidi/path-for ssr-routes/only-routes :user-impersonate)) :hx-vals (format "{\"db/id\": \"%s\"}" (:db/id entity))} "Impersonate") (com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes - :user-edit-dialog - :db/id (:db/id entity)))} + :user-edit-dialog + :db/id (:db/id entity)))} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -238,7 +238,7 @@ (when-let [profile-image (:user/profile-image-url user) ] [:div.rounded-full.overflow-hidden.w-8.h-8.display-inline [:img {:src profile-image }]]) - [:span.inline-block ](:user/name user)])} + [:span.inline-block ] (:user/name user)])} {:key "email" :name "Email" @@ -292,49 +292,50 @@ (defn dialog* [{:keys [form-params form-errors entity]}] + (println "FORM PARMS" form-params) (fc/start-form - form-params form-errors - (com/modal - {:hx-target "this" - :hx-indicator "this"} - [:form {:hx-ext "response-targets" - :hx-put (str (bidi/path-for ssr-routes/only-routes - :user-edit-save - :request-method :put)) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :class "w-full h-full"} - [:fieldset {:class "hx-disable h-full"} - (com/modal-card - {} - [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name entity)]] - [:div.space-y-6 - (fc/with-field :db/id - (com/hidden {:name (fc/field-name) - :value (fc/field-value)})) - (fc/with-field :user/role - (com/validated-field {:label "Role" - :errors (fc/field-errors)} - (com/select {:name (fc/field-name) - :class "w-36" - :autofocus true - :value (some->> (fc/field-value) name) - :options (ref->select-options "user-role")}))) - (fc/with-field :user/clients - (com/validated-field {:label "Clients"} - (com/data-grid {:headers [(com/data-grid-header {} "Client") - (com/data-grid-header {} )] - :id "client-table"} - (fc/cursor-map #(client-row* %)) - (com/data-grid-new-row {:colspan 2 - :index (count (fc/field-value)) - :hx-get (bidi/path-for ssr-routes/only-routes - :user-client-new)} - "Assign new client"))))] - [:div - (com/form-errors {:errors (:errors fc/*form-errors*)}) - (com/validated-save-button {:errors (seq form-errors)} - "Save user")])]]))) + form-params form-errors + (com/modal + {:hx-target "this" + :hx-indicator "this"} + [:form {:hx-ext "response-targets" + :hx-put (str (bidi/path-for ssr-routes/only-routes + :user-edit-save + :request-method :put)) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :class "w-full h-full"} + [:fieldset {:class "hx-disable h-full"} + (com/modal-card + {} + [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name entity)]] + [:div.space-y-6 + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (fc/with-field :user/role + (com/validated-field {:label "Role" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :class "w-36" + :autofocus true + :value (some->> (fc/field-value) name) + :options (ref->select-options "user-role")}))) + (fc/with-field :user/clients + (com/validated-field {:label "Clients"} + (com/data-grid {:headers [(com/data-grid-header {} "Client") + (com/data-grid-header {})] + :id "client-table"} + (fc/cursor-map #(client-row* %)) + (com/data-grid-new-row {:colspan 2 + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes + :user-client-new)} + "Assign new client"))))] + [:div + (com/form-errors {:errors (:errors fc/*form-errors*)}) + (com/validated-save-button {:errors (seq form-errors)} + "Save user")])]]))) (defn user-edit-save [{:keys [form-params identity] :as request}] (let [_ @(dc/transact conn [[:upsert-entity form-params]]) diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 6967e630..2682ec75 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -1,15 +1,25 @@ (ns auto-ap.ssr.utils - (:require - [auto-ap.datomic :refer [all-schema conn]] - [auto-ap.logging :as alog] - [clojure.string :as str] - [config.core :refer [env]] - [datomic.api :as dc] - [hiccup2.core :as hiccup] - [malli.core :as mc] - [malli.error :as me] - [malli.transform :as mt2] - [slingshot.slingshot :refer [throw+ try+]])) + (:require [auto-ap.datomic :refer [all-schema conn]] + [auto-ap.logging :as alog] + [auto-ap.time :as atime] + [clj-time.coerce :as coerce] + [clj-time.core :as time] + [clojure.string :as str] + [datomic.api :as dc] + [hiccup2.core :as hiccup] + [hiccup.compiler :refer [HtmlRenderer render-html]] + [malli.core :as mc] + [malli.core :as m] + [malli.error :as me] + [malli.registry :as mr] + [malli.transform :as mt2] + [slingshot.slingshot :refer [throw+ try+]] + [taoensso.encore :refer [filter-vals]])) + +(defrecord OOBElements [elements] + HtmlRenderer + (render-html [this] + (str/join "\n" (map render-html elements)))) (defn html-response [hiccup & {:keys [status headers oob] :or {status 200 headers {} oob []}}] {:status status @@ -33,7 +43,17 @@ [hiccup] (mapcat identity (-> opts - (assoc-in [:headers "hx-trigger"] "modalopen") + (update-in [:headers "hx-trigger"] (fn [ht] (str/join ", " (filter identity [ht "modalopen"])))) + (assoc-in [:headers "hx-retarget"] "#modal-content") + (assoc-in [:headers "hx-reswap"] "innerHTML")))))) + +(defn modal-replace-response [hiccup & {:as opts}] + (apply html-response + (into + [hiccup] + (mapcat identity + (-> opts + (assoc-in [:headers "hx-trigger"] "modalswap") (assoc-in [:headers "hx-retarget"] "#modal-content") (assoc-in [:headers "hx-reswap"] "innerHTML")))))) @@ -96,11 +116,17 @@ :long empty->nil 'nat-int? empty->nil}})) -(def entity-id (mc/schema [nat-int? {:error/message "required" - :decode/arbitrary (fn [e] - (if (and (map? e) (:db/id e)) - (:db/id e) - e))}])) +(def raw-entity-id [nat-int? {:error/message "required" + :decode/arbitrary (fn [e] + (if (and (map? e) (:db/id e)) + (:db/id e) + e))}]) + +(def entity-id (mc/schema [nat-int? {:error/message "required" + :decode/arbitrary (fn [e] + (if (and (map? e) (:db/id e)) + (:db/id e) + e))}])) (def temp-id (mc/schema [:string {:min 1}])) (def money (mc/schema [:double])) @@ -125,7 +151,7 @@ (if (sequential? x) x (into [] - (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] + (for [[k v] (sort-by (comp #(Long/parseLong %) first) x)] v))))}) (defn many-entity [params & keys] @@ -158,13 +184,173 @@ (throw+ (ex-info m (merge data {:type :form-validation :form-validation-errors [m]})))) +(def clj-date-schema + (mc/schema [inst? {:date-format atime/normal-date}])) + +(def date-transformer + (mt2/transformer + {:decoders + {'inst? {:compile (fn [schema _] + (let [properties (mc/properties schema) + format (:format properties atime/normal-date)] + (fn [m] + (if (string? m) + (coerce/to-date-time (atime/parse m format)) + + m))))}} + :encoders + {'inst? + {:compile (fn [schema _] + (let [properties (mc/properties schema) + format (:format properties atime/normal-date)] + (fn [m] + (cond + (inst? m) + (atime/unparse-local (coerce/to-date-time m) format) + + (instance? org.joda.time.DateTime m) + (atime/unparse-local m format) + + :else + m))))}}})) + + + +(def date-range-transformer + (mt2/transformer {:decoders + {:map {:compile (fn [schema _] + (let [properties (mc/properties schema)] + (fn [m] + (if (:date-range properties) + (let [[date-range-key start-date-key end-date-key] (:date-range properties) + date-range-value (get m date-range-key)] + (if date-range-value + (-> (condp = date-range-value + "week" + (assoc m + start-date-key (time/plus (time/now) (time/days -7)) + end-date-key (time/now)) + + "month" + (assoc m + start-date-key (time/plus (time/now) (time/months -1)) + end-date-key (time/now)) + + "year" + (assoc m + start-date-key (time/plus (time/now) (time/years -1)) + end-date-key (time/now)) + + "all" + (assoc m start-date-key (time/plus (time/now) (time/years -3)) + end-date-key (time/now)) + + m) + (dissoc date-range-key)) + m)) + m))))}}})) + +(defn ->db-id [m] + (cond + (map? m) + (:db/id m) + (nat-int? m) + m + (and (string? m) (not-empty m)) + (Long/parseLong m) + + :else + m)) + +(def pull-transformer + (mt2/transformer {:decoders + {:entity-map + {:compile (fn [schema _] + (let [pull-expr (:pull (mc/properties schema))] + (if pull-expr + (fn pull-data [m] + (cond + (nat-int? m) + (dc/pull (dc/db conn) pull-expr m) + (and (string? m) (not-empty m)) + (dc/pull (dc/db conn) pull-expr (Long/parseLong m)) + :else + nil)) + identity)))}} + :encoders + {:entity-map + {:compile (fn [schema _] + (let [pull-expr (:pull (mc/properties schema))] + (if pull-expr + (fn pull-data [m] + (cond + (map? m) + (:db/id m) + (nat-int? m) + m + (and (string? m) (not-empty m)) + (Long/parseLong m) + + :else + m)) + identity)))}}})) + +(def coerce-vector + (mt2/transformer {:decoders {:vector {:compile (fn [schema _] + (when (:coerce? (m/properties schema)) + (fn [data] + (cond + (vector? data) + data + (sequential? data) + data + (and (map? data) + (every? #(try (Long/parseLong %) true (catch Exception _ false)) (keys data))) + (into [] (->> (keys data) + sort + (map data))) + (nil? data) + nil + :else + [data]))))}}})) + +(defn wrap-merge-prior-hx [handler] + (fn [{:keys [headers] :as request}] + (let [is-htmx-that-should-inherit-url-parameters? (and (not (get headers "hx-boosted")) + (get headers "hx-request"))] + (alog/peek ::check {:enabled? is-htmx-that-should-inherit-url-parameters? + :params (:query-params request)}) + + (if is-htmx-that-should-inherit-url-parameters? + (handler (update request :query-params (fn [qp] + (->> (concat (:hx-query-params request) qp) + (into {}))))) + (handler request))))) + + +(def dissoc-nil-transformer + (let [e {:map {:compile (fn [schema _] + (fn [data] + (if (map? data) + (filter-vals + (fn [x] + (not (nil? x))) + data) + data)))}}] + (mt2/transformer {:encoders e + :decoders e}))) + (def main-transformer (mt2/transformer parse-empty-as-nil + date-transformer (mt2/key-transformer {:encode keyword->str :decode str->keyword}) mt2/string-transformer mt2/json-transformer (mt2/transformer {:name :arbitrary}) + coerce-vector + date-range-transformer + pull-transformer mt2/default-value-transformer)) (defn strip [s] @@ -192,7 +378,7 @@ :error {:explain (mc/explain schema entity)}})))) -(defn schema-enforce-request [{:keys [form-params query-params params] :as request} & {:keys [form-schema query-schema route-schema params-schema]}] +(defn schema-enforce-request [{:keys [form-params query-params hx-query-params params] :as request} & {:keys [form-schema hx-schema query-schema route-schema params-schema]}] (let [request (try (cond-> request (and (:params request) params-schema) @@ -216,6 +402,14 @@ form-params main-transformer)) + (and hx-schema hx-query-params) + (assoc :hx-query-params + (mc/coerce + hx-schema + hx-query-params + main-transformer)) + + (and query-schema query-params) (assoc :query-params (mc/coerce @@ -241,9 +435,10 @@ :error (:data (ex-data e))}))))] request)) -(defn wrap-schema-enforce [handler & {:keys [form-schema query-schema route-schema params-schema]}] +(defn wrap-schema-enforce [handler & {:keys [form-schema query-schema route-schema params-schema hx-schema]}] (fn [request] (handler (schema-enforce-request request + :hx-schema hx-schema :form-schema form-schema :query-schema query-schema :route-schema route-schema @@ -293,7 +488,10 @@ (into [:enum {:decode/string #(if (keyword? %) % (when (not-empty %) - (keyword n %)))}] + (keyword n %))) + :encode/string #(if (keyword? %) + (name %) + %)}] (for [{:db/keys [ident]} (all-schema) :when (= n (namespace ident))] ident))) @@ -375,4 +573,32 @@ (handler (if entity (assoc request :entity entity) - request))))) \ No newline at end of file + request))))) + +(mr/set-default-registry! + (mr/composite-registry + (mc/default-schemas) + {:entity-id entity-id + :entity-map + (mc/-simple-schema {:type :entity-map + :pred map?}) + #_[:map {:name :entity-map} [:db/id nat-int?]]})) + +(comment + + (mc/coerce [:map [:x {:optional true} [:maybe [:entity-map {:pull '[:db/id]}]]]] + {:x nil :g 1} + main-transformer) + + (mc/decode [:map [:x [:entity-map {:pull '[:db/id :db/ident]}]]] + {:x 87} + main-transformer)) + +(defn round-money [d] + (with-precision 2 + (double (.setScale (bigdec d) 2 java.math.RoundingMode/HALF_UP)))) + + +(defn wrap-implied-route-param [handler & {:as route-params}] + (fn [request] + (handler (update-in request [:route-params] merge route-params)))) \ No newline at end of file diff --git a/src/clj/user.clj b/src/clj/user.clj index 0e3e2818..0ce1ba08 100644 --- a/src/clj/user.clj +++ b/src/clj/user.clj @@ -19,6 +19,7 @@ [com.brunobonacci.mulog.buffer :as rb] [config.core :refer [env]] [datomic.api :as dc] + [puget.printer :as puget] [datomic.api :as d] [figwheel.main.api] [hawk.core] @@ -27,30 +28,32 @@ (:import (org.apache.commons.io.input BOMInputStream) [org.eclipse.jetty.server.handler.gzip GzipHandler])) - (defn println-event [item] - (printf "%s: %s - %s:%s by %s\n" - (str (c/to-date-time (:mulog/timestamp item))) - (:mulog/namespace item) (:mulog/event-name item) - (if (:mulog/duration item) - (str " " (int (/ (:mulog/duration item) 1000000)) "ms") - "") - (:user-name item)) - (println (reduce - (fn [acc [k v]] - (assoc acc k v)) - {} - (dissoc - item - :user))) - #_(puget/cprint (reduce - (fn [acc [k v]] - (assoc acc k v)) - {} - (dissoc - item - :user)) - {:seq-limit 10}) + #_(printf "%s: %s - %s:%s by %s\n" + (str (c/to-date-time (:mulog/timestamp item))) + (:mulog/namespace item) (:mulog/event-name item) + (if (:mulog/duration item) + (str " " (int (/ (:mulog/duration item) 1000000)) "ms") + "") + (:user-name item)) + #_(println (reduce + (fn [acc [k v]] + (assoc acc k v)) + {} + (dissoc + item + :user))) + (when (= :auto-ap.logging/peek (:mulog/event-name item)) + (println "\u001B[31mTEST") + ) + (puget/cprint (reduce + (fn [acc [k v]] + (assoc acc k v)) + {} + (dissoc + item + :user)) + {:seq-limit 10}) (println)) @@ -354,7 +357,7 @@ `src` or `resources`." [] (println "starting auto reset") - (hawk.core/watch! [{:paths ["src/"] + (hawk.core/watch! [{:paths ["src/" "test/"] :handler auto-reset-handler}])) diff --git a/src/clj/user.fiddle b/src/clj/user.fiddle index e0af7b6a..75b90a2f 100644 --- a/src/clj/user.fiddle +++ b/src/clj/user.fiddle @@ -150,7 +150,6 @@ {:db/id c :client/groups ["NTG"]})))) - (dc/q '[:find (count ?je) :in $$ :where [$$ ?je :journal-entry/client 17592238607837]] diff --git a/src/cljc/auto_ap/permissions.cljc b/src/cljc/auto_ap/permissions.cljc index ee183252..d1287f85 100644 --- a/src/cljc/auto_ap/permissions.cljc +++ b/src/cljc/auto_ap/permissions.cljc @@ -25,6 +25,24 @@ (#{:invoice-page :payment-page :my-company-page :transaction-page :ledger-page} subject) true + (= [:invoice :import] [subject activity]) + true + + (= [:invoice :create] [subject activity]) + true + + (= [:invoice :pay] [subject activity]) + true + + (= [:invoice :edit] [subject activity]) + true + + (= [:invoice :delete] [subject activity]) + true + + (= [:sales :read] [subject activity]) + true + (= [:vendor :create] [subject activity]) true @@ -44,6 +62,18 @@ (= [:vendor :edit] [subject activity]) true + (= [:invoice :create] [subject activity]) + true + + (= [:invoice :pay] [subject activity]) + true + + (= [:invoice :edit] [subject activity]) + true + + (= [:invoice :delete] [subject activity]) + true + :else false) (#{:user-role/read-only "read-only"} role) @@ -66,6 +96,19 @@ (= [:signature :edit] [subject activity]) true + + (= [:invoice :create] [subject activity]) + true + + (= [:invoice :pay] [subject activity]) + true + + (= [:invoice :edit] [subject activity]) + true + + (= [:invoice :delete] [subject activity]) + true + :else false) :else diff --git a/src/cljc/auto_ap/routes/invoice.cljc b/src/cljc/auto_ap/routes/invoice.cljc new file mode 100644 index 00000000..b6b19552 --- /dev/null +++ b/src/cljc/auto_ap/routes/invoice.cljc @@ -0,0 +1,32 @@ +(ns auto-ap.routes.invoice) +(def routes {"" {:get ::all-page + "/unpaid" ::unpaid-page + "/paid" ::paid-page + "/voided" ::voided-page} + "/new" {:get ::new-wizard + :post ::new-invoice-submit + :put ::new-invoice-submit + "/due-date" ::due-date + "/scheduled-payment-date" ::scheduled-payment-date + "/navigate" ::new-wizard-navigate + "/account/new" ::new-wizard-new-account + "/account/location-select" ::location-select + "/account/prediction" ::account-prediction + "/total" ::expense-account-total} + + "/pay-button" ::pay-button + "/pay" {:get ::pay-wizard + "/navigate" ::pay-wizard-navigate + :post ::pay-submit} + "/bulk-delete" {:get ::bulk-delete + :delete ::bulk-delete-confirm} + ["/" [#"\d+" :db/id]] {:delete ::delete + "/unvoid" ::unvoid + "/edit" ::edit-wizard} + "/table" ::table + + "/glimpse" {"" {:get :invoice-glimpse + :post :invoice-glimpse-upload + ["/" [#"\w+" :textract-invoice-id]] {:get :invoice-glimpse-textract-invoice + "/create" {:post :invoice-glimpse-create-invoice} + "/update" {:patch :invoice-glimpse-update-textract-invoice}}}}}) diff --git a/src/cljc/auto_ap/routes/outgoing_invoice.cljc b/src/cljc/auto_ap/routes/outgoing_invoice.cljc new file mode 100644 index 00000000..cef47a0f --- /dev/null +++ b/src/cljc/auto_ap/routes/outgoing_invoice.cljc @@ -0,0 +1,4 @@ +(ns auto-ap.routes.outgoing-invoice) +(def routes {"/" {"new" {:get ::new + :post ::new-submit} + "line-item/new" {:get ::new-line-item}}}) \ No newline at end of file diff --git a/src/cljc/auto_ap/routes/payments.cljc b/src/cljc/auto_ap/routes/payments.cljc new file mode 100644 index 00000000..7014784e --- /dev/null +++ b/src/cljc/auto_ap/routes/payments.cljc @@ -0,0 +1,9 @@ +(ns auto-ap.routes.payments) +(def routes {"" {:get ::all-page + "/pending" ::pending-page + "/voided" ::voided-page + "/cleared" ::cleared-page} + "/bulk-delete" {:get ::bulk-delete + :delete ::bulk-delete-confirm} + ["/" [#"\d+" :db/id]] {:delete ::delete} + "/table" ::table}) diff --git a/src/cljc/auto_ap/ssr_routes.cljc b/src/cljc/auto_ap/ssr_routes.cljc index 5888e8fe..8d63b197 100644 --- a/src/cljc/auto_ap/ssr_routes.cljc +++ b/src/cljc/auto_ap/ssr_routes.cljc @@ -4,6 +4,9 @@ [auto-ap.routes.admin.import-batch :as ib-routes] [auto-ap.routes.indicators :as indicator-routes] [auto-ap.routes.admin.vendors :as v-routes] + [auto-ap.routes.outgoing-invoice :as oi-routes] + [auto-ap.routes.payments :as p-routes] + [auto-ap.routes.invoice :as i-routes] [auto-ap.routes.admin.clients :as ac-routes] [auto-ap.routes.admin.sales-summaries :as ss-routes] [auto-ap.routes.admin.transaction-rules :as tr-routes])) @@ -12,11 +15,7 @@ "logout" :logout "search" :search "indicators" indicator-routes/routes - "invoice" {"/glimpse" {"" {:get :invoice-glimpse - :post :invoice-glimpse-upload - ["/" [#"\w+" :textract-invoice-id]] {:get :invoice-glimpse-textract-invoice - "/create" {:post :invoice-glimpse-create-invoice} - "/update" {:patch :invoice-glimpse-update-textract-invoice}}}}} + "account" {"/search" {:get :account-search}} "admin" {"" :auto-ap.routes.admin/page "/client" ac-routes/routes @@ -66,6 +65,9 @@ "/cash-drawer-shifts" {"" {:get :pos-cash-drawer-shifts} "/table" {:get :pos-cash-drawer-shift-table}}} + "outgoing-invoice" oi-routes/routes + "payment" p-routes/routes + "invoice" i-routes/routes "vendor" {"/search" :vendor-search} ;; TODO Include IDS in routes for company-specific things, as opposed to headers "company" {"" :company diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index bf757c4a..2a35bbd2 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -2,6 +2,7 @@ (:require [auto-ap.events :as events] [auto-ap.routes :as routes] [auto-ap.subs :as subs] + [auto-ap.routes.payments :as payment-routes] [auto-ap.status :as status] [auto-ap.views.components.buttons :as buttons] [auto-ap.views.components.dropdown @@ -17,7 +18,8 @@ [goog.string :as gstring] [re-frame.core :as re-frame] [auto-ap.views.components.expense-accounts-dialog :as expense-accounts-dialog] - [auto-ap.views.pages.data-page :as data-page])) + [auto-ap.views.pages.data-page :as data-page] + [auto-ap.ssr-routes :as ssr-routes])) (defn data-params->query-params [params] (if (:exact-match-id params) @@ -195,7 +197,7 @@ [:td (:post-date (:transaction (:payment invoice-payment)))] [:td [buttons/fa-icon {:icon "fa-external-link" - :href (str (bidi/path-for routes/routes :payments ) + :href (str (bidi/path-for ssr-routes/only-routes ::payment-routes/page ) "?" (url/map->query {:exact-match-id (:id (:payment invoice-payment))}))}]]]) (when source-url diff --git a/src/cljs/auto_ap/views/components/layouts.cljs b/src/cljs/auto_ap/views/components/layouts.cljs index ca216162..a555e0a4 100644 --- a/src/cljs/auto_ap/views/components/layouts.cljs +++ b/src/cljs/auto_ap/views/components/layouts.cljs @@ -6,6 +6,8 @@ [auto-ap.forms.builder :as form-builder] [auto-ap.routes :as routes] [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.routes.payments :as payment-routes] + [auto-ap.routes.invoice :as invoice-routes] [auto-ap.subs :as subs] [auto-ap.views.components.modal :as modal] [auto-ap.views.components.search :as search] @@ -175,11 +177,11 @@ "Home" ] (when (p/can? @user {:subject :invoice-page}) [:a.navbar-item {:class [(active-when ap #{:unpaid-invoices :paid-invoices})] - :href (bidi/path-for routes/routes :unpaid-invoices)} + :href (str (bidi/path-for ssr-routes/only-routes ::invoice-routes/all-page) "?date-range=month")} "Invoices" ]) (when (p/can? @user {:subject :payment-page}) [:a.navbar-item {:class [(active-when ap = :payments)] - :href (bidi/path-for routes/routes :payments)} + :href (str (bidi/path-for ssr-routes/only-routes ::payment-routes/all-page) "?date-range=month")} "Payments" ]) (when (p/can? @user {:subject :pos-page}) [:a.navbar-item {:class [(active-when ap = :pos-sales)] diff --git a/src/cljs/auto_ap/views/pages/transactions/table.cljs b/src/cljs/auto_ap/views/pages/transactions/table.cljs index 4dd59416..3d78fb88 100644 --- a/src/cljs/auto_ap/views/pages/transactions/table.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/table.cljs @@ -1,25 +1,22 @@ (ns auto-ap.views.pages.transactions.table - (:require - [auto-ap.events :as events] - [auto-ap.routes :as routes] - [auto-ap.status :as status] - [auto-ap.subs :as subs] - [auto-ap.views.components.buttons :as buttons] - [auto-ap.views.components.dropdown - :refer [drop-down drop-down-contents]] - [auto-ap.views.components.grid :as grid] - [auto-ap.views.pages.data-page :as data-page] - [auto-ap.views.pages.transactions.form :as edit] - [auto-ap.views.utils - :refer [action-cell-width - date->str - dispatch-event-with-propagation - nf - pretty - with-role]] - [bidi.bidi :as bidi] - [cemerick.url :as url] - [re-frame.core :as re-frame])) + (:require [auto-ap.events :as events] + [auto-ap.routes :as routes] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.status :as status] + [auto-ap.routes.payments :as payment-route] + [auto-ap.subs :as subs] + [auto-ap.views.components.buttons :as buttons] + [auto-ap.views.components.dropdown + :refer [drop-down drop-down-contents]] + [auto-ap.views.components.grid :as grid] + [auto-ap.views.pages.data-page :as data-page] + [auto-ap.views.pages.transactions.form :as edit] + [auto-ap.views.utils + :refer [action-cell-width date->str dispatch-event-with-propagation nf + pretty with-role]] + [bidi.bidi :as bidi] + [cemerick.url :as url] + [re-frame.core :as re-frame])) (re-frame/reg-event-fx ::editing-matches-found @@ -133,7 +130,7 @@ [:td (date->str (:date payment) pretty)] [:td [buttons/fa-icon {:icon "fa-external-link" - :href (str (bidi/path-for routes/routes :payments) + :href (str (bidi/path-for ssr-routes/only-routes ::payment-route/page) "?" (url/map->query {:exact-match-id (:id payment)}))}]]]) (when expected-deposit diff --git a/start-solr.sh b/start-solr.sh index dc219f7a..d79437ee 100755 --- a/start-solr.sh +++ b/start-solr.sh @@ -1,5 +1,5 @@ #!/bin/bash #sudo docker run --rm -ti -v ~/dev/integreat/data/solr:/var/solr --network=bridge -p 8983:8983 solr -sudo podman container run --user 1000 --privileged --volume /home/notid/dev/integreat/data/solr:/var/solr -p 8983:8983 solr +sudo podman container run --user 1000 --privileged --volume /home/notid/dev/integreat/data/solr:/var/solr -p 8983:8983 docker.io/solr diff --git a/tailwind.config.js b/tailwind.config.js index 2055a69a..feca3add 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -19,9 +19,24 @@ module.exports = { '87.5%': { transform: 'translateX(5px)' }, '100%': { transform: 'translateX(0px)' }, }, + gentleGrow: { + "0%": { + "transform": "scale(1.0)", + "animation-timing-function": "cubic-bezier(0.8, 0, 1, 1)" + }, + "50%": { + "transform": "scale(1.1)", + "animation-timing-function": "cubic-bezier(0, 0, 0.2, 1)" + }, + "100%": { + "transform": "scale(1.0)", + "animation-timing-function": "cubic-bezier(0.8, 0, 1, 1)" + } + } }, animation: { 'shake': 'shake 0.5s ease-out 1', + "gg": "gentleGrow 1s infinite" }, "fontFamily": { "sans": ["Calibri", "ui-sans-serif", "system-ui", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"] diff --git a/terraform/connect-ports-cloud-staging.sh b/terraform/connect-ports-cloud-staging.sh new file mode 100755 index 00000000..77db7143 --- /dev/null +++ b/terraform/connect-ports-cloud-staging.sh @@ -0,0 +1,2 @@ +#!/bin/sh +ssh -L 2049:172.31.32.90:2049 3.213.115.86 -L 8983:solr-staging.local:8983 -L 4334:integreat-datomic.local:4334 -L9001:integreat-app-staging.local:9000 diff --git a/terraform/connect-ports-cloud.sh b/terraform/connect-ports-cloud.sh index 730ea7af..ede6c7fc 100755 --- a/terraform/connect-ports-cloud.sh +++ b/terraform/connect-ports-cloud.sh @@ -1,2 +1,2 @@ #!/bin/sh -ssh -L 2049:172.31.32.90:2049 3.213.115.86 -L 8983:solr-prod.local:8983 -L 4334:integreat-datomic.local:4334 +ssh -L 2049:172.31.32.90:2049 3.213.115.86 -L 8983:solr-prod.local:8983 -L 4334:integreat-datomic.local:4334 -L9001:integreat-app-prod.local:9000 diff --git a/terraform/staging-solr-taskdef.json b/terraform/staging-solr-taskdef.json index 9ef140f9..ae8a891d 100644 --- a/terraform/staging-solr-taskdef.json +++ b/terraform/staging-solr-taskdef.json @@ -3,7 +3,7 @@ "environment": [ { "name": "DD_ENV", - "value": "prod" + "value": "staging" }, { "name": "DD_SERVICE", @@ -16,13 +16,13 @@ "logConfiguration": { "logDriver": "awslogs", "options": { - "awslogs-group": "/ecs/solr-prod", + "awslogs-group": "/ecs/solr-staging", "awslogs-region": "us-east-1", "awslogs-stream-prefix": "ecs" } }, "dockerLabels": { - "com.datadoghq.tags.env": "prod", + "com.datadoghq.tags.env": "staging", "com.datadoghq.tags.service": "solr" }, "mountPoints": [], diff --git a/terraform/terraform.tfstate.d/staging/terraform.tfstate b/terraform/terraform.tfstate.d/staging/terraform.tfstate index d7372951..70b2bc4a 100644 --- a/terraform/terraform.tfstate.d/staging/terraform.tfstate +++ b/terraform/terraform.tfstate.d/staging/terraform.tfstate @@ -1,10 +1,1391 @@ { "version": 4, - "terraform_version": "1.4.6", - "serial": 139, + "terraform_version": "1.7.5", + "serial": 216, "lineage": "91d10fe0-8033-8778-c202-78d5a81632e8", - "outputs": {}, + "outputs": { + "aws_access_key_id": { + "value": "AKIAZ4TSKSJ2TMDQ3WFK", + "type": "string", + "sensitive": true + }, + "aws_default_region": { + "value": "us-east-1", + "type": "string" + }, + "aws_secret_access_key": { + "value": "VZHxF3iX2DpP1yCKGmV6qJmprs9LqrETDmKMePbk", + "type": "string", + "sensitive": true + }, + "queue_url": { + "value": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging", + "type": "string" + } + }, "resources": [ + { + "mode": "data", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "account_id": "679918342773", + "arn": "arn:aws:iam::679918342773:user/bryce", + "id": "679918342773", + "user_id": "AIDAJPUJFTOKO4IRADMV4" + }, + "sensitive_attributes": [] + } + ] + }, + { + "mode": "data", + "type": "aws_iam_policy_document", + "name": "toast_policy_doc", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "499479035", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:*\",\n \"Resource\": [\n \"arn:aws:s3:::toast.staging.app.integreatconsult.com/*\",\n \"arn:aws:s3:::toast.staging.app.integreatconsult.com\"\n ],\n \"Principal\": {\n \"AWS\": [\n \"arn:aws:iam::679918342773:role/http-proxy\",\n \"arn:aws:iam::679918342773:role/datomic-ddb\"\n ]\n }\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "s3:*" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "arn:aws:iam::679918342773:role/datomic-ddb", + "arn:aws:iam::679918342773:role/http-proxy" + ], + "type": "AWS" + } + ], + "resources": [ + "arn:aws:s3:::toast.staging.app.integreatconsult.com", + "arn:aws:s3:::toast.staging.app.integreatconsult.com/*" + ], + "sid": "" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "mode": "managed", + "type": "aws_acm_certificate", + "name": "cert", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:acm:us-east-1:679918342773:certificate/ca150186-1e27-4321-b23f-d934211de8b8", + "certificate_authority_arn": "", + "certificate_body": null, + "certificate_chain": null, + "domain_name": "staging3.app.integreatconsult.com", + "domain_validation_options": [ + { + "domain_name": "staging3.app.integreatconsult.com", + "resource_record_name": "_469d48ffed86c3b36df870ed56721086.staging3.app.integreatconsult.com.", + "resource_record_type": "CNAME", + "resource_record_value": "_7e6747707e32a59a81055222c94098d0.zdxcnfdgtt.acm-validations.aws." + } + ], + "early_renewal_duration": "", + "id": "arn:aws:acm:us-east-1:679918342773:certificate/ca150186-1e27-4321-b23f-d934211de8b8", + "key_algorithm": "RSA_2048", + "not_after": "2025-04-20T23:59:59Z", + "not_before": "2024-03-21T00:00:00Z", + "options": [ + { + "certificate_transparency_logging_preference": "ENABLED" + } + ], + "pending_renewal": false, + "private_key": null, + "renewal_eligibility": "ELIGIBLE", + "renewal_summary": [], + "status": "ISSUED", + "subject_alternative_names": [ + "staging3.app.integreatconsult.com" + ], + "tags": {}, + "tags_all": {}, + "type": "AMAZON_ISSUED", + "validation_emails": [], + "validation_method": "DNS", + "validation_option": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_acm_certificate", + "name": "data_cert", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:acm:us-east-1:679918342773:certificate/2444dddf-c3f5-4638-8f63-98edc35f36d0", + "certificate_authority_arn": "", + "certificate_body": null, + "certificate_chain": null, + "domain_name": "data.staging.app.integreatconsult.com", + "domain_validation_options": [ + { + "domain_name": "data.staging.app.integreatconsult.com", + "resource_record_name": "_77ae6550c5d5ab752ecb52f05de9a4e4.data.staging.app.integreatconsult.com.", + "resource_record_type": "CNAME", + "resource_record_value": "_d8b38342271f96bebc65dffa37c1762e.mhbtsbpdnt.acm-validations.aws." + } + ], + "early_renewal_duration": "", + "id": "arn:aws:acm:us-east-1:679918342773:certificate/2444dddf-c3f5-4638-8f63-98edc35f36d0", + "key_algorithm": "RSA_2048", + "not_after": "", + "not_before": "", + "options": [ + { + "certificate_transparency_logging_preference": "ENABLED" + } + ], + "pending_renewal": false, + "private_key": null, + "renewal_eligibility": "INELIGIBLE", + "renewal_summary": [], + "status": "PENDING_VALIDATION", + "subject_alternative_names": [ + "data.staging.app.integreatconsult.com" + ], + "tags": {}, + "tags_all": {}, + "type": "AMAZON_ISSUED", + "validation_emails": [], + "validation_method": "DNS", + "validation_option": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_service", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "alarms": [], + "capacity_provider_strategy": [ + { + "base": 1, + "capacity_provider": "FARGATE_SPOT", + "weight": 5 + } + ], + "cluster": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "deployment_circuit_breaker": [ + { + "enable": false, + "rollback": false + } + ], + "deployment_controller": [ + { + "type": "ECS" + } + ], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": 0, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_new_deployment": null, + "health_check_grace_period_seconds": 600, + "iam_role": "/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS", + "id": "arn:aws:ecs:us-east-1:679918342773:service/default/integreat_app_staging", + "launch_type": "", + "load_balancer": [ + { + "container_name": "integreat-app", + "container_port": 3000, + "elb_name": "", + "target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9" + } + ], + "name": "integreat_app_staging", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-16161a39", + "subnet-323deb78", + "subnet-44c2774b", + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "LATEST", + "propagate_tags": "NONE", + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [ + { + "container_name": "", + "container_port": 0, + "port": 0, + "registry_arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-nsn252bfk4r6bzpj" + } + ], + "tags": {}, + "tags_all": {}, + "task_definition": "arn:aws:ecs:us-east-1:679918342773:task-definition/integreat_app_staging:162", + "timeouts": { + "create": null, + "delete": null, + "update": null + }, + "triggers": {}, + "wait_for_steady_state": true + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_ecs_task_definition.integreat_app", + "aws_lb_target_group.integreat_app", + "aws_service_discovery_service.service" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_service", + "name": "solr", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "alarms": [], + "capacity_provider_strategy": [ + { + "base": 1, + "capacity_provider": "FARGATE", + "weight": 5 + } + ], + "cluster": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "deployment_circuit_breaker": [ + { + "enable": false, + "rollback": false + } + ], + "deployment_controller": [ + { + "type": "ECS" + } + ], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": 1, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_new_deployment": null, + "health_check_grace_period_seconds": 0, + "iam_role": "/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS", + "id": "arn:aws:ecs:us-east-1:679918342773:service/default/solr_app_staging", + "launch_type": "", + "load_balancer": [], + "name": "solr_app_staging", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "LATEST", + "propagate_tags": "NONE", + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [ + { + "container_name": "", + "container_port": 0, + "port": 0, + "registry_arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-s7tr2j6rcazkgsxp" + } + ], + "tags": null, + "tags_all": {}, + "task_definition": "arn:aws:ecs:us-east-1:679918342773:task-definition/solr_staging:2", + "timeouts": { + "create": null, + "delete": null, + "update": null + }, + "triggers": {}, + "wait_for_steady_state": true + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_ecs_task_definition.solr", + "aws_efs_file_system.solr_storage", + "aws_service_discovery_service.solr" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/integreat_app_staging:162", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/integreat_app_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"integreat-app\"},\"environment\":[{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"integreat-app\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-staging\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":3000,\"hostPort\":3000,\"protocol\":\"tcp\"},{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "4096", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "integreat_app_staging", + "id": "integreat_app_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "16384", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 162, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "solr", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/solr_staging:2", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/solr_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"solr\"},\"environment\":[{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"solr\"}],\"essential\":true,\"image\":\"solr\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/solr-staging\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[{\"containerPath\":\"/var/solr\",\"readOnly\":false,\"sourceVolume\":\"solr-storage\"}],\"name\":\"solr\",\"portMappings\":[{\"containerPort\":8983,\"hostPort\":8983,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "solr_staging", + "id": "solr_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 2, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [], + "file_system_id": "fs-0486d889f5a7706e8", + "root_directory": "/", + "transit_encryption": "", + "transit_encryption_port": null + } + ], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "", + "name": "solr-storage" + } + ] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "aws_efs_file_system.solr_storage" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_efs_file_system", + "name": "solr_storage", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:elasticfilesystem:us-east-1:679918342773:file-system/fs-0486d889f5a7706e8", + "availability_zone_id": "", + "availability_zone_name": "", + "creation_token": "solr_storage-staging", + "dns_name": "fs-0486d889f5a7706e8.efs.us-east-1.amazonaws.com", + "encrypted": false, + "id": "fs-0486d889f5a7706e8", + "kms_key_id": "", + "lifecycle_policy": [], + "number_of_mount_targets": 6, + "owner_id": "679918342773", + "performance_mode": "generalPurpose", + "provisioned_throughput_in_mibps": 0, + "size_in_bytes": [ + { + "value": 6144, + "value_in_ia": 0, + "value_in_standard": 6144 + } + ], + "tags": { + "Name": "solr_storage_staging" + }, + "tags_all": { + "Name": "solr_storage_staging" + }, + "throughput_mode": "bursting" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_access_key", + "name": "app_user", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "create_date": "2024-03-21T05:39:43Z", + "encrypted_secret": null, + "encrypted_ses_smtp_password_v4": null, + "id": "AKIAZ4TSKSJ2TMDQ3WFK", + "key_fingerprint": null, + "pgp_key": null, + "secret": "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", + "ses_smtp_password_v4": "BMYut7OzUgr5EKH3LCZDjTFk3X8rm7MdReTojaFulVgA", + "status": "Active", + "user": "integreat-staging" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_iam_user.app_user" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_user", + "name": "app_user", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::679918342773:user/integreat-staging", + "force_destroy": false, + "id": "integreat-staging", + "name": "integreat-staging", + "path": "/", + "permissions_boundary": null, + "tags": {}, + "tags_all": {}, + "unique_id": "AIDAZ4TSKSJ2SDDJ5OMWV" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_user_policy_attachment", + "name": "app_user_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "integreat-staging-20240321053943002300000005", + "policy_arn": "arn:aws:iam::aws:policy/AdministratorAccess", + "user": "integreat-staging" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_iam_user.app_user" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "access_logs": [ + { + "bucket": "", + "enabled": false, + "prefix": "" + } + ], + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "arn_suffix": "app/integreat-app-staging/d65758eb97c8e4e5", + "customer_owned_ipv4_pool": "", + "desync_mitigation_mode": "defensive", + "dns_name": "integreat-app-staging-1122841226.us-east-1.elb.amazonaws.com", + "drop_invalid_header_fields": false, + "enable_cross_zone_load_balancing": true, + "enable_deletion_protection": true, + "enable_http2": true, + "enable_tls_version_and_cipher_suite_headers": false, + "enable_waf_fail_open": false, + "enable_xff_client_port": false, + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "idle_timeout": 120, + "internal": false, + "ip_address_type": "ipv4", + "load_balancer_type": "application", + "name": "integreat-app-staging", + "name_prefix": null, + "preserve_host_header": false, + "security_groups": [ + "sg-0024906e0e1f78048" + ], + "subnet_mapping": [ + { + "allocation_id": "", + "ipv6_address": "", + "outpost_id": "", + "private_ipv4_address": "", + "subnet_id": "subnet-16161a39" + }, + { + "allocation_id": "", + "ipv6_address": "", + "outpost_id": "", + "private_ipv4_address": "", + "subnet_id": "subnet-323deb78" + }, + { + "allocation_id": "", + "ipv6_address": "", + "outpost_id": "", + "private_ipv4_address": "", + "subnet_id": "subnet-44c2774b" + }, + { + "allocation_id": "", + "ipv6_address": "", + "outpost_id": "", + "private_ipv4_address": "", + "subnet_id": "subnet-5e675761" + }, + { + "allocation_id": "", + "ipv6_address": "", + "outpost_id": "", + "private_ipv4_address": "", + "subnet_id": "subnet-8519fde2" + }, + { + "allocation_id": "", + "ipv6_address": "", + "outpost_id": "", + "private_ipv4_address": "", + "subnet_id": "subnet-89bab8d4" + } + ], + "subnets": [ + "subnet-16161a39", + "subnet-323deb78", + "subnet-44c2774b", + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ], + "tags": {}, + "tags_all": {}, + "timeouts": null, + "vpc_id": "vpc-b5b7d6ce", + "xff_header_processing_mode": "append", + "zone_id": "Z35SXDOTRQ7X7K" + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6NjAwMDAwMDAwMDAwLCJ1cGRhdGUiOjYwMDAwMDAwMDAwMH19" + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_listener", + "name": "http", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "alpn_policy": null, + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/198d2d83a47036f2", + "certificate_arn": null, + "default_action": [ + { + "authenticate_cognito": [], + "authenticate_oidc": [], + "fixed_response": [], + "forward": [], + "order": 1, + "redirect": [ + { + "host": "#{host}", + "path": "/#{path}", + "port": "443", + "protocol": "HTTPS", + "query": "#{query}", + "status_code": "HTTP_301" + } + ], + "target_group_arn": "", + "type": "redirect" + } + ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/198d2d83a47036f2", + "load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "port": 80, + "protocol": "HTTP", + "ssl_policy": "", + "tags": {}, + "tags_all": {}, + "timeouts": { + "read": null + } + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsicmVhZCI6NjAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "aws_lb.integreat_app" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_listener", + "name": "https", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "alpn_policy": null, + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8", + "certificate_arn": "arn:aws:acm:us-east-1:679918342773:certificate/ca150186-1e27-4321-b23f-d934211de8b8", + "default_action": [ + { + "authenticate_cognito": [], + "authenticate_oidc": [], + "fixed_response": [], + "forward": [], + "order": 1, + "redirect": [], + "target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9", + "type": "forward" + } + ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8", + "load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "port": 443, + "protocol": "HTTPS", + "ssl_policy": "ELBSecurityPolicy-2016-08", + "tags": {}, + "tags_all": {}, + "timeouts": { + "read": null + } + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsicmVhZCI6NjAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "aws_acm_certificate.cert", + "aws_lb.integreat_app", + "aws_lb_target_group.integreat_app" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_listener_rule", + "name": "static", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "action": [ + { + "authenticate_cognito": [], + "authenticate_oidc": [], + "fixed_response": [], + "forward": [], + "order": 1, + "redirect": [ + { + "host": "s3.amazonaws.com", + "path": "/staging3.app.integreatconsult.com/#{path}", + "port": "443", + "protocol": "HTTPS", + "query": "#{query}", + "status_code": "HTTP_301" + } + ], + "target_group_arn": "", + "type": "redirect" + } + ], + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener-rule/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8/4cefe09d0fb96f84", + "condition": [ + { + "host_header": [], + "http_header": [], + "http_request_method": [], + "path_pattern": [ + { + "values": [ + "/css/*", + "/finance-font/*", + "/img/*", + "/js/compiled/*", + "index.html" + ] + } + ], + "query_string": [], + "source_ip": [] + } + ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener-rule/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8/4cefe09d0fb96f84", + "listener_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8", + "priority": 1, + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_acm_certificate.cert", + "aws_lb.integreat_app", + "aws_lb_listener.https", + "aws_lb_target_group.integreat_app" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_target_group", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9", + "arn_suffix": "targetgroup/integreat-app-staging/a8cd2c002073aec9", + "connection_termination": false, + "deregistration_delay": "120", + "health_check": [ + { + "enabled": true, + "healthy_threshold": 2, + "interval": 60, + "matcher": "200", + "path": "/api/health-check", + "port": "traffic-port", + "protocol": "HTTP", + "timeout": 14, + "unhealthy_threshold": 3 + } + ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9", + "ip_address_type": "ipv4", + "lambda_multi_value_headers_enabled": false, + "load_balancing_algorithm_type": "round_robin", + "load_balancing_cross_zone_enabled": "use_load_balancer_configuration", + "name": "integreat-app-staging", + "name_prefix": null, + "port": 80, + "preserve_client_ip": null, + "protocol": "HTTP", + "protocol_version": "HTTP1", + "proxy_protocol_v2": false, + "slow_start": 0, + "stickiness": [ + { + "cookie_duration": 86400, + "cookie_name": "", + "enabled": false, + "type": "lb_cookie" + } + ], + "tags": {}, + "tags_all": {}, + "target_failover": [ + { + "on_deregistration": null, + "on_unhealthy": null + } + ], + "target_type": "ip", + "vpc_id": "vpc-b5b7d6ce" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "data", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "status": "tainted", + "schema_version": 0, + "attributes": { + "acceleration_status": null, + "acl": "private", + "arn": null, + "bucket": "data.staging.app.integreatconsult.com", + "bucket_domain_name": null, + "bucket_prefix": null, + "bucket_regional_domain_name": null, + "cors_rule": null, + "force_destroy": false, + "grant": [], + "hosted_zone_id": null, + "id": "data.staging.app.integreatconsult.com", + "lifecycle_rule": null, + "logging": null, + "object_lock_configuration": null, + "object_lock_enabled": null, + "policy": "{\"Id\":\"Policy1526084187222\",\"Statement\":[{\"Action\":[\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com/*\",\"Sid\":\"Stmt1526084185514\"},{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com\",\"Sid\":\"AllowReadForProd\"},{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/http-proxy\"},\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com\",\"Sid\":\"AllowReadForProdProxy\"}],\"Version\":\"2012-10-17\"}", + "region": null, + "replication_configuration": null, + "request_payer": null, + "server_side_encryption_configuration": null, + "tags": null, + "tags_all": null, + "timeouts": null, + "versioning": null, + "website": [ + { + "error_document": "", + "index_document": "index.html", + "redirect_all_requests_to": "", + "routing_rules": "" + } + ], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "invoices", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::integreat-mail-staging", + "bucket": "integreat-mail-staging", + "bucket_domain_name": "integreat-mail-staging.s3.amazonaws.com", + "bucket_prefix": "", + "bucket_regional_domain_name": "integreat-mail-staging.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": false, + "grant": [ + { + "id": "e30528e0ba05fd1f250869c1b4db0eff90001b4d9ad90dd2e01b210844f83e5a", + "permissions": [ + "FULL_CONTROL" + ], + "type": "CanonicalUser", + "uri": "" + } + ], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "integreat-mail-staging", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "object_lock_enabled": false, + "policy": "{\"Statement\":[{\"Action\":\"s3:PutObject\",\"Condition\":{\"StringEquals\":{\"aws:Referer\":\"679918342773\"}},\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ses.amazonaws.com\"},\"Resource\":\"arn:aws:s3:::integreat-mail-staging/*\",\"Sid\":\"AllowSESPuts\"}],\"Version\":\"2012-10-17\"}", + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [ + { + "rule": [ + { + "apply_server_side_encryption_by_default": [ + { + "kms_master_key_id": "", + "sse_algorithm": "AES256" + } + ], + "bucket_key_enabled": false + } + ] + } + ], + "tags": {}, + "tags_all": {}, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "static", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "status": "tainted", + "schema_version": 0, + "attributes": { + "acceleration_status": null, + "acl": null, + "arn": null, + "bucket": "staging3.app.integreatconsult.com", + "bucket_domain_name": null, + "bucket_prefix": null, + "bucket_regional_domain_name": null, + "cors_rule": [ + { + "allowed_headers": [ + "*" + ], + "allowed_methods": [ + "PUT", + "POST", + "DELETE", + "GET" + ], + "allowed_origins": [ + "https://staging3.app.integreatconsult.com" + ], + "expose_headers": [], + "max_age_seconds": 0 + } + ], + "force_destroy": false, + "grant": [], + "hosted_zone_id": null, + "id": "staging3.app.integreatconsult.com", + "lifecycle_rule": null, + "logging": null, + "object_lock_configuration": null, + "object_lock_enabled": null, + "policy": "{\"Id\":\"Policy1526084187222\",\"Statement\":[{\"Action\":[\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::staging3.app.integreatconsult.com/*\",\"Sid\":\"Stmt1526084185514\"}],\"Version\":\"2012-10-17\"}", + "region": null, + "replication_configuration": null, + "request_payer": "BucketOwner", + "server_side_encryption_configuration": null, + "tags": null, + "tags_all": null, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [ + { + "error_document": "", + "index_document": "index.html", + "redirect_all_requests_to": "", + "routing_rules": "" + } + ], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "toast_bucket", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acceleration_status": "", + "acl": null, + "arn": "arn:aws:s3:::toast.staging.app.integreatconsult.com", + "bucket": "toast.staging.app.integreatconsult.com", + "bucket_domain_name": "toast.staging.app.integreatconsult.com.s3.amazonaws.com", + "bucket_prefix": "", + "bucket_regional_domain_name": "toast.staging.app.integreatconsult.com.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": false, + "grant": [ + { + "id": "e30528e0ba05fd1f250869c1b4db0eff90001b4d9ad90dd2e01b210844f83e5a", + "permissions": [ + "FULL_CONTROL" + ], + "type": "CanonicalUser", + "uri": "" + } + ], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "toast.staging.app.integreatconsult.com", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "object_lock_enabled": false, + "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"arn:aws:iam::679918342773:role/datomic-ddb\",\"arn:aws:iam::679918342773:role/http-proxy\"]},\"Resource\":[\"arn:aws:s3:::toast.staging.app.integreatconsult.com/*\",\"arn:aws:s3:::toast.staging.app.integreatconsult.com\"],\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}", + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [ + { + "rule": [ + { + "apply_server_side_encryption_by_default": [ + { + "kms_master_key_id": "", + "sse_algorithm": "AES256" + } + ], + "bucket_key_enabled": false + } + ] + } + ], + "tags": {}, + "tags_all": {}, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket_notification", + "name": "mail_bucket_notification", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "integreat-mail-staging", + "eventbridge": false, + "id": "integreat-mail-staging", + "lambda_function": [], + "queue": [ + { + "events": [ + "s3:ObjectCreated:*" + ], + "filter_prefix": "", + "filter_suffix": "", + "id": "tf-s3-queue-20240321054008457900000008", + "queue_arn": "arn:aws:sqs:us-east-1:679918342773:integreat-mail-staging" + } + ], + "topic": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.invoices", + "aws_sqs_queue.integreat-mail", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "toast_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "toast.staging.app.integreatconsult.com", + "id": "toast.staging.app.integreatconsult.com", + "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"arn:aws:iam::679918342773:role/http-proxy\",\"arn:aws:iam::679918342773:role/datomic-ddb\"]},\"Resource\":[\"arn:aws:s3:::toast.staging.app.integreatconsult.com/*\",\"arn:aws:s3:::toast.staging.app.integreatconsult.com\"],\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.toast_bucket", + "data.aws_iam_policy_document.toast_policy_doc" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_service_discovery_service", + "name": "service", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-nsn252bfk4r6bzpj", + "description": "", + "dns_config": [ + { + "dns_records": [ + { + "ttl": 10, + "type": "A" + } + ], + "namespace_id": "ns-gv2z744em7myo2jp", + "routing_policy": "MULTIVALUE" + } + ], + "force_destroy": false, + "health_check_config": [], + "health_check_custom_config": [ + { + "failure_threshold": 1 + } + ], + "id": "srv-nsn252bfk4r6bzpj", + "name": "integreat-app-staging", + "namespace_id": "ns-gv2z744em7myo2jp", + "tags": {}, + "tags_all": {}, + "type": "DNS_HTTP" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_service_discovery_service", + "name": "solr", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-s7tr2j6rcazkgsxp", + "description": "", + "dns_config": [ + { + "dns_records": [ + { + "ttl": 10, + "type": "A" + } + ], + "namespace_id": "ns-gv2z744em7myo2jp", + "routing_policy": "MULTIVALUE" + } + ], + "force_destroy": false, + "health_check_config": [], + "health_check_custom_config": [ + { + "failure_threshold": 1 + } + ], + "id": "srv-s7tr2j6rcazkgsxp", + "name": "solr-staging", + "namespace_id": "ns-gv2z744em7myo2jp", + "tags": {}, + "tags_all": {}, + "type": "DNS_HTTP" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_ses_receipt_rule", + "name": "store", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "add_header_action": [], + "after": null, + "arn": "arn:aws:ses:us-east-1:679918342773:receipt-rule-set/default-rule-set:receipt-rule/store-staging", + "bounce_action": [], + "enabled": true, + "id": "store-staging", + "lambda_action": [], + "name": "store-staging", + "recipients": [ + "invoices-staging@mail.app.integreatconsult.com" + ], + "rule_set_name": "default-rule-set", + "s3_action": [ + { + "bucket_name": "integreat-mail-staging", + "kms_key_arn": "", + "object_key_prefix": "", + "position": 1, + "topic_arn": "" + } + ], + "scan_enabled": true, + "sns_action": [], + "stop_action": [], + "tls_policy": "Optional", + "workmail_action": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.invoices", + "aws_ses_receipt_rule_set.main", + "data.aws_caller_identity.current" + ] + } + ] + }, { "mode": "managed", "type": "aws_ses_receipt_rule_set", @@ -21,6 +1402,1941 @@ "sensitive_attributes": [] } ] + }, + { + "mode": "managed", + "type": "aws_sqs_queue", + "name": "background-request", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:sqs:us-east-1:679918342773:integreat-background-request-staging", + "content_based_deduplication": false, + "deduplication_scope": "", + "delay_seconds": 0, + "fifo_queue": false, + "fifo_throughput_limit": "", + "id": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-background-request-staging", + "kms_data_key_reuse_period_seconds": 300, + "kms_master_key_id": "", + "max_message_size": 262144, + "message_retention_seconds": 345600, + "name": "integreat-background-request-staging", + "name_prefix": "", + "policy": "{\"Statement\":[{\"Action\":\"sqs:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:sqs:*:*:integreat-background-request-staging\"}],\"Version\":\"2012-10-17\"}", + "receive_wait_time_seconds": 0, + "redrive_allow_policy": "", + "redrive_policy": "", + "sqs_managed_sse_enabled": true, + "tags": {}, + "tags_all": {}, + "url": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-background-request-staging", + "visibility_timeout_seconds": 30 + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_sqs_queue", + "name": "integreat-mail", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:sqs:us-east-1:679918342773:integreat-mail-staging", + "content_based_deduplication": false, + "deduplication_scope": "", + "delay_seconds": 0, + "fifo_queue": false, + "fifo_throughput_limit": "", + "id": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging", + "kms_data_key_reuse_period_seconds": 300, + "kms_master_key_id": "", + "max_message_size": 262144, + "message_retention_seconds": 345600, + "name": "integreat-mail-staging", + "name_prefix": "", + "policy": "{\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"arn:aws:s3:::integreat-mail-staging\"}},\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:*:*:integreat-mail-staging\"}],\"Version\":\"2012-10-17\"}", + "receive_wait_time_seconds": 0, + "redrive_allow_policy": "", + "redrive_policy": "", + "sqs_managed_sse_enabled": true, + "tags": {}, + "tags_all": {}, + "url": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging", + "visibility_timeout_seconds": 30 + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.invoices", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_sqs_queue", + "name": "integreat-scheduled-jobs", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:sqs:us-east-1:679918342773:integreat-scheduled-jobs-staging", + "content_based_deduplication": false, + "deduplication_scope": "", + "delay_seconds": 0, + "fifo_queue": false, + "fifo_throughput_limit": "", + "id": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-scheduled-jobs-staging", + "kms_data_key_reuse_period_seconds": 300, + "kms_master_key_id": "", + "max_message_size": 262144, + "message_retention_seconds": 345600, + "name": "integreat-scheduled-jobs-staging", + "name_prefix": "", + "policy": "{\"Statement\":[{\"Action\":\"sqs:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:sqs:*:*:integreat-scheduled-jobs-staging\"}],\"Version\":\"2012-10-17\"}", + "receive_wait_time_seconds": 0, + "redrive_allow_policy": "", + "redrive_policy": "", + "sqs_managed_sse_enabled": true, + "tags": {}, + "tags_all": {}, + "url": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-scheduled-jobs-staging", + "visibility_timeout_seconds": 30 + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.bulk_journal_import_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/bulk_journal_import_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/bulk_journal_import_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"bulk-journal-import\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"bulk-journal-import\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"bulk-journal-import\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "bulk_journal_import_staging", + "id": "bulk_journal_import_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.close_auto_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/close-auto-invoices-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "close-auto-invoices-schedule", + "is_enabled": true, + "name": "close-auto-invoices-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(1 hour)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.close_auto_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/close_auto_invoices_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "close-auto-invoices-schedule-close-auto-invoices", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "close-auto-invoices-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "close-auto-invoices" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.close_auto_invoices_job.aws_cloudwatch_event_rule.schedule", + "module.close_auto_invoices_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.close_auto_invoices_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/close_auto_invoices_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/close_auto_invoices_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"close-auto-invoices\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"close-auto-invoices\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"close-auto-invoices\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "close_auto_invoices_staging", + "id": "close_auto_invoices_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.current_balance_cache", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/current-balance-cache-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "current-balance-cache-schedule", + "is_enabled": true, + "name": "current-balance-cache-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(60 minutes)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.current_balance_cache", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/current_balance_cache_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "current-balance-cache-schedule-current-balance-cache", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "current-balance-cache-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "current-balance-cache" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.current_balance_cache.aws_cloudwatch_event_rule.schedule", + "module.current_balance_cache.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.current_balance_cache", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/current_balance_cache_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/current_balance_cache_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"current-balance-cache\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"current-balance-cache\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"current-balance-cache\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "current_balance_cache_staging", + "id": "current_balance_cache_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.import_uploaded_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/import-uploaded-invoices-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "import-uploaded-invoices-schedule", + "is_enabled": true, + "name": "import-uploaded-invoices-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(1 hour)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.import_uploaded_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/import_uploaded_invoices_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "import-uploaded-invoices-schedule-import-uploaded-invoices", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "import-uploaded-invoices-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "import-uploaded-invoices" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.import_uploaded_invoices_job.aws_cloudwatch_event_rule.schedule", + "module.import_uploaded_invoices_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.import_uploaded_invoices_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/import_uploaded_invoices_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/import_uploaded_invoices_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"import-uploaded-invoices\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"import-uploaded-invoices\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"import-uploaded-invoices\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "import_uploaded_invoices_staging", + "id": "import_uploaded_invoices_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.insight_outcome_recommendation_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/insight-outcome-recommendation-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "insight-outcome-recommendation-schedule", + "is_enabled": true, + "name": "insight-outcome-recommendation-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.insight_outcome_recommendation_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/insight_outcome_recommendation_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "insight-outcome-recommendation-schedule-insight-outcome-recommendation", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "insight-outcome-recommendation-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "insight-outcome-recommendation" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.insight_outcome_recommendation_job.aws_cloudwatch_event_rule.schedule", + "module.insight_outcome_recommendation_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.insight_outcome_recommendation_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/insight_outcome_recommendation_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/insight_outcome_recommendation_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"insight-outcome-recommendation\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"insight-outcome-recommendation\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"insight-outcome-recommendation\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "2048", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "insight_outcome_recommendation_staging", + "id": "insight_outcome_recommendation_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.intuit_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/intuit-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "intuit-schedule", + "is_enabled": true, + "name": "intuit-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.intuit_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/intuit_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "intuit-schedule-intuit", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "intuit-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "intuit" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.intuit_job.aws_cloudwatch_event_rule.schedule", + "module.intuit_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.intuit_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/intuit_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/intuit_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"intuit\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"intuit\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"intuit\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "intuit_staging", + "id": "intuit_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.load_historical_sales_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/load_historical_sales_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/load_historical_sales_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"load-historical-sales\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"load-historical-sales\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"load-historical-sales\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "load_historical_sales_staging", + "id": "load_historical_sales_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.ntg_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/ntg-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "ntg-schedule", + "is_enabled": true, + "name": "ntg-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.ntg_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/ntg_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "ntg-schedule-ntg", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "ntg-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "ntg" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.ntg_job.aws_cloudwatch_event_rule.schedule", + "module.ntg_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.ntg_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/ntg_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/ntg_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"ntg\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"ntg\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"ntg\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "ntg_staging", + "id": "ntg_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.plaid_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/plaid-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "plaid-schedule", + "is_enabled": true, + "name": "plaid-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.plaid_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/plaid_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "plaid-schedule-plaid", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "plaid-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "plaid" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.plaid_job.aws_cloudwatch_event_rule.schedule", + "module.plaid_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.plaid_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/plaid_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/plaid_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"plaid\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"plaid\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"plaid\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "plaid_staging", + "id": "plaid_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.reconcile_ledger_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/reconcile-ledger-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "reconcile-ledger-schedule", + "is_enabled": true, + "name": "reconcile-ledger-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(1 hour)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.reconcile_ledger_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/reconcile_ledger_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "reconcile-ledger-schedule-reconcile-ledger", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "reconcile-ledger-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "reconcile-ledger" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.reconcile_ledger_job.aws_cloudwatch_event_rule.schedule", + "module.reconcile_ledger_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.reconcile_ledger_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/reconcile_ledger_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/reconcile_ledger_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"reconcile-ledger\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"reconcile-ledger\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"reconcile-ledger\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "2048", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "reconcile_ledger_staging", + "id": "reconcile_ledger_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "8192", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.register_invoice_import_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/register_invoice_import_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/register_invoice_import_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"register-invoice-import\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"register-invoice-import\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"register-invoice-import\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "2048", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "register_invoice_import_staging", + "id": "register_invoice_import_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "8192", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.square_import_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/square-import-job-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "square-import-job-schedule", + "is_enabled": true, + "name": "square-import-job-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(4 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.square_import_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/square_import_job_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "square-import-job-schedule-square-import-job", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "square-import-job-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "square-import-job" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.square_import_job.aws_cloudwatch_event_rule.schedule", + "module.square_import_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.square_import_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/square_import_job_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/square_import_job_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"square-import-job\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"square-import-job\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"square-import-job\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "square_import_job_staging", + "id": "square_import_job_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.sysco_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/sysco-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "sysco-schedule", + "is_enabled": true, + "name": "sysco-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(3 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.sysco_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/sysco_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "sysco-schedule-sysco", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "sysco-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "sysco" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.sysco_job.aws_cloudwatch_event_rule.schedule", + "module.sysco_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.sysco_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/sysco_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/sysco_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"sysco\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"sysco\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"sysco\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "sysco_staging", + "id": "sysco_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.vendor_usages_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/vendor-usages-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "vendor-usages-schedule", + "is_enabled": true, + "name": "vendor-usages-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(4 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.vendor_usages_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/vendor_usages_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "vendor-usages-schedule-vendor-usages", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "vendor-usages-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "vendor-usages" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.vendor_usages_job.aws_cloudwatch_event_rule.schedule", + "module.vendor_usages_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.vendor_usages_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/vendor_usages_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/vendor_usages_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"vendor-usages\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"vendor-usages\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"vendor-usages\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "vendor_usages_staging", + "id": "vendor_usages_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.yodlee2_accounts_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_accounts_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_accounts_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"yodlee2-accounts\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"yodlee2-accounts\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"yodlee2-accounts\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "yodlee2_accounts_staging", + "id": "yodlee2_accounts_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.yodlee2_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/yodlee2-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "yodlee2-schedule", + "is_enabled": true, + "name": "yodlee2-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": {}, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.yodlee2_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": {}, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "yodlee2-schedule-yodlee2", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "yodlee2-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "yodlee2" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.yodlee2_job.aws_cloudwatch_event_rule.schedule", + "module.yodlee2_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.yodlee2_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"yodlee2\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"yodlee2\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"yodlee2\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "yodlee2_staging", + "id": "yodlee2_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": {}, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] } ], "check_results": null diff --git a/terraform/terraform.tfstate.d/staging/terraform.tfstate.backup b/terraform/terraform.tfstate.d/staging/terraform.tfstate.backup index 67efe66f..9a1f001e 100644 --- a/terraform/terraform.tfstate.d/staging/terraform.tfstate.backup +++ b/terraform/terraform.tfstate.d/staging/terraform.tfstate.backup @@ -1,9 +1,28 @@ { "version": 4, - "terraform_version": "1.4.6", - "serial": 133, + "terraform_version": "1.7.5", + "serial": 208, "lineage": "91d10fe0-8033-8778-c202-78d5a81632e8", - "outputs": {}, + "outputs": { + "aws_access_key_id": { + "value": "AKIAZ4TSKSJ2TMDQ3WFK", + "type": "string", + "sensitive": true + }, + "aws_default_region": { + "value": "us-east-1", + "type": "string" + }, + "aws_secret_access_key": { + "value": "VZHxF3iX2DpP1yCKGmV6qJmprs9LqrETDmKMePbk", + "type": "string", + "sensitive": true + }, + "queue_url": { + "value": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging", + "type": "string" + } + }, "resources": [ { "mode": "data", @@ -23,6 +42,563 @@ } ] }, + { + "mode": "data", + "type": "aws_iam_policy_document", + "name": "toast_policy_doc", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "499479035", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:*\",\n \"Resource\": [\n \"arn:aws:s3:::toast.staging.app.integreatconsult.com/*\",\n \"arn:aws:s3:::toast.staging.app.integreatconsult.com\"\n ],\n \"Principal\": {\n \"AWS\": [\n \"arn:aws:iam::679918342773:role/http-proxy\",\n \"arn:aws:iam::679918342773:role/datomic-ddb\"\n ]\n }\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "s3:*" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "arn:aws:iam::679918342773:role/datomic-ddb", + "arn:aws:iam::679918342773:role/http-proxy" + ], + "type": "AWS" + } + ], + "resources": [ + "arn:aws:s3:::toast.staging.app.integreatconsult.com", + "arn:aws:s3:::toast.staging.app.integreatconsult.com/*" + ], + "sid": "" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "mode": "managed", + "type": "aws_acm_certificate", + "name": "cert", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:acm:us-east-1:679918342773:certificate/ca150186-1e27-4321-b23f-d934211de8b8", + "certificate_authority_arn": "", + "certificate_body": null, + "certificate_chain": null, + "domain_name": "staging3.app.integreatconsult.com", + "domain_validation_options": [ + { + "domain_name": "staging3.app.integreatconsult.com", + "resource_record_name": "_469d48ffed86c3b36df870ed56721086.staging3.app.integreatconsult.com.", + "resource_record_type": "CNAME", + "resource_record_value": "_7e6747707e32a59a81055222c94098d0.zdxcnfdgtt.acm-validations.aws." + } + ], + "early_renewal_duration": "", + "id": "arn:aws:acm:us-east-1:679918342773:certificate/ca150186-1e27-4321-b23f-d934211de8b8", + "key_algorithm": "RSA_2048", + "not_after": "", + "not_before": "", + "options": [ + { + "certificate_transparency_logging_preference": "ENABLED" + } + ], + "pending_renewal": false, + "private_key": null, + "renewal_eligibility": "INELIGIBLE", + "renewal_summary": [], + "status": "PENDING_VALIDATION", + "subject_alternative_names": [ + "staging3.app.integreatconsult.com" + ], + "tags": null, + "tags_all": {}, + "type": "AMAZON_ISSUED", + "validation_emails": [], + "validation_method": "DNS", + "validation_option": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_acm_certificate", + "name": "data_cert", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:acm:us-east-1:679918342773:certificate/2444dddf-c3f5-4638-8f63-98edc35f36d0", + "certificate_authority_arn": "", + "certificate_body": null, + "certificate_chain": null, + "domain_name": "data.staging.app.integreatconsult.com", + "domain_validation_options": [ + { + "domain_name": "data.staging.app.integreatconsult.com", + "resource_record_name": "_77ae6550c5d5ab752ecb52f05de9a4e4.data.staging.app.integreatconsult.com.", + "resource_record_type": "CNAME", + "resource_record_value": "_d8b38342271f96bebc65dffa37c1762e.mhbtsbpdnt.acm-validations.aws." + } + ], + "early_renewal_duration": "", + "id": "arn:aws:acm:us-east-1:679918342773:certificate/2444dddf-c3f5-4638-8f63-98edc35f36d0", + "key_algorithm": "RSA_2048", + "not_after": "", + "not_before": "", + "options": [ + { + "certificate_transparency_logging_preference": "ENABLED" + } + ], + "pending_renewal": false, + "private_key": null, + "renewal_eligibility": "INELIGIBLE", + "renewal_summary": [], + "status": "PENDING_VALIDATION", + "subject_alternative_names": [ + "data.staging.app.integreatconsult.com" + ], + "tags": null, + "tags_all": {}, + "type": "AMAZON_ISSUED", + "validation_emails": [], + "validation_method": "DNS", + "validation_option": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_service", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "alarms": [], + "capacity_provider_strategy": [ + { + "base": 1, + "capacity_provider": "FARGATE_SPOT", + "weight": 5 + } + ], + "cluster": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "deployment_circuit_breaker": [ + { + "enable": false, + "rollback": false + } + ], + "deployment_controller": [ + { + "type": "ECS" + } + ], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": 0, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_new_deployment": null, + "health_check_grace_period_seconds": 600, + "iam_role": "/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS", + "id": "arn:aws:ecs:us-east-1:679918342773:service/default/integreat_app_staging", + "launch_type": "", + "load_balancer": [ + { + "container_name": "integreat-app", + "container_port": 3000, + "elb_name": "", + "target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9" + } + ], + "name": "integreat_app_staging", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-16161a39", + "subnet-323deb78", + "subnet-44c2774b", + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "LATEST", + "propagate_tags": "NONE", + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [ + { + "container_name": "", + "container_port": 0, + "port": 0, + "registry_arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-nsn252bfk4r6bzpj" + } + ], + "tags": null, + "tags_all": {}, + "task_definition": "arn:aws:ecs:us-east-1:679918342773:task-definition/integreat_app_staging:162", + "timeouts": { + "create": null, + "delete": null, + "update": null + }, + "triggers": {}, + "wait_for_steady_state": true + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_ecs_task_definition.integreat_app", + "aws_lb_target_group.integreat_app", + "aws_service_discovery_service.service" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_service", + "name": "solr", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "status": "tainted", + "schema_version": 0, + "attributes": { + "alarms": [], + "capacity_provider_strategy": [ + { + "base": 1, + "capacity_provider": "FARGATE", + "weight": 5 + } + ], + "cluster": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "deployment_circuit_breaker": [ + { + "enable": false, + "rollback": false + } + ], + "deployment_controller": [ + { + "type": "ECS" + } + ], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": 1, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "iam_role": null, + "id": "arn:aws:ecs:us-east-1:679918342773:service/default/solr_app_staging", + "launch_type": null, + "load_balancer": [], + "name": "solr_app_staging", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "LATEST", + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [ + { + "container_name": "", + "container_port": 0, + "port": 0, + "registry_arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-s7tr2j6rcazkgsxp" + } + ], + "tags": null, + "tags_all": null, + "task_definition": "arn:aws:ecs:us-east-1:679918342773:task-definition/solr_staging:1", + "timeouts": { + "create": null, + "delete": null, + "update": null + }, + "triggers": null, + "wait_for_steady_state": true + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_ecs_task_definition.solr", + "aws_efs_file_system.solr_storage", + "aws_service_discovery_service.solr" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/integreat_app_staging:162", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/integreat_app_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"integreat-app\"},\"environment\":[{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"integreat-app\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-staging\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":3000,\"hostPort\":3000,\"protocol\":\"tcp\"},{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "4096", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "integreat_app_staging", + "id": "integreat_app_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "16384", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 162, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "solr", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/solr_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/solr_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"prod\",\"com.datadoghq.tags.service\":\"solr\"},\"environment\":[{\"name\":\"DD_ENV\",\"value\":\"prod\"},{\"name\":\"DD_SERVICE\",\"value\":\"solr\"}],\"essential\":true,\"image\":\"solr\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/solr-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[{\"containerPath\":\"/var/solr\",\"readOnly\":false,\"sourceVolume\":\"solr-storage\"}],\"name\":\"solr\",\"portMappings\":[{\"containerPort\":8983,\"hostPort\":8983,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "solr_staging", + "id": "solr_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [], + "file_system_id": "fs-0486d889f5a7706e8", + "root_directory": "/", + "transit_encryption": "", + "transit_encryption_port": null + } + ], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "", + "name": "solr-storage" + } + ] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "aws_efs_file_system.solr_storage" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_efs_file_system", + "name": "solr_storage", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:elasticfilesystem:us-east-1:679918342773:file-system/fs-0486d889f5a7706e8", + "availability_zone_id": "", + "availability_zone_name": "", + "creation_token": "solr_storage-staging", + "dns_name": "fs-0486d889f5a7706e8.efs.us-east-1.amazonaws.com", + "encrypted": false, + "id": "fs-0486d889f5a7706e8", + "kms_key_id": "", + "lifecycle_policy": [], + "number_of_mount_targets": 0, + "owner_id": "679918342773", + "performance_mode": "generalPurpose", + "provisioned_throughput_in_mibps": 0, + "size_in_bytes": [ + { + "value": 6144, + "value_in_ia": 0, + "value_in_standard": 6144 + } + ], + "tags": { + "Name": "solr_storage_staging" + }, + "tags_all": { + "Name": "solr_storage_staging" + }, + "throughput_mode": "bursting" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_access_key", + "name": "app_user", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "create_date": "2024-03-21T05:39:43Z", + "encrypted_secret": null, + "encrypted_ses_smtp_password_v4": null, + "id": "AKIAZ4TSKSJ2TMDQ3WFK", + "key_fingerprint": null, + "pgp_key": null, + "secret": "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", + "ses_smtp_password_v4": "BMYut7OzUgr5EKH3LCZDjTFk3X8rm7MdReTojaFulVgA", + "status": "Active", + "user": "integreat-staging" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_iam_user.app_user" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_user", + "name": "app_user", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::679918342773:user/integreat-staging", + "force_destroy": false, + "id": "integreat-staging", + "name": "integreat-staging", + "path": "/", + "permissions_boundary": null, + "tags": null, + "tags_all": {}, + "unique_id": "AIDAZ4TSKSJ2SDDJ5OMWV" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_user_policy_attachment", + "name": "app_user_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "integreat-staging-20240321053943002300000005", + "policy_arn": "arn:aws:iam::aws:policy/AdministratorAccess", + "user": "integreat-staging" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_iam_user.app_user" + ] + } + ] + }, { "mode": "managed", "type": "aws_lb", @@ -39,11 +615,11 @@ "prefix": "" } ], - "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/dc040205e561419e", - "arn_suffix": "app/integreat-app-staging/dc040205e561419e", + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "arn_suffix": "app/integreat-app-staging/d65758eb97c8e4e5", "customer_owned_ipv4_pool": "", "desync_mitigation_mode": "defensive", - "dns_name": "integreat-app-staging-229185591.us-east-1.elb.amazonaws.com", + "dns_name": "integreat-app-staging-1122841226.us-east-1.elb.amazonaws.com", "drop_invalid_header_fields": false, "enable_cross_zone_load_balancing": true, "enable_deletion_protection": true, @@ -51,7 +627,7 @@ "enable_tls_version_and_cipher_suite_headers": false, "enable_waf_fail_open": false, "enable_xff_client_port": false, - "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/dc040205e561419e", + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", "idle_timeout": 120, "internal": false, "ip_address_type": "ipv4", @@ -114,7 +690,7 @@ "subnet-8519fde2", "subnet-89bab8d4" ], - "tags": {}, + "tags": null, "tags_all": {}, "timeouts": null, "vpc_id": "vpc-b5b7d6ce", @@ -128,66 +704,267 @@ }, { "mode": "managed", - "type": "aws_s3_bucket", - "name": "data", + "type": "aws_lb_listener", + "name": "http", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 0, "attributes": { - "acceleration_status": "", - "acl": "private", - "arn": "arn:aws:s3:::data.staging.app.integreatconsult.com", - "bucket": "data.staging.app.integreatconsult.com", - "bucket_domain_name": "data.staging.app.integreatconsult.com.s3.amazonaws.com", - "bucket_prefix": "", - "bucket_regional_domain_name": "data.staging.app.integreatconsult.com.s3.amazonaws.com", - "cors_rule": [], - "force_destroy": false, - "grant": [ + "alpn_policy": null, + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/198d2d83a47036f2", + "certificate_arn": null, + "default_action": [ { - "id": "e30528e0ba05fd1f250869c1b4db0eff90001b4d9ad90dd2e01b210844f83e5a", - "permissions": [ - "FULL_CONTROL" - ], - "type": "CanonicalUser", - "uri": "" - } - ], - "hosted_zone_id": "Z3AQBSTGFYJSTF", - "id": "data.staging.app.integreatconsult.com", - "lifecycle_rule": [], - "logging": [], - "object_lock_configuration": [], - "object_lock_enabled": false, - "policy": "{\"Id\":\"Policy1526084187222\",\"Statement\":[{\"Action\":\"s3:GetObject\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com/*\",\"Sid\":\"Stmt1526084185514\"},{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com\",\"Sid\":\"AllowReadForProd\"},{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/cargo-lambda-role-44d9b00d-f09e-4a28-aa5f-1039518c4678\"},\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com\",\"Sid\":\"AllowReadForXLS\"}],\"Version\":\"2012-10-17\"}", - "region": "us-east-1", - "replication_configuration": [], - "request_payer": "BucketOwner", - "server_side_encryption_configuration": [ - { - "rule": [ + "authenticate_cognito": [], + "authenticate_oidc": [], + "fixed_response": [], + "forward": [], + "order": 1, + "redirect": [ { - "apply_server_side_encryption_by_default": [ - { - "kms_master_key_id": "", - "sse_algorithm": "AES256" - } - ], - "bucket_key_enabled": false + "host": "#{host}", + "path": "/#{path}", + "port": "443", + "protocol": "HTTPS", + "query": "#{query}", + "status_code": "HTTP_301" } - ] + ], + "target_group_arn": "", + "type": "redirect" } ], - "tags": {}, + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/198d2d83a47036f2", + "load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "port": 80, + "protocol": "HTTP", + "ssl_policy": "", + "tags": null, "tags_all": {}, - "timeouts": null, - "versioning": [ + "timeouts": { + "read": null + } + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsicmVhZCI6NjAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "aws_lb.integreat_app" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_listener", + "name": "https", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "alpn_policy": null, + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8", + "certificate_arn": "arn:aws:acm:us-east-1:679918342773:certificate/ca150186-1e27-4321-b23f-d934211de8b8", + "default_action": [ { - "enabled": false, - "mfa_delete": false + "authenticate_cognito": [], + "authenticate_oidc": [], + "fixed_response": [], + "forward": [], + "order": 1, + "redirect": [], + "target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9", + "type": "forward" } ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8", + "load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:loadbalancer/app/integreat-app-staging/d65758eb97c8e4e5", + "port": 443, + "protocol": "HTTPS", + "ssl_policy": "ELBSecurityPolicy-2016-08", + "tags": null, + "tags_all": {}, + "timeouts": { + "read": null + } + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsicmVhZCI6NjAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "aws_acm_certificate.cert", + "aws_lb.integreat_app", + "aws_lb_target_group.integreat_app" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_listener_rule", + "name": "static", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "action": [ + { + "authenticate_cognito": [], + "authenticate_oidc": [], + "fixed_response": [], + "forward": [], + "order": 1, + "redirect": [ + { + "host": "s3.amazonaws.com", + "path": "/staging3.app.integreatconsult.com/#{path}", + "port": "443", + "protocol": "HTTPS", + "query": "#{query}", + "status_code": "HTTP_301" + } + ], + "target_group_arn": "", + "type": "redirect" + } + ], + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener-rule/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8/4cefe09d0fb96f84", + "condition": [ + { + "host_header": [], + "http_header": [], + "http_request_method": [], + "path_pattern": [ + { + "values": [ + "/css/*", + "/finance-font/*", + "/img/*", + "/js/compiled/*", + "index.html" + ] + } + ], + "query_string": [], + "source_ip": [] + } + ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener-rule/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8/4cefe09d0fb96f84", + "listener_arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:listener/app/integreat-app-staging/d65758eb97c8e4e5/5d2f6b277d3d8af8", + "priority": 1, + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_acm_certificate.cert", + "aws_lb.integreat_app", + "aws_lb_listener.https", + "aws_lb_target_group.integreat_app" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lb_target_group", + "name": "integreat_app", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9", + "arn_suffix": "targetgroup/integreat-app-staging/a8cd2c002073aec9", + "connection_termination": false, + "deregistration_delay": "120", + "health_check": [ + { + "enabled": true, + "healthy_threshold": 2, + "interval": 60, + "matcher": "200", + "path": "/api/health-check", + "port": "traffic-port", + "protocol": "HTTP", + "timeout": 14, + "unhealthy_threshold": 3 + } + ], + "id": "arn:aws:elasticloadbalancing:us-east-1:679918342773:targetgroup/integreat-app-staging/a8cd2c002073aec9", + "ip_address_type": "ipv4", + "lambda_multi_value_headers_enabled": false, + "load_balancing_algorithm_type": "round_robin", + "load_balancing_cross_zone_enabled": "use_load_balancer_configuration", + "name": "integreat-app-staging", + "name_prefix": null, + "port": 80, + "preserve_client_ip": null, + "protocol": "HTTP", + "protocol_version": "HTTP1", + "proxy_protocol_v2": false, + "slow_start": 0, + "stickiness": [ + { + "cookie_duration": 86400, + "cookie_name": "", + "enabled": false, + "type": "lb_cookie" + } + ], + "tags": null, + "tags_all": {}, + "target_failover": [ + { + "on_deregistration": null, + "on_unhealthy": null + } + ], + "target_type": "ip", + "vpc_id": "vpc-b5b7d6ce" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "data", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "status": "tainted", + "schema_version": 0, + "attributes": { + "acceleration_status": null, + "acl": "private", + "arn": null, + "bucket": "data.staging.app.integreatconsult.com", + "bucket_domain_name": null, + "bucket_prefix": null, + "bucket_regional_domain_name": null, + "cors_rule": null, + "force_destroy": false, + "grant": [], + "hosted_zone_id": null, + "id": "data.staging.app.integreatconsult.com", + "lifecycle_rule": null, + "logging": null, + "object_lock_configuration": null, + "object_lock_enabled": null, + "policy": "{\"Id\":\"Policy1526084187222\",\"Statement\":[{\"Action\":[\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com/*\",\"Sid\":\"Stmt1526084185514\"},{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com\",\"Sid\":\"AllowReadForProd\"},{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/http-proxy\"},\"Resource\":\"arn:aws:s3:::data.staging.app.integreatconsult.com\",\"Sid\":\"AllowReadForProdProxy\"}],\"Version\":\"2012-10-17\"}", + "region": null, + "replication_configuration": null, + "request_payer": null, + "server_side_encryption_configuration": null, + "tags": null, + "tags_all": null, + "timeouts": null, + "versioning": null, "website": [ { "error_document": "", @@ -196,11 +973,11 @@ "routing_rules": "" } ], - "website_domain": "s3-website-us-east-1.amazonaws.com", - "website_endpoint": "data.staging.app.integreatconsult.com.s3-website-us-east-1.amazonaws.com" + "website_domain": null, + "website_endpoint": null }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19" } ] }, @@ -257,7 +1034,7 @@ ] } ], - "tags": {}, + "tags": null, "tags_all": {}, "timeouts": null, "versioning": [ @@ -271,12 +1048,345 @@ "website_endpoint": null }, "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", "dependencies": [ "data.aws_caller_identity.current" ] } ] }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "static", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "status": "tainted", + "schema_version": 0, + "attributes": { + "acceleration_status": null, + "acl": null, + "arn": null, + "bucket": "staging3.app.integreatconsult.com", + "bucket_domain_name": null, + "bucket_prefix": null, + "bucket_regional_domain_name": null, + "cors_rule": [ + { + "allowed_headers": [ + "*" + ], + "allowed_methods": [ + "PUT", + "POST", + "DELETE", + "GET" + ], + "allowed_origins": [ + "https://staging3.app.integreatconsult.com" + ], + "expose_headers": [], + "max_age_seconds": 0 + } + ], + "force_destroy": false, + "grant": [], + "hosted_zone_id": null, + "id": "staging3.app.integreatconsult.com", + "lifecycle_rule": null, + "logging": null, + "object_lock_configuration": null, + "object_lock_enabled": null, + "policy": "{\"Id\":\"Policy1526084187222\",\"Statement\":[{\"Action\":[\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::staging3.app.integreatconsult.com/*\",\"Sid\":\"Stmt1526084185514\"}],\"Version\":\"2012-10-17\"}", + "region": null, + "replication_configuration": null, + "request_payer": "BucketOwner", + "server_side_encryption_configuration": null, + "tags": null, + "tags_all": null, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [ + { + "error_document": "", + "index_document": "index.html", + "redirect_all_requests_to": "", + "routing_rules": "" + } + ], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "toast_bucket", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acceleration_status": "", + "acl": null, + "arn": "arn:aws:s3:::toast.staging.app.integreatconsult.com", + "bucket": "toast.staging.app.integreatconsult.com", + "bucket_domain_name": "toast.staging.app.integreatconsult.com.s3.amazonaws.com", + "bucket_prefix": "", + "bucket_regional_domain_name": "toast.staging.app.integreatconsult.com.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": false, + "grant": [ + { + "id": "e30528e0ba05fd1f250869c1b4db0eff90001b4d9ad90dd2e01b210844f83e5a", + "permissions": [ + "FULL_CONTROL" + ], + "type": "CanonicalUser", + "uri": "" + } + ], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "toast.staging.app.integreatconsult.com", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "object_lock_enabled": false, + "policy": "", + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [ + { + "rule": [ + { + "apply_server_side_encryption_by_default": [ + { + "kms_master_key_id": "", + "sse_algorithm": "AES256" + } + ], + "bucket_key_enabled": false + } + ] + } + ], + "tags": null, + "tags_all": {}, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19" + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket_notification", + "name": "mail_bucket_notification", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "integreat-mail-staging", + "eventbridge": false, + "id": "integreat-mail-staging", + "lambda_function": [], + "queue": [ + { + "events": [ + "s3:ObjectCreated:*" + ], + "filter_prefix": "", + "filter_suffix": "", + "id": "tf-s3-queue-20240321054008457900000008", + "queue_arn": "arn:aws:sqs:us-east-1:679918342773:integreat-mail-staging" + } + ], + "topic": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.invoices", + "aws_sqs_queue.integreat-mail", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "toast_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "toast.staging.app.integreatconsult.com", + "id": "toast.staging.app.integreatconsult.com", + "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"arn:aws:iam::679918342773:role/http-proxy\",\"arn:aws:iam::679918342773:role/datomic-ddb\"]},\"Resource\":[\"arn:aws:s3:::toast.staging.app.integreatconsult.com/*\",\"arn:aws:s3:::toast.staging.app.integreatconsult.com\"],\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.toast_bucket", + "data.aws_iam_policy_document.toast_policy_doc" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_service_discovery_service", + "name": "service", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-nsn252bfk4r6bzpj", + "description": "", + "dns_config": [ + { + "dns_records": [ + { + "ttl": 10, + "type": "A" + } + ], + "namespace_id": "ns-gv2z744em7myo2jp", + "routing_policy": "MULTIVALUE" + } + ], + "force_destroy": false, + "health_check_config": [], + "health_check_custom_config": [ + { + "failure_threshold": 1 + } + ], + "id": "srv-nsn252bfk4r6bzpj", + "name": "integreat-app-staging", + "namespace_id": "ns-gv2z744em7myo2jp", + "tags": null, + "tags_all": {}, + "type": "DNS_HTTP" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_service_discovery_service", + "name": "solr", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:servicediscovery:us-east-1:679918342773:service/srv-s7tr2j6rcazkgsxp", + "description": "", + "dns_config": [ + { + "dns_records": [ + { + "ttl": 10, + "type": "A" + } + ], + "namespace_id": "ns-gv2z744em7myo2jp", + "routing_policy": "MULTIVALUE" + } + ], + "force_destroy": false, + "health_check_config": [], + "health_check_custom_config": [ + { + "failure_threshold": 1 + } + ], + "id": "srv-s7tr2j6rcazkgsxp", + "name": "solr-staging", + "namespace_id": "ns-gv2z744em7myo2jp", + "tags": null, + "tags_all": {}, + "type": "DNS_HTTP" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_ses_receipt_rule", + "name": "store", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "add_header_action": [], + "after": null, + "arn": "arn:aws:ses:us-east-1:679918342773:receipt-rule-set/default-rule-set:receipt-rule/store-staging", + "bounce_action": [], + "enabled": true, + "id": "store-staging", + "lambda_action": [], + "name": "store-staging", + "recipients": [ + "invoices-staging@mail.app.integreatconsult.com" + ], + "rule_set_name": "default-rule-set", + "s3_action": [ + { + "bucket_name": "integreat-mail-staging", + "kms_key_arn": "", + "object_key_prefix": "", + "position": 1, + "topic_arn": "" + } + ], + "scan_enabled": true, + "sns_action": [], + "stop_action": [], + "tls_policy": "Optional", + "workmail_action": [] + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.invoices", + "aws_ses_receipt_rule_set.main", + "data.aws_caller_identity.current" + ] + } + ] + }, { "mode": "managed", "type": "aws_ses_receipt_rule_set", @@ -293,6 +1403,1941 @@ "sensitive_attributes": [] } ] + }, + { + "mode": "managed", + "type": "aws_sqs_queue", + "name": "background-request", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:sqs:us-east-1:679918342773:integreat-background-request-staging", + "content_based_deduplication": false, + "deduplication_scope": "", + "delay_seconds": 0, + "fifo_queue": false, + "fifo_throughput_limit": "", + "id": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-background-request-staging", + "kms_data_key_reuse_period_seconds": 300, + "kms_master_key_id": "", + "max_message_size": 262144, + "message_retention_seconds": 345600, + "name": "integreat-background-request-staging", + "name_prefix": "", + "policy": "{\"Statement\":[{\"Action\":\"sqs:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:sqs:*:*:integreat-background-request-staging\"}],\"Version\":\"2012-10-17\"}", + "receive_wait_time_seconds": 0, + "redrive_allow_policy": "", + "redrive_policy": "", + "sqs_managed_sse_enabled": true, + "tags": null, + "tags_all": {}, + "url": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-background-request-staging", + "visibility_timeout_seconds": 30 + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "aws_sqs_queue", + "name": "integreat-mail", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:sqs:us-east-1:679918342773:integreat-mail-staging", + "content_based_deduplication": false, + "deduplication_scope": "", + "delay_seconds": 0, + "fifo_queue": false, + "fifo_throughput_limit": "", + "id": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging", + "kms_data_key_reuse_period_seconds": 300, + "kms_master_key_id": "", + "max_message_size": 262144, + "message_retention_seconds": 345600, + "name": "integreat-mail-staging", + "name_prefix": "", + "policy": "{\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"arn:aws:s3:::integreat-mail-staging\"}},\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:*:*:integreat-mail-staging\"}],\"Version\":\"2012-10-17\"}", + "receive_wait_time_seconds": 0, + "redrive_allow_policy": "", + "redrive_policy": "", + "sqs_managed_sse_enabled": true, + "tags": null, + "tags_all": {}, + "url": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-mail-staging", + "visibility_timeout_seconds": 30 + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.invoices", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_sqs_queue", + "name": "integreat-scheduled-jobs", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:sqs:us-east-1:679918342773:integreat-scheduled-jobs-staging", + "content_based_deduplication": false, + "deduplication_scope": "", + "delay_seconds": 0, + "fifo_queue": false, + "fifo_throughput_limit": "", + "id": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-scheduled-jobs-staging", + "kms_data_key_reuse_period_seconds": 300, + "kms_master_key_id": "", + "max_message_size": 262144, + "message_retention_seconds": 345600, + "name": "integreat-scheduled-jobs-staging", + "name_prefix": "", + "policy": "{\"Statement\":[{\"Action\":\"sqs:*\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::679918342773:role/datomic-ddb\"},\"Resource\":\"arn:aws:sqs:*:*:integreat-scheduled-jobs-staging\"}],\"Version\":\"2012-10-17\"}", + "receive_wait_time_seconds": 0, + "redrive_allow_policy": "", + "redrive_policy": "", + "sqs_managed_sse_enabled": true, + "tags": null, + "tags_all": {}, + "url": "https://sqs.us-east-1.amazonaws.com/679918342773/integreat-scheduled-jobs-staging", + "visibility_timeout_seconds": 30 + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.bulk_journal_import_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/bulk_journal_import_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/bulk_journal_import_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"bulk-journal-import\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"bulk-journal-import\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"bulk-journal-import\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "bulk_journal_import_staging", + "id": "bulk_journal_import_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.close_auto_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/close-auto-invoices-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "close-auto-invoices-schedule", + "is_enabled": true, + "name": "close-auto-invoices-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(1 hour)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.close_auto_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/close_auto_invoices_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "close-auto-invoices-schedule-close-auto-invoices", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "close-auto-invoices-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "close-auto-invoices" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.close_auto_invoices_job.aws_cloudwatch_event_rule.schedule", + "module.close_auto_invoices_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.close_auto_invoices_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/close_auto_invoices_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/close_auto_invoices_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"close-auto-invoices\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"close-auto-invoices\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"close-auto-invoices\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "close_auto_invoices_staging", + "id": "close_auto_invoices_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.current_balance_cache", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/current-balance-cache-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "current-balance-cache-schedule", + "is_enabled": true, + "name": "current-balance-cache-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(60 minutes)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.current_balance_cache", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/current_balance_cache_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "current-balance-cache-schedule-current-balance-cache", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "current-balance-cache-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "current-balance-cache" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.current_balance_cache.aws_cloudwatch_event_rule.schedule", + "module.current_balance_cache.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.current_balance_cache", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/current_balance_cache_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/current_balance_cache_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"current-balance-cache\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"current-balance-cache\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"current-balance-cache\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "current_balance_cache_staging", + "id": "current_balance_cache_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.import_uploaded_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/import-uploaded-invoices-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "import-uploaded-invoices-schedule", + "is_enabled": true, + "name": "import-uploaded-invoices-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(1 hour)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.import_uploaded_invoices_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/import_uploaded_invoices_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "import-uploaded-invoices-schedule-import-uploaded-invoices", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "import-uploaded-invoices-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "import-uploaded-invoices" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.import_uploaded_invoices_job.aws_cloudwatch_event_rule.schedule", + "module.import_uploaded_invoices_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.import_uploaded_invoices_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/import_uploaded_invoices_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/import_uploaded_invoices_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"import-uploaded-invoices\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"import-uploaded-invoices\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"import-uploaded-invoices\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "import_uploaded_invoices_staging", + "id": "import_uploaded_invoices_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.insight_outcome_recommendation_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/insight-outcome-recommendation-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "insight-outcome-recommendation-schedule", + "is_enabled": true, + "name": "insight-outcome-recommendation-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.insight_outcome_recommendation_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/insight_outcome_recommendation_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "insight-outcome-recommendation-schedule-insight-outcome-recommendation", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "insight-outcome-recommendation-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "insight-outcome-recommendation" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.insight_outcome_recommendation_job.aws_cloudwatch_event_rule.schedule", + "module.insight_outcome_recommendation_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.insight_outcome_recommendation_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/insight_outcome_recommendation_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/insight_outcome_recommendation_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"insight-outcome-recommendation\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"insight-outcome-recommendation\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"insight-outcome-recommendation\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "2048", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "insight_outcome_recommendation_staging", + "id": "insight_outcome_recommendation_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.intuit_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/intuit-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "intuit-schedule", + "is_enabled": true, + "name": "intuit-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.intuit_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/intuit_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "intuit-schedule-intuit", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "intuit-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "intuit" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.intuit_job.aws_cloudwatch_event_rule.schedule", + "module.intuit_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.intuit_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/intuit_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/intuit_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"intuit\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"intuit\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"intuit\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "intuit_staging", + "id": "intuit_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.load_historical_sales_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/load_historical_sales_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/load_historical_sales_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"load-historical-sales\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"load-historical-sales\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"load-historical-sales\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "load_historical_sales_staging", + "id": "load_historical_sales_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.ntg_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/ntg-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "ntg-schedule", + "is_enabled": true, + "name": "ntg-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.ntg_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/ntg_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "ntg-schedule-ntg", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "ntg-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "ntg" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.ntg_job.aws_cloudwatch_event_rule.schedule", + "module.ntg_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.ntg_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/ntg_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/ntg_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"ntg\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"ntg\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"ntg\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "ntg_staging", + "id": "ntg_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.plaid_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/plaid-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "plaid-schedule", + "is_enabled": true, + "name": "plaid-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.plaid_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/plaid_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "plaid-schedule-plaid", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "plaid-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "plaid" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.plaid_job.aws_cloudwatch_event_rule.schedule", + "module.plaid_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.plaid_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/plaid_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/plaid_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"plaid\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"plaid\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"plaid\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "plaid_staging", + "id": "plaid_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.reconcile_ledger_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/reconcile-ledger-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "reconcile-ledger-schedule", + "is_enabled": true, + "name": "reconcile-ledger-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(1 hour)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.reconcile_ledger_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/reconcile_ledger_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "reconcile-ledger-schedule-reconcile-ledger", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "reconcile-ledger-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "reconcile-ledger" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.reconcile_ledger_job.aws_cloudwatch_event_rule.schedule", + "module.reconcile_ledger_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.reconcile_ledger_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/reconcile_ledger_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/reconcile_ledger_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"reconcile-ledger\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"reconcile-ledger\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"reconcile-ledger\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "2048", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "reconcile_ledger_staging", + "id": "reconcile_ledger_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "8192", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.register_invoice_import_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/register_invoice_import_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/register_invoice_import_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"register-invoice-import\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"register-invoice-import\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"register-invoice-import\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "2048", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "register_invoice_import_staging", + "id": "register_invoice_import_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "8192", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.square_import_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/square-import-job-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "square-import-job-schedule", + "is_enabled": true, + "name": "square-import-job-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(4 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.square_import_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/square_import_job_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "square-import-job-schedule-square-import-job", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "square-import-job-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "square-import-job" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.square_import_job.aws_cloudwatch_event_rule.schedule", + "module.square_import_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.square_import_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/square_import_job_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/square_import_job_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"square-import-job\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"square-import-job\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"square-import-job\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "square_import_job_staging", + "id": "square_import_job_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "4096", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.sysco_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/sysco-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "sysco-schedule", + "is_enabled": true, + "name": "sysco-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(3 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.sysco_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/sysco_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "sysco-schedule-sysco", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "sysco-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "sysco" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.sysco_job.aws_cloudwatch_event_rule.schedule", + "module.sysco_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.sysco_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/sysco_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/sysco_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"sysco\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"sysco\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"sysco\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "sysco_staging", + "id": "sysco_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.vendor_usages_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/vendor-usages-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "vendor-usages-schedule", + "is_enabled": true, + "name": "vendor-usages-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(4 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.vendor_usages_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/vendor_usages_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "vendor-usages-schedule-vendor-usages", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "vendor-usages-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "vendor-usages" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.vendor_usages_job.aws_cloudwatch_event_rule.schedule", + "module.vendor_usages_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.vendor_usages_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/vendor_usages_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/vendor_usages_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"vendor-usages\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"vendor-usages\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"vendor-usages\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "vendor_usages_staging", + "id": "vendor_usages_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.yodlee2_accounts_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_accounts_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_accounts_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"yodlee2-accounts\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"yodlee2-accounts\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"yodlee2-accounts\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "yodlee2_accounts_staging", + "id": "yodlee2_accounts_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] + }, + { + "module": "module.yodlee2_job", + "mode": "managed", + "type": "aws_cloudwatch_event_rule", + "name": "schedule", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:events:us-east-1:679918342773:rule/yodlee2-schedule", + "description": "", + "event_bus_name": "default", + "event_pattern": null, + "id": "yodlee2-schedule", + "is_enabled": true, + "name": "yodlee2-schedule", + "name_prefix": "", + "role_arn": "", + "schedule_expression": "rate(6 hours)", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "module": "module.yodlee2_job", + "mode": "managed", + "type": "aws_cloudwatch_event_target", + "name": "job_target", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:cluster/default", + "batch_target": [], + "dead_letter_config": [], + "ecs_target": [ + { + "capacity_provider_strategy": [], + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "group": "", + "launch_type": "FARGATE", + "network_configuration": [ + { + "assign_public_ip": true, + "security_groups": [ + "sg-004e5855310c453a3", + "sg-02d167406b1082698" + ], + "subnets": [ + "subnet-5e675761", + "subnet-8519fde2", + "subnet-89bab8d4" + ] + } + ], + "ordered_placement_strategy": [], + "placement_constraint": [], + "platform_version": "", + "propagate_tags": "TASK_DEFINITION", + "tags": null, + "task_count": 1, + "task_definition_arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_staging:1" + } + ], + "event_bus_name": "default", + "http_target": [], + "id": "yodlee2-schedule-yodlee2", + "input": "", + "input_path": "", + "input_transformer": [], + "kinesis_target": [], + "redshift_target": [], + "retry_policy": [], + "role_arn": "arn:aws:iam::679918342773:role/service-role/Amazon_EventBridge_Invoke_ECS_1758992733", + "rule": "yodlee2-schedule", + "run_command_targets": [], + "sqs_target": [], + "target_id": "yodlee2" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "module.yodlee2_job.aws_cloudwatch_event_rule.schedule", + "module.yodlee2_job.aws_ecs_task_definition.background_taskdef" + ] + } + ] + }, + { + "module": "module.yodlee2_job", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "background_taskdef", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "arn": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_staging:1", + "arn_without_revision": "arn:aws:ecs:us-east-1:679918342773:task-definition/yodlee2_staging", + "container_definitions": "[{\"cpu\":0,\"dockerLabels\":{\"com.datadoghq.tags.env\":\"staging\",\"com.datadoghq.tags.service\":\"yodlee2\"},\"environment\":[{\"name\":\"DD_CONTAINER_ENV_AS_TAGS\",\"value\":\"{\\\"INTEGREAT_JOB\\\":\\\"background_job\\\"}\"},{\"name\":\"DD_ENV\",\"value\":\"staging\"},{\"name\":\"DD_SERVICE\",\"value\":\"yodlee2\"},{\"name\":\"INTEGREAT_JOB\",\"value\":\"yodlee2\"},{\"name\":\"config\",\"value\":\"/usr/local/config/staging-background-worker.edn\"}],\"essential\":true,\"image\":\"679918342773.dkr.ecr.us-east-1.amazonaws.com/integreat-cloud:staging\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/integreat-app-prod\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"ecs\"}},\"mountPoints\":[],\"name\":\"integreat-app\",\"portMappings\":[{\"containerPort\":9000,\"hostPort\":9000,\"protocol\":\"tcp\"},{\"containerPort\":9090,\"hostPort\":9090,\"protocol\":\"tcp\"}],\"systemControls\":[],\"volumesFrom\":[]},{\"cpu\":0,\"environment\":[{\"name\":\"DD_API_KEY\",\"value\":\"ce10d932c47b358e81081ae67bd8c112\"},{\"name\":\"ECS_FARGATE\",\"value\":\"true\"}],\"essential\":true,\"image\":\"public.ecr.aws/datadog/agent:latest\",\"mountPoints\":[],\"name\":\"datadog-agent\",\"portMappings\":[],\"systemControls\":[],\"volumesFrom\":[]}]", + "cpu": "1024", + "ephemeral_storage": [], + "execution_role_arn": "arn:aws:iam::679918342773:role/ecsTaskExecutionRole", + "family": "yodlee2_staging", + "id": "yodlee2_staging", + "inference_accelerator": [], + "ipc_mode": "", + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": "", + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "FARGATE" + ], + "revision": 1, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "tags_all": {}, + "task_role_arn": "arn:aws:iam::679918342773:role/datomic-ddb", + "volume": [] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" + } + ] } ], "check_results": null diff --git a/test/clj/auto_ap/ssr/invoice/new_invoice_wizard_test.clj b/test/clj/auto_ap/ssr/invoice/new_invoice_wizard_test.clj new file mode 100644 index 00000000..b71e88c0 --- /dev/null +++ b/test/clj/auto_ap/ssr/invoice/new_invoice_wizard_test.clj @@ -0,0 +1,94 @@ +(ns auto-ap.ssr.invoice.new-invoice-wizard-test + (:require [clojure.test :refer [deftest testing is]] + [auto-ap.ssr.invoice.new-invoice-wizard :as sut9])) + + +(deftest maybe-spread-locations-test + (testing "Shared amount correctly spread across multiple locations" + (let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount 100.0 + :invoice-expense-account/location "Shared"}] + :invoice/total 100.0} + result (sut9/maybe-spread-locations invoice ["Location 1" + "Location 2"])] + (is (= + [{:invoice-expense-account/amount 50.0 + :invoice-expense-account/location "Location 1"} + {:invoice-expense-account/amount 50.0 + :invoice-expense-account/location "Location 2"}] + (map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result)))))) + + (testing "Shared amount correctly spread with negative amounts" + (let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount -100.0 + :invoice-expense-account/location "Shared"}] + :invoice/total -100.0} + result (sut9/maybe-spread-locations invoice ["Location 1" + "Location 2"])] + (is (= + [{:invoice-expense-account/amount -50.0 + :invoice-expense-account/location "Location 1"} + {:invoice-expense-account/amount -50.0 + :invoice-expense-account/location "Location 2"}] + (map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result)))))) + + + + (testing "Shared amount correctly spread with leftovers" + (let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount 100.0 + :invoice-expense-account/location "Shared"}] + :invoice/total 100.0} + result (sut9/maybe-spread-locations invoice ["Location 1" + "Location 2" + "Location 3"])] + (is (= + [{:invoice-expense-account/amount 33.34 + :invoice-expense-account/location "Location 1"} + {:invoice-expense-account/amount 33.33 + :invoice-expense-account/location "Location 2"} + {:invoice-expense-account/amount 33.33 + :invoice-expense-account/location "Location 3"}] + (map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result)))))) + + (testing "Shared amount correctly spread with leftovers in negatives" + (let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount -33.33333333333333 + :invoice-expense-account/location "A"} + {:invoice-expense-account/amount -33.33333333333333 + :invoice-expense-account/location "B"} + {:invoice-expense-account/amount -33.33333333333333 + :invoice-expense-account/location "C"}] + :invoice/total -100.0} + result (sut9/maybe-spread-locations invoice ["Location 1"])] + (is (= [{:invoice-expense-account/amount -33.34 + :invoice-expense-account/location "A"} + {:invoice-expense-account/amount -33.33 + :invoice-expense-account/location "B"} + {:invoice-expense-account/amount -33.33 + :invoice-expense-account/location "C"}] + (map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result)))))) + + (testing "Shared amount correctly spread with negative amounts and leftovers" + (let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount -101.33 + :invoice-expense-account/location "Shared"}] + :invoice/total -101.33} + result (sut9/maybe-spread-locations invoice ["Location 1" + "Location 2"])] + (is (= + [{:invoice-expense-account/amount -50.67 + :invoice-expense-account/location "Location 1"} + {:invoice-expense-account/amount -50.66 + :invoice-expense-account/location "Location 2"}] + (map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result)))))) + + (testing "Leftovers should not exceed a single cent" + (let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount -100 + :invoice-expense-account/location "Shared"} + {:invoice-expense-account/amount -5 + :invoice-expense-account/location "Shared"}] + :invoice/total -101} + result (sut8/maybe-spread-locations invoice ["Location 1" ])] + (is (= + [{:invoice-expense-account/amount -100.0 + :invoice-expense-account/location "Location 1"} + {:invoice-expense-account/amount -5.0 + :invoice-expense-account/location "Location 1"}] + (map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result))))))) +