From 7ac06012ec263ee6f00e8ccea153067a6a0a8d18 Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Sun, 6 Mar 2022 00:04:01 +0000 Subject: [PATCH 01/13] Initialize eslint --- web/.eslintrc.js | 17 +++ web/package.json | 4 + web/yarn.lock | 351 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 363 insertions(+), 9 deletions(-) create mode 100644 web/.eslintrc.js diff --git a/web/.eslintrc.js b/web/.eslintrc.js new file mode 100644 index 0000000..3dc2f88 --- /dev/null +++ b/web/.eslintrc.js @@ -0,0 +1,17 @@ +module.exports = { + extends: [ + // add more generic rulesets here, such as: + // 'eslint:recommended', + 'plugin:vue/vue3-recommended', + // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x. + ], + rules: { + // override/add rules settings here, such as: + // 'vue/no-unused-vars': 'error' + }, + "parser": "vue-eslint-parser", + "parserOptions": { + "parser": "@typescript-eslint/parser", + "sourceType": "module" + } +} diff --git a/web/package.json b/web/package.json index 36f3f5d..754215d 100644 --- a/web/package.json +++ b/web/package.json @@ -20,10 +20,14 @@ }, "devDependencies": { "@types/file-saver": "^2.0.5", + "@typescript-eslint/parser": "^5.13.0", "@vitejs/plugin-vue": "^2.0.0", "@vue/cli-plugin-babel": "5.0.0-beta.7", "@vue/cli-plugin-typescript": "~4.5.0", "@vue/cli-service": "5.0.0-beta.7", + "eslint": "^8.10.0", + "eslint-plugin-vue": "^8.5.0", + "prettier": "2.5.1", "sass": "^1.38.0", "sass-loader": "^10.0.0", "typescript": "^4.5.5", diff --git a/web/yarn.lock b/web/yarn.lock index f16a011..ee19f64 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -957,6 +957,21 @@ resolved "https://registry.yarnpkg.com/@emmetio/scanner/-/scanner-1.0.0.tgz#065b2af6233fe7474d44823e3deb89724af42b5f" integrity sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA== +"@eslint/eslintrc@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" + integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -1001,6 +1016,20 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@jridgewell/resolve-uri@^3.0.3": version "3.0.4" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz#b876e3feefb9c8d3aa84014da28b5e52a0640d72" @@ -1281,6 +1310,50 @@ dependencies: "@types/node" "*" +"@typescript-eslint/parser@^5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.13.0.tgz#0394ed8f2f849273c0bf4b811994d177112ced5c" + integrity sha512-GdrU4GvBE29tm2RqWOM0P5QfCtgCyN4hXICj/X9ibKED16136l9ZpoJvCL5pSKtmJzA+NRDzQ312wWMejCVVfg== + dependencies: + "@typescript-eslint/scope-manager" "5.13.0" + "@typescript-eslint/types" "5.13.0" + "@typescript-eslint/typescript-estree" "5.13.0" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.13.0.tgz#cf6aff61ca497cb19f0397eea8444a58f46156b6" + integrity sha512-T4N8UvKYDSfVYdmJq7g2IPJYCRzwtp74KyDZytkR4OL3NRupvswvmJQJ4CX5tDSurW2cvCc1Ia1qM7d0jpa7IA== + dependencies: + "@typescript-eslint/types" "5.13.0" + "@typescript-eslint/visitor-keys" "5.13.0" + +"@typescript-eslint/types@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.13.0.tgz#da1de4ae905b1b9ff682cab0bed6b2e3be9c04e5" + integrity sha512-LmE/KO6DUy0nFY/OoQU0XelnmDt+V8lPQhh8MOVa7Y5k2gGRd6U9Kp3wAjhB4OHg57tUO0nOnwYQhRRyEAyOyg== + +"@typescript-eslint/typescript-estree@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.13.0.tgz#b37c07b748ff030a3e93d87c842714e020b78141" + integrity sha512-Q9cQow0DeLjnp5DuEDjLZ6JIkwGx3oYZe+BfcNuw/POhtpcxMTy18Icl6BJqTSd+3ftsrfuVb7mNHRZf7xiaNA== + dependencies: + "@typescript-eslint/types" "5.13.0" + "@typescript-eslint/visitor-keys" "5.13.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.13.0.tgz#f45ff55bcce16403b221ac9240fbeeae4764f0fd" + integrity sha512-HLKEAS/qA1V7d9EzcpLFykTePmOQqOFim8oCvhY3pZgQ8Hi38hYpHd9e5GN6nQBFQNecNhws5wkS9Y5XIO0s/g== + dependencies: + "@typescript-eslint/types" "5.13.0" + eslint-visitor-keys "^3.0.0" + "@vitejs/plugin-vue@^2.0.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-2.1.0.tgz#ddf5e0059f84f2ff649afc25ce5a59211e670542" @@ -2089,6 +2162,11 @@ acorn-import-assertions@^1.7.6: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + acorn-node@^1.6.1: version "1.8.2" resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" @@ -2118,7 +2196,7 @@ acorn@^7.0.0, acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4, acorn@^8.0.5, acorn@^8.4.1: +acorn@^8.0.4, acorn@^8.0.5, acorn@^8.4.1, acorn@^8.7.0: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== @@ -2160,7 +2238,7 @@ ajv-keywords@^5.0.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2277,6 +2355,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -3351,7 +3434,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3528,7 +3611,7 @@ debug@^3.1.1: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== @@ -3552,6 +3635,11 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + deepmerge@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" @@ -3724,6 +3812,13 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + doctypes@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" @@ -4046,6 +4141,21 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-plugin-vue@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.5.0.tgz#65832bba43ca713fa5da16bdfcf55d0095677f6f" + integrity sha512-i1uHCTAKOoEj12RDvdtONWrGzjFm/djkzqfhmQ0d6M/W8KM81mhswd/z+iTZ0jCpdUedW3YRgcVfQ37/J4zoYQ== + dependencies: + eslint-utils "^3.0.0" + natural-compare "^1.4.0" + semver "^7.3.5" + vue-eslint-parser "^8.0.1" + eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -4062,11 +4172,93 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^7.0.0, eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" + integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== + dependencies: + "@eslint/eslintrc" "^1.2.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.6.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.0.0, espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.1.0, esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" @@ -4079,7 +4271,7 @@ estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -4289,6 +4481,11 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + fastq@^1.6.0: version "1.13.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" @@ -4315,6 +4512,13 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + file-saver@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" @@ -4388,6 +4592,19 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -4529,6 +4746,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4626,7 +4848,14 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globby@^11.0.1, globby@^11.0.2, globby@^11.0.3: +globals@^13.6.0, globals@^13.9.0: + version "13.12.1" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.1.tgz#ec206be932e6c77236677127577aa8e50bf1c5cb" + integrity sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -4961,7 +5190,7 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore@^4.0.3: +ignore@^4.0.3, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== @@ -4976,7 +5205,7 @@ immutable@^4.0.0: resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== -import-fresh@^3.1.0, import-fresh@^3.2.1: +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -5373,6 +5602,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -5413,6 +5649,11 @@ json-schema@0.4.0: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -5513,6 +5754,14 @@ launch-editor@^2.2.1, launch-editor@^2.3.0: picocolors "^1.0.0" shell-quote "^1.6.1" +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + lilconfig@^2.0.3, lilconfig@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" @@ -5591,6 +5840,11 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -5979,6 +6233,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -6235,6 +6494,18 @@ opener@^1.5.2: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + ora@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" @@ -6817,7 +7088,12 @@ postcss@^8.1.10, postcss@^8.2.15, postcss@^8.2.6, postcss@^8.3.5, postcss@^8.4.5 picocolors "^1.0.0" source-map-js "^1.0.2" -"prettier@^1.18.2 || ^2.0.0": +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@2.5.1, "prettier@^1.18.2 || ^2.0.0": version "2.5.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== @@ -7196,6 +7472,11 @@ regexp.prototype.flags@^1.2.0: call-bind "^1.0.2" define-properties "^1.1.3" +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + regexpu-core@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" @@ -7975,6 +8256,11 @@ strip-indent@^2.0.0: resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + stylehacks@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.2.tgz#fa10e5181c6e8dc0bddb4a3fb372e9ac42bba2ad" @@ -8112,6 +8398,11 @@ terser@^5.10.0, terser@^5.7.2: source-map "~0.7.2" source-map-support "~0.5.20" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" @@ -8288,6 +8579,13 @@ tsutils@^2.29.0: dependencies: tslib "^1.8.1" +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -8305,6 +8603,18 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" @@ -8472,6 +8782,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -8644,6 +8959,19 @@ vue-demi@*: resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.12.1.tgz#f7e18efbecffd11ab069d1472d7a06e319b4174c" integrity sha512-QL3ny+wX8c6Xm1/EZylbgzdoDolye+VpCXRhI2hug9dJTP3OUJ3lmiKN3CsVV3mOJKwFi0nsstbgob0vG7aoIw== +vue-eslint-parser@^8.0.1: + version "8.3.0" + resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d" + integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g== + dependencies: + debug "^4.3.2" + eslint-scope "^7.0.0" + eslint-visitor-keys "^3.1.0" + espree "^9.0.0" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^7.3.5" + vue-hot-reload-api@^2.3.0: version "2.3.4" resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2" @@ -8953,6 +9281,11 @@ with@^7.0.0: assert-never "^1.2.1" babel-walk "3.0.0-canary-5" +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" From d8d713f841cf69115c7c3fed395187aa80d6076e Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Tue, 15 Mar 2022 07:53:25 +0000 Subject: [PATCH 02/13] Change prettier configuration --- web/package.json | 76 ++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/web/package.json b/web/package.json index 754215d..335cbc4 100644 --- a/web/package.json +++ b/web/package.json @@ -1,37 +1,43 @@ { - "name": "web", - "version": "0.0.0", - "scripts": { - "serve": "vite preview", - "build": "vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@mdi/font": "5.9.55", - "@vueuse/core": "^7.6.1", - "autoprefixer": "^10.4.2", - "file-saver": "^2.0.5", - "pinia": "^2.0.11", - "postcss": "^8.4.6", - "tailwindcss": "^3.0.18", - "vue": "^3.2.25", - "vue-router": "^4.0.12" - }, - "devDependencies": { - "@types/file-saver": "^2.0.5", - "@typescript-eslint/parser": "^5.13.0", - "@vitejs/plugin-vue": "^2.0.0", - "@vue/cli-plugin-babel": "5.0.0-beta.7", - "@vue/cli-plugin-typescript": "~4.5.0", - "@vue/cli-service": "5.0.0-beta.7", - "eslint": "^8.10.0", - "eslint-plugin-vue": "^8.5.0", - "prettier": "2.5.1", - "sass": "^1.38.0", - "sass-loader": "^10.0.0", - "typescript": "^4.5.5", - "vite": "^2.7.2", - "vue-tsc": "^0.32.0" - } + "name": "web", + "version": "0.0.0", + "scripts": { + "serve": "vite preview", + "build": "vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@mdi/font": "5.9.55", + "@vueuse/core": "^7.6.1", + "autoprefixer": "^10.4.2", + "file-saver": "^2.0.5", + "pinia": "^2.0.11", + "postcss": "^8.4.6", + "tailwindcss": "^3.0.18", + "vue": "^3.2.25", + "vue-router": "^4.0.12" + }, + "devDependencies": { + "@types/file-saver": "^2.0.5", + "@typescript-eslint/parser": "^5.13.0", + "@vitejs/plugin-vue": "^2.0.0", + "@vue/cli-plugin-babel": "5.0.0-beta.7", + "@vue/cli-plugin-typescript": "~4.5.0", + "@vue/cli-service": "5.0.0-beta.7", + "eslint": "^8.10.0", + "eslint-plugin-vue": "^8.5.0", + "prettier": "2.5.1", + "sass": "^1.38.0", + "sass-loader": "^10.0.0", + "typescript": "^4.5.5", + "vite": "^2.7.2", + "vue-tsc": "^0.32.0" + }, + "prettier": { + "bracketSameLine": true, + "embeddedLanguageFormatting": "off", + "tabWidth": 4, + "useTabs": true + } } From 61a534610fd1e70c694cea2457b5d83d12666c0d Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Tue, 15 Mar 2022 12:49:53 +0000 Subject: [PATCH 03/13] Run prettier --- web/.eslintrc.js | 32 +- web/index.html | 21 +- web/postcss.config.js | 10 +- web/src/@types/shims-vue.d.ts | 8 +- web/src/App.vue | 54 +-- web/src/api.ts | 36 +- web/src/components/AccountWithReconciled.vue | 22 +- web/src/components/Autocomplete.vue | 45 ++- web/src/components/Button.vue | 13 +- web/src/components/Card.vue | 12 +- web/src/components/Checkbox.vue | 12 +- web/src/components/Currency.vue | 10 +- web/src/components/DateInput.vue | 15 +- web/src/components/Input.vue | 10 +- web/src/components/Modal.vue | 65 ++-- web/src/components/TransactionEditRow.vue | 61 +-- web/src/components/TransactionInputRow.vue | 67 ++-- web/src/components/TransactionRow.vue | 69 ++-- web/src/date.ts | 13 +- web/src/dialogs/EditAccount.vue | 60 ++- web/src/dialogs/NewBudget.vue | 17 +- web/src/index.css | 12 +- web/src/main.ts | 123 +++--- web/src/pages/Account.vue | 173 +++++---- web/src/pages/Admin.vue | 12 +- web/src/pages/BudgetSidebar.vue | 108 +++--- web/src/pages/Budgeting.vue | 114 ++++-- web/src/pages/Dashboard.vue | 26 +- web/src/pages/Index.vue | 26 +- web/src/pages/Login.vue | 39 +- web/src/pages/Register.vue | 107 +++--- web/src/pages/Settings.vue | 117 +++--- web/src/pinia-logger.ts | 146 ++++--- web/src/router/index.ts | 95 +++-- web/src/stores/budget-account.ts | 378 ++++++++++--------- web/src/stores/budget.ts | 116 +++--- web/src/stores/session.ts | 116 +++--- web/src/stores/settings.ts | 38 +- web/src/stores/transactions.ts | 193 +++++----- web/tailwind.config.js | 15 +- web/tsconfig.json | 18 +- web/vite.config.js | 48 +-- 42 files changed, 1485 insertions(+), 1187 deletions(-) diff --git a/web/.eslintrc.js b/web/.eslintrc.js index 3dc2f88..09e832e 100644 --- a/web/.eslintrc.js +++ b/web/.eslintrc.js @@ -1,17 +1,17 @@ module.exports = { - extends: [ - // add more generic rulesets here, such as: - // 'eslint:recommended', - 'plugin:vue/vue3-recommended', - // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x. - ], - rules: { - // override/add rules settings here, such as: - // 'vue/no-unused-vars': 'error' - }, - "parser": "vue-eslint-parser", - "parserOptions": { - "parser": "@typescript-eslint/parser", - "sourceType": "module" - } -} + extends: [ + // add more generic rulesets here, such as: + // 'eslint:recommended', + "plugin:vue/vue3-recommended", + // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x. + ], + rules: { + // override/add rules settings here, such as: + // 'vue/no-unused-vars': 'error' + }, + parser: "vue-eslint-parser", + parserOptions: { + parser: "@typescript-eslint/parser", + sourceType: "module", + }, +}; diff --git a/web/index.html b/web/index.html index b2535d4..506228f 100644 --- a/web/index.html +++ b/web/index.html @@ -1,13 +1,14 @@ - - - - - Vite App - - -
- - + + + + + Vite App + + +
+ + diff --git a/web/postcss.config.js b/web/postcss.config.js index 33ad091..e873f1a 100644 --- a/web/postcss.config.js +++ b/web/postcss.config.js @@ -1,6 +1,6 @@ module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/web/src/@types/shims-vue.d.ts b/web/src/@types/shims-vue.d.ts index 7dcfc86..811114b 100644 --- a/web/src/@types/shims-vue.d.ts +++ b/web/src/@types/shims-vue.d.ts @@ -1,5 +1,5 @@ declare module "*.vue" { - import { defineComponent } from "vue"; - const component: ReturnType; - export default component; -} \ No newline at end of file + import { defineComponent } from "vue"; + const component: ReturnType; + export default component; +} diff --git a/web/src/App.vue b/web/src/App.vue index 057c1f2..9b55f2f 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -26,29 +26,39 @@ export default defineComponent({ \ No newline at end of file +
+ +
+ + + diff --git a/web/src/api.ts b/web/src/api.ts index c245db5..e5292c9 100644 --- a/web/src/api.ts +++ b/web/src/api.ts @@ -1,26 +1,26 @@ import { useSessionStore } from "./stores/session"; -export const BASE_URL = "/api/v1" +export const BASE_URL = "/api/v1"; export function GET(path: string) { - const sessionStore = useSessionStore(); - return fetch(BASE_URL + path, { - headers: sessionStore.AuthHeaders, - }) -}; + const sessionStore = useSessionStore(); + return fetch(BASE_URL + path, { + headers: sessionStore.AuthHeaders, + }); +} export function POST(path: string, body: FormData | string | null) { - const sessionStore = useSessionStore(); - return fetch(BASE_URL + path, { - method: "POST", - headers: sessionStore.AuthHeaders, - body: body, - }) + const sessionStore = useSessionStore(); + return fetch(BASE_URL + path, { + method: "POST", + headers: sessionStore.AuthHeaders, + body: body, + }); } export function DELETE(path: string) { - const sessionStore = useSessionStore(); - return fetch(BASE_URL + path, { - method: "DELETE", - headers: sessionStore.AuthHeaders, - }) -} \ No newline at end of file + const sessionStore = useSessionStore(); + return fetch(BASE_URL + path, { + method: "DELETE", + headers: sessionStore.AuthHeaders, + }); +} diff --git a/web/src/components/AccountWithReconciled.vue b/web/src/components/AccountWithReconciled.vue index 044c754..21036d7 100644 --- a/web/src/components/AccountWithReconciled.vue +++ b/web/src/components/AccountWithReconciled.vue @@ -19,13 +19,15 @@ function daysSinceLastReconciled() { \ No newline at end of file + + + {{account.Name}} + + + {{daysSinceLastReconciled()}} + + + diff --git a/web/src/components/Autocomplete.vue b/web/src/components/Autocomplete.vue index 470c4be..b3d275c 100644 --- a/web/src/components/Autocomplete.vue +++ b/web/src/components/Autocomplete.vue @@ -81,22 +81,29 @@ function clear() { \ No newline at end of file +
+ + {{ text }} +
+ {{ suggestion.Name }} +
+
+ diff --git a/web/src/components/Button.vue b/web/src/components/Button.vue index 9491068..e3ef6a8 100644 --- a/web/src/components/Button.vue +++ b/web/src/components/Button.vue @@ -1,10 +1,7 @@ - + \ No newline at end of file + + diff --git a/web/src/components/Card.vue b/web/src/components/Card.vue index 6464848..bf9866a 100644 --- a/web/src/components/Card.vue +++ b/web/src/components/Card.vue @@ -1,8 +1,8 @@ - + \ No newline at end of file +
+ +
+ diff --git a/web/src/components/Checkbox.vue b/web/src/components/Checkbox.vue index 544ec52..b2aab40 100644 --- a/web/src/components/Checkbox.vue +++ b/web/src/components/Checkbox.vue @@ -3,9 +3,9 @@ const props = defineProps(["modelValue"]); \ No newline at end of file + + diff --git a/web/src/components/Currency.vue b/web/src/components/Currency.vue index 809df4f..31c13cc 100644 --- a/web/src/components/Currency.vue +++ b/web/src/components/Currency.vue @@ -1,7 +1,7 @@ \ No newline at end of file + {{ formattedValue }} € + diff --git a/web/src/components/DateInput.vue b/web/src/components/DateInput.vue index 5177b1e..473ad41 100644 --- a/web/src/components/DateInput.vue +++ b/web/src/components/DateInput.vue @@ -26,11 +26,10 @@ function selectAll(event: FocusEvent) { \ No newline at end of file + + diff --git a/web/src/components/Input.vue b/web/src/components/Input.vue index 831cbe1..9b0e32d 100644 --- a/web/src/components/Input.vue +++ b/web/src/components/Input.vue @@ -3,8 +3,8 @@ const props = defineProps(["modelValue"]); \ No newline at end of file + + diff --git a/web/src/components/Modal.vue b/web/src/components/Modal.vue index d628210..721098d 100644 --- a/web/src/components/Modal.vue +++ b/web/src/components/Modal.vue @@ -30,33 +30,38 @@ function submitDialog() { \ No newline at end of file + +
+
+
+

+ {{ buttonText }} +

+ +
+ + +
+
+
+
+ diff --git a/web/src/components/TransactionEditRow.vue b/web/src/components/TransactionEditRow.vue index c7e3f4e..0e0364d 100644 --- a/web/src/components/TransactionEditRow.vue +++ b/web/src/components/TransactionEditRow.vue @@ -38,29 +38,38 @@ function saveTransaction(e: MouseEvent) { \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/components/TransactionInputRow.vue b/web/src/components/TransactionInputRow.vue index d892eda..5c79180 100644 --- a/web/src/components/TransactionInputRow.vue +++ b/web/src/components/TransactionInputRow.vue @@ -52,32 +52,41 @@ function saveTransaction(e: MouseEvent) { \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/components/TransactionRow.vue b/web/src/components/TransactionRow.vue index 0d87765..73cd718 100644 --- a/web/src/components/TransactionRow.vue +++ b/web/src/components/TransactionRow.vue @@ -47,34 +47,45 @@ function getStatusSymbol() { \ No newline at end of file + diff --git a/web/src/date.ts b/web/src/date.ts index de7fccf..64a8217 100644 --- a/web/src/date.ts +++ b/web/src/date.ts @@ -1,7 +1,8 @@ export function formatDate(date: Date): string { - return date.toLocaleDateString(undefined, { // you can use undefined as first argument - year: "numeric", - month: "2-digit", - day: "2-digit", - }); -} \ No newline at end of file + return date.toLocaleDateString(undefined, { + // you can use undefined as first argument + year: "numeric", + month: "2-digit", + day: "2-digit", + }); +} diff --git a/web/src/dialogs/EditAccount.vue b/web/src/dialogs/EditAccount.vue index d8e3515..707392f 100644 --- a/web/src/dialogs/EditAccount.vue +++ b/web/src/dialogs/EditAccount.vue @@ -20,7 +20,7 @@ function editAccount(e : {cancel:boolean}) : boolean { if(CurrentAccount.value?.ClearedBalance != 0 && !accountOpen.value){ e.cancel = true; error.value = "Cannot close account with balance"; - return false; + return false; } error.value = ""; @@ -42,35 +42,29 @@ function openEditAccount(e : any) { \ No newline at end of file + + +
+ +
+
+ + +
+
+ + +
+
+ {{ error }} +
+
+ diff --git a/web/src/dialogs/NewBudget.vue b/web/src/dialogs/NewBudget.vue index 86d72d7..d1b8de2 100644 --- a/web/src/dialogs/NewBudget.vue +++ b/web/src/dialogs/NewBudget.vue @@ -11,9 +11,14 @@ function saveBudget() { \ No newline at end of file + +
+ +
+
+ diff --git a/web/src/index.css b/web/src/index.css index 345b41c..8fad555 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -3,15 +3,15 @@ @tailwind utilities; h1 { - font-size: 200%; + font-size: 200%; } a { - text-decoration: underline; + text-decoration: underline; } #app { - font-family: Avenir, Helvetica, Arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} \ No newline at end of file + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/web/src/main.ts b/web/src/main.ts index 7fdd123..d0c64c2 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -1,72 +1,79 @@ -import { createApp } from 'vue' -import App from './App.vue' -import './index.css' -import router from './router' -import { createPinia } from 'pinia' -import { useBudgetsStore } from './stores/budget'; -import { useAccountStore } from './stores/budget-account' -import PiniaLogger from './pinia-logger' -import { useSessionStore } from './stores/session' +import { createApp } from "vue"; +import App from "./App.vue"; +import "./index.css"; +import router from "./router"; +import { createPinia } from "pinia"; +import { useBudgetsStore } from "./stores/budget"; +import { useAccountStore } from "./stores/budget-account"; +import PiniaLogger from "./pinia-logger"; +import { useSessionStore } from "./stores/session"; -const app = createApp(App) -app.use(router) +const app = createApp(App); +app.use(router); -const pinia = createPinia() -pinia.use(PiniaLogger({ - expanded: false, - showDuration: true -})) -app.use(pinia) -app.mount('#app') +const pinia = createPinia(); +pinia.use( + PiniaLogger({ + expanded: false, + showDuration: true, + }) +); +app.use(pinia); +app.mount("#app"); router.beforeEach(async (to, from, next) => { - const budgetStore = useBudgetsStore(); - await budgetStore.SetCurrentBudget((to.params.budgetid)); + const budgetStore = useBudgetsStore(); + await budgetStore.SetCurrentBudget(to.params.budgetid); - const accountStore = useAccountStore(); - await accountStore.SetCurrentAccount((to.params.budgetid), (to.params.accountid)); - next(); -}) + const accountStore = useAccountStore(); + await accountStore.SetCurrentAccount( + to.params.budgetid, + to.params.accountid + ); + next(); +}); router.beforeEach((to, from, next) => { - const sessionStore = useSessionStore(); - const token = sessionStore.Session?.Token; - let loggedIn = false; + const sessionStore = useSessionStore(); + const token = sessionStore.Session?.Token; + let loggedIn = false; - if (token != null) { - const jwt = parseJwt(token); - if (jwt.exp > Date.now() / 1000) - loggedIn = true; - } + if (token != null) { + const jwt = parseJwt(token); + if (jwt.exp > Date.now() / 1000) loggedIn = true; + } - if (to.matched.some(record => record.meta.requiresAuth)) { - if (!loggedIn) { - next({ path: '/login' }); - } else { - next(); - } - - } else if (to.matched.some(record => record.meta.hideForAuth)) { - if (loggedIn) { - next({ path: '/dashboard' }); - } else { - next(); - } - } else { - next(); - } + if (to.matched.some((record) => record.meta.requiresAuth)) { + if (!loggedIn) { + next({ path: "/login" }); + } else { + next(); + } + } else if (to.matched.some((record) => record.meta.hideForAuth)) { + if (loggedIn) { + next({ path: "/dashboard" }); + } else { + next(); + } + } else { + next(); + } }); function parseJwt(token: string) { - var base64Url = token.split('.')[1]; - var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); - var jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); + var base64Url = token.split(".")[1]; + var base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); + var jsonPayload = decodeURIComponent( + atob(base64) + .split("") + .map(function (c) { + return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); + }) + .join("") + ); - return JSON.parse(jsonPayload); -}; + return JSON.parse(jsonPayload); +} - -1646426130 -1646512855755 \ No newline at end of file +1646426130; +1646512855755; diff --git a/web/src/pages/Account.vue b/web/src/pages/Account.vue index 37949bb..5cfdd70 100644 --- a/web/src/pages/Account.vue +++ b/web/src/pages/Account.vue @@ -42,94 +42,101 @@ function createReconcilationTransaction() { \ No newline at end of file + diff --git a/web/src/pages/Admin.vue b/web/src/pages/Admin.vue index 183df55..da0687d 100644 --- a/web/src/pages/Admin.vue +++ b/web/src/pages/Admin.vue @@ -8,9 +8,9 @@ onMounted(() => { \ No newline at end of file +

Danger Zone

+
+ +

This removes all data and starts from scratch. Not undoable!

+
+ diff --git a/web/src/pages/BudgetSidebar.vue b/web/src/pages/BudgetSidebar.vue index 0407e76..8cb72c5 100644 --- a/web/src/pages/BudgetSidebar.vue +++ b/web/src/pages/BudgetSidebar.vue @@ -22,45 +22,59 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa diff --git a/web/src/pages/Budgeting.vue b/web/src/pages/Budgeting.vue index 13a0c7b..86af6cd 100644 --- a/web/src/pages/Budgeting.vue +++ b/web/src/pages/Budgeting.vue @@ -69,47 +69,85 @@ function getGroupState(group: { Name: string, Expand: boolean }): boolean { function assignedChanged(e : Event, category : Category){ const target = e.target as HTMLInputElement; const value = target.valueAsNumber; - POST("/budget/"+CurrentBudgetID.value+"/category/" + category.ID + "/" + selected.value.Year + "/" + (selected.value.Month+1), + POST("/budget/"+CurrentBudgetID.value+"/category/" + category.ID + "/" + selected.value.Year + "/" + (selected.value.Month+1), JSON.stringify({Assigned: category.Assigned})); } diff --git a/web/src/pages/Dashboard.vue b/web/src/pages/Dashboard.vue index 1325af1..ec4aac2 100644 --- a/web/src/pages/Dashboard.vue +++ b/web/src/pages/Dashboard.vue @@ -11,15 +11,19 @@ const BudgetsList = useSessionStore().BudgetsList; diff --git a/web/src/pages/Index.vue b/web/src/pages/Index.vue index d16481a..916684d 100644 --- a/web/src/pages/Index.vue +++ b/web/src/pages/Index.vue @@ -1,13 +1,13 @@ - - - \ No newline at end of file + + + diff --git a/web/src/pages/Login.vue b/web/src/pages/Login.vue index 0914df1..964865d 100644 --- a/web/src/pages/Login.vue +++ b/web/src/pages/Login.vue @@ -28,18 +28,27 @@ function formSubmit(e: MouseEvent) { \ No newline at end of file +
+ + +
+
{{ error }}
+ +

+ New user? + Register instead! +

+ diff --git a/web/src/pages/Register.vue b/web/src/pages/Register.vue index cc4a1ec..a2f13a8 100644 --- a/web/src/pages/Register.vue +++ b/web/src/pages/Register.vue @@ -1,48 +1,59 @@ - - - \ No newline at end of file + + + diff --git a/web/src/pages/Settings.vue b/web/src/pages/Settings.vue index 21dab9a..d605b47 100644 --- a/web/src/pages/Settings.vue +++ b/web/src/pages/Settings.vue @@ -72,53 +72,82 @@ function ynabExport() { saveAs(blob, timeStamp + " " + CurrentBudgetName.value + " - Transactions.tsv"); }) } - \ No newline at end of file + + + +

Export as YNAB TSV

+ +
+ +
+
+ + + diff --git a/web/src/pinia-logger.ts b/web/src/pinia-logger.ts index ff30b98..f6c419d 100644 --- a/web/src/pinia-logger.ts +++ b/web/src/pinia-logger.ts @@ -1,81 +1,107 @@ -import { PiniaPluginContext, StoreGeneric, _ActionsTree, _StoreOnActionListenerContext } from 'pinia'; +import { + PiniaPluginContext, + StoreGeneric, + _ActionsTree, + _StoreOnActionListenerContext, +} from "pinia"; const cloneDeep = (obj: T): T => { - try { - return JSON.parse(JSON.stringify(obj)); - } catch { - return { ...obj }; - } + try { + return JSON.parse(JSON.stringify(obj)); + } catch { + return { ...obj }; + } }; const formatTime = (date = new Date()) => { - const hours = date.getHours().toString().padStart(2, '0'); - const minutes = date.getMinutes().toString().padStart(2, '0'); - const seconds = date.getSeconds().toString().padStart(2, '0'); + const hours = date.getHours().toString().padStart(2, "0"); + const minutes = date.getMinutes().toString().padStart(2, "0"); + const seconds = date.getSeconds().toString().padStart(2, "0"); - return `${hours}:${minutes}:${seconds}`; + return `${hours}:${minutes}:${seconds}`; }; export interface PiniaLoggerOptions { - disabled?: boolean; - expanded?: boolean; - showDuration?: boolean - showStoreName?: boolean; - logErrors?: boolean; + disabled?: boolean; + expanded?: boolean; + showDuration?: boolean; + showStoreName?: boolean; + logErrors?: boolean; } -export type PiniaActionListenerContext = _StoreOnActionListenerContext; +export type PiniaActionListenerContext = _StoreOnActionListenerContext< + StoreGeneric, + string, + _ActionsTree +>; const defaultOptions: PiniaLoggerOptions = { - logErrors: true, - disabled: false, - expanded: true, - showStoreName: true, - showDuration: false, + logErrors: true, + disabled: false, + expanded: true, + showStoreName: true, + showDuration: false, }; -export const PiniaLogger = (config = defaultOptions) => (ctx: PiniaPluginContext) => { - const options = { - ...defaultOptions, - ...config, - }; +export const PiniaLogger = + (config = defaultOptions) => + (ctx: PiniaPluginContext) => { + const options = { + ...defaultOptions, + ...config, + }; - if (options.disabled) return; + if (options.disabled) return; + ctx.store.$onAction((action: PiniaActionListenerContext) => { + const startTime = Date.now(); + const prevState = cloneDeep(ctx.store.$state); - ctx.store.$onAction((action: PiniaActionListenerContext) => { - const startTime = Date.now(); - const prevState = cloneDeep(ctx.store.$state); + const log = (isError?: boolean, error?: any) => { + const endTime = Date.now(); + const duration = endTime - startTime + "ms"; + const nextState = cloneDeep(ctx.store.$state); + const storeName = action.store.$id; + const title = `${formatTime()} action 🍍 ${ + options.showStoreName ? `[${storeName}] ` : "" + }${action.name} ${ + isError ? `failed after ` : "" + }in ${duration}`; - const log = (isError?: boolean, error?: any) => { - const endTime = Date.now(); - const duration = endTime - startTime + 'ms'; - const nextState = cloneDeep(ctx.store.$state); - const storeName = action.store.$id; - const title = `${formatTime()} action 🍍 ${options.showStoreName ? `[${storeName}] ` : ''}${action.name} ${isError ? `failed after ` : ''}in ${duration}`; + console[options.expanded ? "group" : "groupCollapsed"]( + `%c${title}`, + `font-weight: bold; ${isError ? "color: #ed4981;" : ""}` + ); + console.log( + "%cprev state", + "font-weight: bold; color: grey;", + prevState + ); + console.log("%caction", "font-weight: bold; color: #69B7FF;", { + type: action.name, + args: + action.args.length > 0 ? { ...action.args } : undefined, + ...(options.showStoreName && { store: action.store.$id }), + ...(options.showDuration && { duration }), + ...(isError && { error }), + }); + console.log( + "%cnext state", + "font-weight: bold; color: #4caf50;", + nextState + ); + console.groupEnd(); + }; - console[options.expanded ? 'group' : 'groupCollapsed'](`%c${title}`, `font-weight: bold; ${isError ? 'color: #ed4981;' : ''}`); - console.log('%cprev state', 'font-weight: bold; color: grey;', prevState); - console.log('%caction', 'font-weight: bold; color: #69B7FF;', { - type: action.name, - args: action.args.length > 0 ? { ...action.args } : undefined, - ...(options.showStoreName && { store: action.store.$id }), - ...(options.showDuration && { duration }), - ...(isError && { error }), - }); - console.log('%cnext state', 'font-weight: bold; color: #4caf50;', nextState); - console.groupEnd(); - }; + action.after(() => { + log(); + }); - action.after(() => { - log(); - }); + if (options.logErrors) { + action.onError((error) => { + log(true, error); + }); + } + }); + }; - if (options.logErrors) { - action.onError((error) => { - log(true, error); - }); - } - }); -}; - -export default PiniaLogger; \ No newline at end of file +export default PiniaLogger; diff --git a/web/src/router/index.ts b/web/src/router/index.ts index 03b9870..91217e6 100644 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -1,30 +1,75 @@ -import { createRouter, createWebHistory, RouteLocationNormalized } from 'vue-router' -import Dashboard from '../pages/Dashboard.vue'; -import Login from '../pages/Login.vue'; -import Index from '../pages/Index.vue'; -import Register from '../pages/Register.vue'; -import Account from '@/pages/Account.vue'; -import Settings from '../pages/Settings.vue'; -import Budgeting from '../pages/Budgeting.vue'; -import BudgetSidebar from '../pages/BudgetSidebar.vue'; +import { + createRouter, + createWebHistory, + RouteLocationNormalized, +} from "vue-router"; +import Dashboard from "../pages/Dashboard.vue"; +import Login from "../pages/Login.vue"; +import Index from "../pages/Index.vue"; +import Register from "../pages/Register.vue"; +import Account from "@/pages/Account.vue"; +import Settings from "../pages/Settings.vue"; +import Budgeting from "../pages/Budgeting.vue"; +import BudgetSidebar from "../pages/BudgetSidebar.vue"; const routes = [ - { path: "/", name: "Index", component: Index }, - { path: "/dashboard", name: "Dashboard", component: Dashboard, meta: { requiresAuth: true } }, - { path: "/login", name: "Login", component: Login, meta: { hideForAuth: true } }, - { path: "/register", name: "Register", component: Register, meta: { hideForAuth: true } }, - { path: "/budget/:budgetid/budgeting", name: "Budget", redirect: (to : RouteLocationNormalized) => - '/budget/' + to.params.budgetid + '/budgeting/' + new Date().getFullYear() + '/' + new Date().getMonth(), - meta: { requiresAuth: true } - }, - { path: "/budget/:budgetid/budgeting/:year/:month", name: "Budget with date", components: { default: Budgeting, sidebar: BudgetSidebar }, props: true, meta: { requiresAuth: true } }, - { path: "/budget/:budgetid/Settings", name: "Budget Settings", components: { default: Settings, sidebar: BudgetSidebar }, props: true, meta: { requiresAuth: true } }, - { path: "/budget/:budgetid/account/:accountid", name: "Account", components: { default: Account, sidebar: BudgetSidebar }, props: true, meta: { requiresAuth: true } }, -] + { path: "/", name: "Index", component: Index }, + { + path: "/dashboard", + name: "Dashboard", + component: Dashboard, + meta: { requiresAuth: true }, + }, + { + path: "/login", + name: "Login", + component: Login, + meta: { hideForAuth: true }, + }, + { + path: "/register", + name: "Register", + component: Register, + meta: { hideForAuth: true }, + }, + { + path: "/budget/:budgetid/budgeting", + name: "Budget", + redirect: (to: RouteLocationNormalized) => + "/budget/" + + to.params.budgetid + + "/budgeting/" + + new Date().getFullYear() + + "/" + + new Date().getMonth(), + meta: { requiresAuth: true }, + }, + { + path: "/budget/:budgetid/budgeting/:year/:month", + name: "Budget with date", + components: { default: Budgeting, sidebar: BudgetSidebar }, + props: true, + meta: { requiresAuth: true }, + }, + { + path: "/budget/:budgetid/Settings", + name: "Budget Settings", + components: { default: Settings, sidebar: BudgetSidebar }, + props: true, + meta: { requiresAuth: true }, + }, + { + path: "/budget/:budgetid/account/:accountid", + name: "Account", + components: { default: Account, sidebar: BudgetSidebar }, + props: true, + meta: { requiresAuth: true }, + }, +]; const router = createRouter({ - history: createWebHistory(), - routes, -}) + history: createWebHistory(), + routes, +}); -export default router \ No newline at end of file +export default router; diff --git a/web/src/stores/budget-account.ts b/web/src/stores/budget-account.ts index e582248..9e2a4e1 100644 --- a/web/src/stores/budget-account.ts +++ b/web/src/stores/budget-account.ts @@ -1,195 +1,233 @@ -import { defineStore } from "pinia" +import { defineStore } from "pinia"; import { GET, POST } from "../api"; import { useBudgetsStore } from "./budget"; import { useSessionStore } from "./session"; import { useTransactionsStore } from "./transactions"; interface State { - Accounts: Map - CurrentAccountID: string | null - Categories: Map - Months: Map>> - Assignments: [] + Accounts: Map; + CurrentAccountID: string | null; + Categories: Map; + Months: Map>>; + Assignments: []; } export interface Account { - ID: string - Name: string - OnBudget: boolean - IsOpen: boolean - ClearedBalance: number - WorkingBalance: number - ReconciledBalance: number - Transactions: string[] - LastReconciled: NullDate + ID: string; + Name: string; + OnBudget: boolean; + IsOpen: boolean; + ClearedBalance: number; + WorkingBalance: number; + ReconciledBalance: number; + Transactions: string[]; + LastReconciled: NullDate; } interface NullDate { - Valid: boolean - Time: Date + Valid: boolean; + Time: Date; } export interface Category { - ID: string - Group: string - Name: string - AvailableLastMonth: number - Assigned: number - Activity: number + ID: string; + Group: string; + Name: string; + AvailableLastMonth: number; + Assigned: number; + Activity: number; } export const useAccountStore = defineStore("budget/account", { - state: (): State => ({ - Accounts: new Map(), - CurrentAccountID: null, - Months: new Map>>(), - Categories: new Map(), - Assignments: [], - }), - getters: { - AccountsList(state) { - return [...state.Accounts.values()]; - }, - AllCategoriesForMonth: (state) => (year: number, month: number) => { - const yearMap = state.Months.get(year); - const monthMap = yearMap?.get(month); - return [...monthMap?.values() || []]; - }, - GetCategoryAvailable(state) { - return (category: Category): number => { - return category.AvailableLastMonth + Number(category.Assigned) + category.Activity; - } - }, - GetIncomeCategoryID(state) { - const budget = useBudgetsStore(); - return budget.CurrentBudget?.IncomeCategoryID; - }, - GetIncomeAvailable(state) { - return (year: number, month: number) => { - const IncomeCategoryID = this.GetIncomeCategoryID; - if (IncomeCategoryID == null) - return 0; + state: (): State => ({ + Accounts: new Map(), + CurrentAccountID: null, + Months: new Map>>(), + Categories: new Map(), + Assignments: [], + }), + getters: { + AccountsList(state) { + return [...state.Accounts.values()]; + }, + AllCategoriesForMonth: (state) => (year: number, month: number) => { + const yearMap = state.Months.get(year); + const monthMap = yearMap?.get(month); + return [...(monthMap?.values() || [])]; + }, + GetCategoryAvailable(state) { + return (category: Category): number => { + return ( + category.AvailableLastMonth + + Number(category.Assigned) + + category.Activity + ); + }; + }, + GetIncomeCategoryID(state) { + const budget = useBudgetsStore(); + return budget.CurrentBudget?.IncomeCategoryID; + }, + GetIncomeAvailable(state) { + return (year: number, month: number) => { + const IncomeCategoryID = this.GetIncomeCategoryID; + if (IncomeCategoryID == null) return 0; - const categories = this.AllCategoriesForMonth(year, month); - const category = categories.filter(x => x.ID == IncomeCategoryID)[0]; - if (category == null) - return 0; - return category.AvailableLastMonth; - } - }, - CategoryGroupsForMonth(state) { - return (year: number, month: number) => { - const categories = this.AllCategoriesForMonth(year, month); - const categoryGroups = []; - let prev = undefined; - for (const category of categories) { - if (category.ID == this.GetIncomeCategoryID) - continue; + const categories = this.AllCategoriesForMonth(year, month); + const category = categories.filter( + (x) => x.ID == IncomeCategoryID + )[0]; + if (category == null) return 0; + return category.AvailableLastMonth; + }; + }, + CategoryGroupsForMonth(state) { + return (year: number, month: number) => { + const categories = this.AllCategoriesForMonth(year, month); + const categoryGroups = []; + let prev = undefined; + for (const category of categories) { + if (category.ID == this.GetIncomeCategoryID) continue; - if (prev == undefined || category.Group != prev.Name) { - prev = { - Name: category.Group, - Available: this.GetCategoryAvailable(category), - AvailableLastMonth: category.AvailableLastMonth, - Activity: category.Activity, - Assigned: category.Assigned, - } - categoryGroups.push({ - ...prev, - Expand: prev.Name != "Hidden Categories", - }); - } else { - categoryGroups[categoryGroups.length-1].Available += this.GetCategoryAvailable(category); - categoryGroups[categoryGroups.length-1].AvailableLastMonth += category.AvailableLastMonth; - categoryGroups[categoryGroups.length-1].Activity += category.Activity; - categoryGroups[categoryGroups.length-1].Assigned += category.Assigned; - continue; - } - } - return categoryGroups; - } - }, - CategoriesForMonthAndGroup(state) { - return (year: number, month: number, group: string) => { - const categories = this.AllCategoriesForMonth(year, month); - return categories.filter(x => x.Group == group); - } - }, - GetAccount(state) { - return (accountid: string) => { - return this.Accounts.get(accountid); - } - }, - CurrentAccount(state): Account | undefined { - if (state.CurrentAccountID == null) - return undefined; + if (prev == undefined || category.Group != prev.Name) { + prev = { + Name: category.Group, + Available: this.GetCategoryAvailable(category), + AvailableLastMonth: category.AvailableLastMonth, + Activity: category.Activity, + Assigned: category.Assigned, + }; + categoryGroups.push({ + ...prev, + Expand: prev.Name != "Hidden Categories", + }); + } else { + categoryGroups[categoryGroups.length - 1].Available += + this.GetCategoryAvailable(category); + categoryGroups[ + categoryGroups.length - 1 + ].AvailableLastMonth += category.AvailableLastMonth; + categoryGroups[categoryGroups.length - 1].Activity += + category.Activity; + categoryGroups[categoryGroups.length - 1].Assigned += + category.Assigned; + continue; + } + } + return categoryGroups; + }; + }, + CategoriesForMonthAndGroup(state) { + return (year: number, month: number, group: string) => { + const categories = this.AllCategoriesForMonth(year, month); + return categories.filter((x) => x.Group == group); + }; + }, + GetAccount(state) { + return (accountid: string) => { + return this.Accounts.get(accountid); + }; + }, + CurrentAccount(state): Account | undefined { + if (state.CurrentAccountID == null) return undefined; - return this.GetAccount(state.CurrentAccountID); - }, - OnBudgetAccounts(state) { - return [...state.Accounts.values()].filter(x => x.OnBudget); - }, - OnBudgetAccountsBalance(state): number { - return this.OnBudgetAccounts.reduce((prev, curr) => prev + Number(curr.ClearedBalance), 0); - }, - OffBudgetAccounts(state) { - return [...state.Accounts.values()].filter(x => !x.OnBudget); - }, - OffBudgetAccountsBalance(state): number { - return this.OffBudgetAccounts.reduce((prev, curr) => prev + Number(curr.ClearedBalance), 0); - }, - }, - actions: { - async SetCurrentAccount(budgetid: string, accountid: string) { - if (budgetid == null) - return; + return this.GetAccount(state.CurrentAccountID); + }, + OnBudgetAccounts(state) { + return [...state.Accounts.values()].filter((x) => x.OnBudget); + }, + OnBudgetAccountsBalance(state): number { + return this.OnBudgetAccounts.reduce( + (prev, curr) => prev + Number(curr.ClearedBalance), + 0 + ); + }, + OffBudgetAccounts(state) { + return [...state.Accounts.values()].filter((x) => !x.OnBudget); + }, + OffBudgetAccountsBalance(state): number { + return this.OffBudgetAccounts.reduce( + (prev, curr) => prev + Number(curr.ClearedBalance), + 0 + ); + }, + }, + actions: { + async SetCurrentAccount(budgetid: string, accountid: string) { + if (budgetid == null) return; - this.CurrentAccountID = accountid; + this.CurrentAccountID = accountid; - if (accountid == null) - return; - const account = this.GetAccount(accountid)!; - useSessionStore().setTitle(account.Name); - await this.FetchAccount(account); - }, - async FetchAccount(account: Account) { - const result = await GET("/account/" + account.ID + "/transactions"); - const response = await result.json(); - const transactionsStore = useTransactionsStore() - const transactions = transactionsStore.AddTransactions(response.Transactions); - account.Transactions = transactions; - }, - async FetchMonthBudget(budgetid: string, year: number, month: number) { - const result = await GET("/budget/" + budgetid + "/" + year + "/" + (month + 1)); - const response = await result.json(); - if (response.Categories == undefined || response.Categories.length <= 0) - return; - this.addCategoriesForMonth(year, month, response.Categories); - }, - async EditAccount(accountid: string, name: string, onBudget: boolean, isOpen: boolean) { - const result = await POST("/account/" + accountid, JSON.stringify({ name: name, onBudget: onBudget, isOpen: isOpen })); - const response = await result.json(); - useBudgetsStore().MergeBudgetingData(response); + if (accountid == null) return; + const account = this.GetAccount(accountid)!; + useSessionStore().setTitle(account.Name); + await this.FetchAccount(account); + }, + async FetchAccount(account: Account) { + const result = await GET( + "/account/" + account.ID + "/transactions" + ); + const response = await result.json(); + const transactionsStore = useTransactionsStore(); + const transactions = transactionsStore.AddTransactions( + response.Transactions + ); + account.Transactions = transactions; + }, + async FetchMonthBudget(budgetid: string, year: number, month: number) { + const result = await GET( + "/budget/" + budgetid + "/" + year + "/" + (month + 1) + ); + const response = await result.json(); + if ( + response.Categories == undefined || + response.Categories.length <= 0 + ) + return; + this.addCategoriesForMonth(year, month, response.Categories); + }, + async EditAccount( + accountid: string, + name: string, + onBudget: boolean, + isOpen: boolean + ) { + const result = await POST( + "/account/" + accountid, + JSON.stringify({ + name: name, + onBudget: onBudget, + isOpen: isOpen, + }) + ); + const response = await result.json(); + useBudgetsStore().MergeBudgetingData(response); - if (!isOpen) { - this.Accounts.delete(accountid); - } - }, - addCategoriesForMonth(year: number, month: number, categories: Category[]): void { - this.$patch((state) => { - const yearMap = state.Months.get(year) || new Map>(); - const monthMap = yearMap.get(month) || new Map(); - for (const category of categories) { - monthMap.set(category.ID, category); - } + if (!isOpen) { + this.Accounts.delete(accountid); + } + }, + addCategoriesForMonth( + year: number, + month: number, + categories: Category[] + ): void { + this.$patch((state) => { + const yearMap = + state.Months.get(year) || + new Map>(); + const monthMap = + yearMap.get(month) || new Map(); + for (const category of categories) { + monthMap.set(category.ID, category); + } - yearMap.set(month, monthMap); - state.Months.set(year, yearMap); - }); - }, - logout() { - this.$reset() - }, - } - -}) + yearMap.set(month, monthMap); + state.Months.set(year, yearMap); + }); + }, + logout() { + this.$reset(); + }, + }, +}); diff --git a/web/src/stores/budget.ts b/web/src/stores/budget.ts index 49b8310..f89af7a 100644 --- a/web/src/stores/budget.ts +++ b/web/src/stores/budget.ts @@ -4,67 +4,67 @@ import { useAccountStore } from "./budget-account"; import { Budget, useSessionStore } from "./session"; interface State { - CurrentBudgetID: string | null, + CurrentBudgetID: string | null; } -export const useBudgetsStore = defineStore('budget', { - state: (): State => ({ - CurrentBudgetID: null, - }), - getters: { - CurrentBudget(): Budget | undefined { - if (this.CurrentBudgetID == null) - return undefined; +export const useBudgetsStore = defineStore("budget", { + state: (): State => ({ + CurrentBudgetID: null, + }), + getters: { + CurrentBudget(): Budget | undefined { + if (this.CurrentBudgetID == null) return undefined; - const sessionStore = useSessionStore(); - return sessionStore.Budgets.get(this.CurrentBudgetID); - }, - CurrentBudgetName(state): string { - return this.CurrentBudget?.Name ?? ""; - }, - }, - actions: { - ImportYNAB(formData: FormData) { - return POST( - "/budget/" + this.CurrentBudgetID + "/import/ynab", - formData, - ); - }, - async NewBudget(budgetName: string): Promise { - const result = await POST( - "/budget/new", - JSON.stringify({ name: budgetName }) - ); - const response = await result.json(); + const sessionStore = useSessionStore(); + return sessionStore.Budgets.get(this.CurrentBudgetID); + }, + CurrentBudgetName(state): string { + return this.CurrentBudget?.Name ?? ""; + }, + }, + actions: { + ImportYNAB(formData: FormData) { + return POST( + "/budget/" + this.CurrentBudgetID + "/import/ynab", + formData + ); + }, + async NewBudget(budgetName: string): Promise { + const result = await POST( + "/budget/new", + JSON.stringify({ name: budgetName }) + ); + const response = await result.json(); - const sessionStore = useSessionStore(); - sessionStore.Budgets.set(response.ID, response); - }, - async SetCurrentBudget(budgetid: string): Promise { - this.CurrentBudgetID = budgetid; + const sessionStore = useSessionStore(); + sessionStore.Budgets.set(response.ID, response); + }, + async SetCurrentBudget(budgetid: string): Promise { + this.CurrentBudgetID = budgetid; - if (budgetid == null) - return + if (budgetid == null) return; - await this.FetchBudget(budgetid); - }, - async FetchBudget(budgetid: string) { - const result = await GET("/budget/" + budgetid); - const response = await result.json(); - this.MergeBudgetingData(response); - }, - MergeBudgetingData(response: any) { - const accounts = useAccountStore(); - for (const account of response.Accounts || []) { - const existingAccount = accounts.Accounts.get(account.ID); - account.Transactions = existingAccount?.Transactions ?? []; - if(account.LastReconciled.Valid) - account.LastReconciled.Time = new Date(account.LastReconciled.Time); - accounts.Accounts.set(account.ID, account); - } - for (const category of response.Categories || []) { - accounts.Categories.set(category.ID, category); - } - }, - } -}) \ No newline at end of file + await this.FetchBudget(budgetid); + }, + async FetchBudget(budgetid: string) { + const result = await GET("/budget/" + budgetid); + const response = await result.json(); + this.MergeBudgetingData(response); + }, + MergeBudgetingData(response: any) { + const accounts = useAccountStore(); + for (const account of response.Accounts || []) { + const existingAccount = accounts.Accounts.get(account.ID); + account.Transactions = existingAccount?.Transactions ?? []; + if (account.LastReconciled.Valid) + account.LastReconciled.Time = new Date( + account.LastReconciled.Time + ); + accounts.Accounts.set(account.ID, account); + } + for (const category of response.Categories || []) { + accounts.Categories.set(category.ID, category); + } + }, + }, +}); diff --git a/web/src/stores/session.ts b/web/src/stores/session.ts index 5b8d690..e6cfa1f 100644 --- a/web/src/stores/session.ts +++ b/web/src/stores/session.ts @@ -1,62 +1,74 @@ -import { StorageSerializers, useStorage } from '@vueuse/core'; -import { defineStore } from 'pinia' -import { POST } from '../api'; +import { StorageSerializers, useStorage } from "@vueuse/core"; +import { defineStore } from "pinia"; +import { POST } from "../api"; interface State { - Session: Session | null - Budgets: Map, + Session: Session | null; + Budgets: Map; } interface Session { - Token: string - User: string + Token: string; + User: string; } export interface Budget { - ID: string - Name: string - AvailableBalance: number - IncomeCategoryID: string + ID: string; + Name: string; + AvailableBalance: number; + IncomeCategoryID: string; } -export const useSessionStore = defineStore('session', { - state: () => ({ - Session: useStorage('session', null, undefined, { serializer: StorageSerializers.object }), - Budgets: useStorage>('budgets', new Map(), undefined, { serializer: StorageSerializers.map }), - }), - getters: { - BudgetsList: (state) => [ ...state.Budgets.values() ], - AuthHeaders: (state) => ({'Authorization': 'Bearer ' + state.Session?.Token}), - LoggedIn: (state) => state.Session != null, - }, - actions: { - setTitle(title : string) { - document.title = "Budgeteer - " + title; - }, - loginSuccess(x : any) { - this.Session = { - User: x.User, - Token: x.Token, - } - for (const budget of x.Budgets) { - this.Budgets.set(budget.ID, budget); - } - }, - async login(login: any) { - const response = await POST("/user/login", JSON.stringify(login)); - const result = await response.json(); - this.loginSuccess(result); - return result; - }, - async register(login : any) { - const response = await POST("/user/register", JSON.stringify(login)); - const result = await response.json(); - this.loginSuccess(result); - return result; - }, - logout() { - this.Session = null; - this.Budgets.clear(); - }, - } -}) \ No newline at end of file +export const useSessionStore = defineStore("session", { + state: () => ({ + Session: useStorage("session", null, undefined, { + serializer: StorageSerializers.object, + }), + Budgets: useStorage>( + "budgets", + new Map(), + undefined, + { serializer: StorageSerializers.map } + ), + }), + getters: { + BudgetsList: (state) => [...state.Budgets.values()], + AuthHeaders: (state) => ({ + Authorization: "Bearer " + state.Session?.Token, + }), + LoggedIn: (state) => state.Session != null, + }, + actions: { + setTitle(title: string) { + document.title = "Budgeteer - " + title; + }, + loginSuccess(x: any) { + this.Session = { + User: x.User, + Token: x.Token, + }; + for (const budget of x.Budgets) { + this.Budgets.set(budget.ID, budget); + } + }, + async login(login: any) { + const response = await POST("/user/login", JSON.stringify(login)); + const result = await response.json(); + this.loginSuccess(result); + return result; + }, + async register(login: any) { + const response = await POST( + "/user/register", + JSON.stringify(login) + ); + const result = await response.json(); + this.loginSuccess(result); + return result; + }, + logout() { + this.Session = null; + this.Budgets.clear(); + }, + }, +}); diff --git a/web/src/stores/settings.ts b/web/src/stores/settings.ts index c63e70a..4d0ea33 100644 --- a/web/src/stores/settings.ts +++ b/web/src/stores/settings.ts @@ -2,27 +2,27 @@ import { useStorage } from "@vueuse/core"; import { defineStore } from "pinia"; interface State { - Menu: MenuSettings + Menu: MenuSettings; } interface MenuSettings { - Show: boolean | null, - Expand: boolean | null, + Show: boolean | null; + Expand: boolean | null; } -export const useSettingsStore = defineStore('settings', { - state: () => ({ - Menu: useStorage('settings', { - Show: null, - Expand: false, - }), - }), - actions: { - toggleMenu() { - this.Menu.Show = !this.Menu.Show; - }, - toggleMenuSize() { - this.Menu.Expand = !this.Menu.Expand; - }, - } -}); \ No newline at end of file +export const useSettingsStore = defineStore("settings", { + state: () => ({ + Menu: useStorage("settings", { + Show: null, + Expand: false, + }), + }), + actions: { + toggleMenu() { + this.Menu.Show = !this.Menu.Show; + }, + toggleMenuSize() { + this.Menu.Expand = !this.Menu.Expand; + }, + }, +}); diff --git a/web/src/stores/transactions.ts b/web/src/stores/transactions.ts index e8c9825..67d9ace 100644 --- a/web/src/stores/transactions.ts +++ b/web/src/stores/transactions.ts @@ -1,105 +1,110 @@ -import { defineStore } from "pinia" +import { defineStore } from "pinia"; import { POST } from "../api"; import { useAccountStore } from "./budget-account"; interface State { - Transactions: Map - Reconciling: boolean + Transactions: Map; + Reconciling: boolean; } export interface Transaction { - ID: string - Date: Date - TransferAccount: string - CategoryGroup: string - Category: string - CategoryID: string | undefined - Memo: string - Status: string - GroupID: string - Payee: string - PayeeID: string | undefined - Amount: number - Reconciled: boolean + ID: string; + Date: Date; + TransferAccount: string; + CategoryGroup: string; + Category: string; + CategoryID: string | undefined; + Memo: string; + Status: string; + GroupID: string; + Payee: string; + PayeeID: string | undefined; + Amount: number; + Reconciled: boolean; } export const useTransactionsStore = defineStore("budget/transactions", { - state: (): State => ({ - Transactions: new Map(), - Reconciling: false, - }), - getters: { - ReconcilingBalance(state): number { - const accountsStore = useAccountStore() - let reconciledBalance = accountsStore.CurrentAccount!.ReconciledBalance; - for (const transaction of this.TransactionsList) { - if (transaction.Reconciled) - reconciledBalance += transaction.Amount; - } - return reconciledBalance; - }, - TransactionsList(state): Transaction[] { - const accountsStore = useAccountStore() - return accountsStore.CurrentAccount!.Transactions.map(x => { - return this.Transactions.get(x)! - }); - }, - }, - actions: { - AddTransactions(transactions: Array) { - const transactionIds = [] as Array; - this.$patch(() => { - for (const transaction of transactions) { - transaction.Date = new Date(transaction.Date); - this.Transactions.set(transaction.ID, transaction); - transactionIds.push(transaction.ID); - } - }); - return transactionIds; - }, - SetReconciledForAllTransactions(value: boolean) { - for (const transaction of this.TransactionsList) { - if (transaction.Status == "Reconciled") - continue; + state: (): State => ({ + Transactions: new Map(), + Reconciling: false, + }), + getters: { + ReconcilingBalance(state): number { + const accountsStore = useAccountStore(); + let reconciledBalance = + accountsStore.CurrentAccount!.ReconciledBalance; + for (const transaction of this.TransactionsList) { + if (transaction.Reconciled) + reconciledBalance += transaction.Amount; + } + return reconciledBalance; + }, + TransactionsList(state): Transaction[] { + const accountsStore = useAccountStore(); + return accountsStore.CurrentAccount!.Transactions.map((x) => { + return this.Transactions.get(x)!; + }); + }, + }, + actions: { + AddTransactions(transactions: Array) { + const transactionIds = [] as Array; + this.$patch(() => { + for (const transaction of transactions) { + transaction.Date = new Date(transaction.Date); + this.Transactions.set(transaction.ID, transaction); + transactionIds.push(transaction.ID); + } + }); + return transactionIds; + }, + SetReconciledForAllTransactions(value: boolean) { + for (const transaction of this.TransactionsList) { + if (transaction.Status == "Reconciled") continue; - transaction.Reconciled = value; - } - }, - async SubmitReconcilation(reconciliationTransactionAmount: number) { - const accountsStore = useAccountStore() - const account = accountsStore.CurrentAccount!; - const reconciledTransactions = this.TransactionsList.filter(x => x.Reconciled); - for (const transaction of reconciledTransactions) { - account.ReconciledBalance += transaction.Amount; - transaction.Status = "Reconciled"; - transaction.Reconciled = false; - } - const result = await POST("/account/" + accountsStore.CurrentAccountID + "/reconcile", JSON.stringify({ - transactionIDs: reconciledTransactions.map(x => x.ID), - reconciliationTransactionAmount: reconciliationTransactionAmount.toString(), - })); - const response = await result.json(); - const recTrans = response.ReconciliationTransaction; - if (recTrans) { - this.AddTransactions([recTrans]); - account.Transactions.unshift(recTrans.ID); - } - }, - logout() { - this.$reset() - }, - async saveTransaction(payload: string) { - const accountsStore = useAccountStore() - const result = await POST("/transaction/new", payload); - const response = await result.json() as Transaction; - this.AddTransactions([response]); - accountsStore.CurrentAccount?.Transactions.unshift(response.ID); - }, - async editTransaction(transactionid: string, payload: string) { - const result = await POST("/transaction/" + transactionid, payload); - const response = await result.json() as Transaction; - this.AddTransactions([response]); - } - } - -}) + transaction.Reconciled = value; + } + }, + async SubmitReconcilation(reconciliationTransactionAmount: number) { + const accountsStore = useAccountStore(); + const account = accountsStore.CurrentAccount!; + const reconciledTransactions = this.TransactionsList.filter( + (x) => x.Reconciled + ); + for (const transaction of reconciledTransactions) { + account.ReconciledBalance += transaction.Amount; + transaction.Status = "Reconciled"; + transaction.Reconciled = false; + } + const result = await POST( + "/account/" + accountsStore.CurrentAccountID + "/reconcile", + JSON.stringify({ + transactionIDs: reconciledTransactions.map((x) => x.ID), + reconciliationTransactionAmount: + reconciliationTransactionAmount.toString(), + }) + ); + const response = await result.json(); + const recTrans = response.ReconciliationTransaction; + if (recTrans) { + this.AddTransactions([recTrans]); + account.Transactions.unshift(recTrans.ID); + } + }, + logout() { + this.$reset(); + }, + async saveTransaction(payload: string) { + const accountsStore = useAccountStore(); + const result = await POST("/transaction/new", payload); + const response = (await result.json()) as Transaction; + this.AddTransactions([response]); + accountsStore.CurrentAccount?.Transactions.unshift(response.ID); + }, + async editTransaction(transactionid: string, payload: string) { + const result = await POST("/transaction/" + transactionid, payload); + const response = (await result.json()) as Transaction; + this.AddTransactions([response]); + }, + }, +}); diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 8b26c47..4aff73d 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -1,10 +1,7 @@ module.exports = { - content: [ - "./index.html", - "./src/**/*.{vue,js,ts,jsx,tsx}" - ], - theme: { - extend: {}, - }, - plugins: [], -} + content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/web/tsconfig.json b/web/tsconfig.json index b4309f4..9f45142 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -1,10 +1,10 @@ { - "compilerOptions": { - "target": "esnext", - "module": "esnext", - // this enables stricter inference for data properties on `this` - "strict": true, - "jsx": "preserve", - "moduleResolution": "node" - } -} \ No newline at end of file + "compilerOptions": { + "target": "esnext", + "module": "esnext", + // this enables stricter inference for data properties on `this` + "strict": true, + "jsx": "preserve", + "moduleResolution": "node" + } +} diff --git a/web/vite.config.js b/web/vite.config.js index 8e1b264..3cea5ef 100644 --- a/web/vite.config.js +++ b/web/vite.config.js @@ -1,30 +1,30 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; -import path from 'path' +import path from "path"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [ - vue(), - // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin - ], - define: { 'process.env': {} }, - resolve: { - alias: { - '@': path.resolve(__dirname, 'src'), - }, - }, - server: { - host: '0.0.0.0', - proxy: { - '/api': { - target: 'http://10.0.0.162:1323/', - changeOrigin: true - } - } - } - /* remove the need to specify .vue files https://vitejs.dev/config/#resolve-extensions + plugins: [ + vue(), + // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin + ], + define: { "process.env": {} }, + resolve: { + alias: { + "@": path.resolve(__dirname, "src"), + }, + }, + server: { + host: "0.0.0.0", + proxy: { + "/api": { + target: "http://10.0.0.162:1323/", + changeOrigin: true, + }, + }, + }, + /* remove the need to specify .vue files https://vitejs.dev/config/#resolve-extensions resolve: { extensions: [ '.js', @@ -37,4 +37,4 @@ export default defineConfig({ ] }, */ -}) +}); From d717ef1b4d908ada5d82133417aadf7a15dc7bd3 Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Tue, 15 Mar 2022 12:52:23 +0000 Subject: [PATCH 04/13] Use spaces --- web/.eslintrc.js | 30 +- web/index.html | 22 +- web/package.json | 82 ++-- web/postcss.config.js | 8 +- web/src/@types/shims-vue.d.ts | 6 +- web/src/App.vue | 62 +-- web/src/api.ts | 30 +- web/src/components/AccountWithReconciled.vue | 22 +- web/src/components/Autocomplete.vue | 50 +-- web/src/components/Button.vue | 6 +- web/src/components/Card.vue | 8 +- web/src/components/Checkbox.vue | 10 +- web/src/components/Currency.vue | 10 +- web/src/components/DateInput.vue | 12 +- web/src/components/Input.vue | 8 +- web/src/components/Modal.vue | 68 +-- web/src/components/TransactionEditRow.vue | 68 +-- web/src/components/TransactionInputRow.vue | 74 ++-- web/src/components/TransactionRow.vue | 78 ++-- web/src/date.ts | 12 +- web/src/dialogs/EditAccount.vue | 50 +-- web/src/dialogs/NewBudget.vue | 20 +- web/src/index.css | 10 +- web/src/main.ts | 90 ++-- web/src/pages/Account.vue | 178 ++++---- web/src/pages/Admin.vue | 10 +- web/src/pages/BudgetSidebar.vue | 124 +++--- web/src/pages/Budgeting.vue | 150 +++---- web/src/pages/Dashboard.vue | 30 +- web/src/pages/Index.vue | 18 +- web/src/pages/Login.vue | 46 +-- web/src/pages/Register.vue | 56 +-- web/src/pages/Settings.vue | 142 +++---- web/src/pinia-logger.ts | 160 +++---- web/src/router/index.ts | 114 ++--- web/src/stores/budget-account.ts | 412 +++++++++---------- web/src/stores/budget.ts | 112 ++--- web/src/stores/session.ts | 118 +++--- web/src/stores/settings.ts | 34 +- web/src/stores/transactions.ts | 194 ++++----- web/tailwind.config.js | 10 +- web/tsconfig.json | 16 +- web/vite.config.js | 40 +- 43 files changed, 1400 insertions(+), 1400 deletions(-) diff --git a/web/.eslintrc.js b/web/.eslintrc.js index 09e832e..3bfbf89 100644 --- a/web/.eslintrc.js +++ b/web/.eslintrc.js @@ -1,17 +1,17 @@ module.exports = { - extends: [ - // add more generic rulesets here, such as: - // 'eslint:recommended', - "plugin:vue/vue3-recommended", - // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x. - ], - rules: { - // override/add rules settings here, such as: - // 'vue/no-unused-vars': 'error' - }, - parser: "vue-eslint-parser", - parserOptions: { - parser: "@typescript-eslint/parser", - sourceType: "module", - }, + extends: [ + // add more generic rulesets here, such as: + // 'eslint:recommended', + "plugin:vue/vue3-recommended", + // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x. + ], + rules: { + // override/add rules settings here, such as: + // 'vue/no-unused-vars': 'error' + }, + parser: "vue-eslint-parser", + parserOptions: { + parser: "@typescript-eslint/parser", + sourceType: "module", + }, }; diff --git a/web/index.html b/web/index.html index 506228f..bf743a6 100644 --- a/web/index.html +++ b/web/index.html @@ -1,14 +1,14 @@ - - - - - Vite App - - -
- - + + + + + Vite App + + +
+ + diff --git a/web/package.json b/web/package.json index 335cbc4..ff2a578 100644 --- a/web/package.json +++ b/web/package.json @@ -1,43 +1,43 @@ { - "name": "web", - "version": "0.0.0", - "scripts": { - "serve": "vite preview", - "build": "vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@mdi/font": "5.9.55", - "@vueuse/core": "^7.6.1", - "autoprefixer": "^10.4.2", - "file-saver": "^2.0.5", - "pinia": "^2.0.11", - "postcss": "^8.4.6", - "tailwindcss": "^3.0.18", - "vue": "^3.2.25", - "vue-router": "^4.0.12" - }, - "devDependencies": { - "@types/file-saver": "^2.0.5", - "@typescript-eslint/parser": "^5.13.0", - "@vitejs/plugin-vue": "^2.0.0", - "@vue/cli-plugin-babel": "5.0.0-beta.7", - "@vue/cli-plugin-typescript": "~4.5.0", - "@vue/cli-service": "5.0.0-beta.7", - "eslint": "^8.10.0", - "eslint-plugin-vue": "^8.5.0", - "prettier": "2.5.1", - "sass": "^1.38.0", - "sass-loader": "^10.0.0", - "typescript": "^4.5.5", - "vite": "^2.7.2", - "vue-tsc": "^0.32.0" - }, - "prettier": { - "bracketSameLine": true, - "embeddedLanguageFormatting": "off", - "tabWidth": 4, - "useTabs": true - } + "name": "web", + "version": "0.0.0", + "scripts": { + "serve": "vite preview", + "build": "vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@mdi/font": "5.9.55", + "@vueuse/core": "^7.6.1", + "autoprefixer": "^10.4.2", + "file-saver": "^2.0.5", + "pinia": "^2.0.11", + "postcss": "^8.4.6", + "tailwindcss": "^3.0.18", + "vue": "^3.2.25", + "vue-router": "^4.0.12" + }, + "devDependencies": { + "@types/file-saver": "^2.0.5", + "@typescript-eslint/parser": "^5.13.0", + "@vitejs/plugin-vue": "^2.0.0", + "@vue/cli-plugin-babel": "5.0.0-beta.7", + "@vue/cli-plugin-typescript": "~4.5.0", + "@vue/cli-service": "5.0.0-beta.7", + "eslint": "^8.10.0", + "eslint-plugin-vue": "^8.5.0", + "prettier": "2.5.1", + "sass": "^1.38.0", + "sass-loader": "^10.0.0", + "typescript": "^4.5.5", + "vite": "^2.7.2", + "vue-tsc": "^0.32.0" + }, + "prettier": { + "bracketSameLine": true, + "embeddedLanguageFormatting": "off", + "tabWidth": 4, + "useTabs": false + } } diff --git a/web/postcss.config.js b/web/postcss.config.js index e873f1a..67cdf1a 100644 --- a/web/postcss.config.js +++ b/web/postcss.config.js @@ -1,6 +1,6 @@ module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, }; diff --git a/web/src/@types/shims-vue.d.ts b/web/src/@types/shims-vue.d.ts index 811114b..9027990 100644 --- a/web/src/@types/shims-vue.d.ts +++ b/web/src/@types/shims-vue.d.ts @@ -1,5 +1,5 @@ declare module "*.vue" { - import { defineComponent } from "vue"; - const component: ReturnType; - export default component; + import { defineComponent } from "vue"; + const component: ReturnType; + export default component; } diff --git a/web/src/App.vue b/web/src/App.vue index 9b55f2f..1418f51 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -26,39 +26,39 @@ export default defineComponent({ diff --git a/web/src/api.ts b/web/src/api.ts index e5292c9..5c5a4cb 100644 --- a/web/src/api.ts +++ b/web/src/api.ts @@ -3,24 +3,24 @@ import { useSessionStore } from "./stores/session"; export const BASE_URL = "/api/v1"; export function GET(path: string) { - const sessionStore = useSessionStore(); - return fetch(BASE_URL + path, { - headers: sessionStore.AuthHeaders, - }); + const sessionStore = useSessionStore(); + return fetch(BASE_URL + path, { + headers: sessionStore.AuthHeaders, + }); } export function POST(path: string, body: FormData | string | null) { - const sessionStore = useSessionStore(); - return fetch(BASE_URL + path, { - method: "POST", - headers: sessionStore.AuthHeaders, - body: body, - }); + const sessionStore = useSessionStore(); + return fetch(BASE_URL + path, { + method: "POST", + headers: sessionStore.AuthHeaders, + body: body, + }); } export function DELETE(path: string) { - const sessionStore = useSessionStore(); - return fetch(BASE_URL + path, { - method: "DELETE", - headers: sessionStore.AuthHeaders, - }); + const sessionStore = useSessionStore(); + return fetch(BASE_URL + path, { + method: "DELETE", + headers: sessionStore.AuthHeaders, + }); } diff --git a/web/src/components/AccountWithReconciled.vue b/web/src/components/AccountWithReconciled.vue index 21036d7..a576cc2 100644 --- a/web/src/components/AccountWithReconciled.vue +++ b/web/src/components/AccountWithReconciled.vue @@ -19,15 +19,15 @@ function daysSinceLastReconciled() { diff --git a/web/src/components/Autocomplete.vue b/web/src/components/Autocomplete.vue index b3d275c..bfc9083 100644 --- a/web/src/components/Autocomplete.vue +++ b/web/src/components/Autocomplete.vue @@ -81,29 +81,29 @@ function clear() { diff --git a/web/src/components/Button.vue b/web/src/components/Button.vue index e3ef6a8..c5baa4f 100644 --- a/web/src/components/Button.vue +++ b/web/src/components/Button.vue @@ -1,7 +1,7 @@ diff --git a/web/src/components/Card.vue b/web/src/components/Card.vue index bf9866a..50d45e2 100644 --- a/web/src/components/Card.vue +++ b/web/src/components/Card.vue @@ -1,8 +1,8 @@ diff --git a/web/src/components/Checkbox.vue b/web/src/components/Checkbox.vue index b2aab40..dfd507d 100644 --- a/web/src/components/Checkbox.vue +++ b/web/src/components/Checkbox.vue @@ -3,9 +3,9 @@ const props = defineProps(["modelValue"]); diff --git a/web/src/components/Currency.vue b/web/src/components/Currency.vue index 31c13cc..80495ac 100644 --- a/web/src/components/Currency.vue +++ b/web/src/components/Currency.vue @@ -15,9 +15,9 @@ const formattedValue = computed(() => internalValue.value.toLocaleString(undefin diff --git a/web/src/components/DateInput.vue b/web/src/components/DateInput.vue index 473ad41..5802c91 100644 --- a/web/src/components/DateInput.vue +++ b/web/src/components/DateInput.vue @@ -26,10 +26,10 @@ function selectAll(event: FocusEvent) { diff --git a/web/src/components/Input.vue b/web/src/components/Input.vue index 9b0e32d..32e624c 100644 --- a/web/src/components/Input.vue +++ b/web/src/components/Input.vue @@ -3,8 +3,8 @@ const props = defineProps(["modelValue"]); diff --git a/web/src/components/Modal.vue b/web/src/components/Modal.vue index 721098d..b028531 100644 --- a/web/src/components/Modal.vue +++ b/web/src/components/Modal.vue @@ -30,38 +30,38 @@ function submitDialog() { diff --git a/web/src/components/TransactionEditRow.vue b/web/src/components/TransactionEditRow.vue index 0e0364d..b2010cd 100644 --- a/web/src/components/TransactionEditRow.vue +++ b/web/src/components/TransactionEditRow.vue @@ -38,38 +38,38 @@ function saveTransaction(e: MouseEvent) { diff --git a/web/src/components/TransactionInputRow.vue b/web/src/components/TransactionInputRow.vue index 5c79180..4bc8679 100644 --- a/web/src/components/TransactionInputRow.vue +++ b/web/src/components/TransactionInputRow.vue @@ -52,41 +52,41 @@ function saveTransaction(e: MouseEvent) { diff --git a/web/src/components/TransactionRow.vue b/web/src/components/TransactionRow.vue index 73cd718..9760282 100644 --- a/web/src/components/TransactionRow.vue +++ b/web/src/components/TransactionRow.vue @@ -47,45 +47,45 @@ function getStatusSymbol() {