diff --git a/.eslintrc.json b/.eslintrc.json
index 55c17a0dfa17bb0c6d974da0149b380394714b93..26c9f5aaafb0af24447ebd42fb63ec50fc8d8071 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,6 +1,6 @@
 {
     "parserOptions": {
-        "parser": "@babel/eslint-parser",
+        "parser": "@typescript-eslint/parser",
         "sourceType": "module"
     },
     "env": {
@@ -9,7 +9,8 @@
     },
     "extends": [
         "eslint:recommended",
-        "plugin:vue/essential"
+        "plugin:vue/essential",
+        "@vue/eslint-config-typescript"
     ],
     "globals": {
         "STUDIP": "writable",
@@ -23,13 +24,15 @@
     ],
     "rules": {
         "no-unused-vars": "off",
-
+        "@typescript-eslint/no-unused-vars": "off",
         "no-async-promise-executor": "error",
         "no-await-in-loop": "error",
         "no-promise-executor-return": "error",
         "require-atomic-updates": "error",
         "max-nested-callbacks": ["error", 4],
         "no-return-await": "error",
-        "prefer-promise-reject-errors": "error"
+        "prefer-promise-reject-errors": "error",
+
+        "vue/multi-word-component-names": "off"
     }
 }
diff --git a/package-lock.json b/package-lock.json
index 53b13dc4453d8eb329ad0acfee101a335105bf8f..2fa3aae5ba51c6499806dc77ee5eb4226cf28985 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,6 +48,10 @@
                 "@fullcalendar/resource-timeline": "^4.3.0",
                 "@fullcalendar/timegrid": "^4.3.0",
                 "@popperjs/core": "^2.11.2",
+                "@types/jquery": "^3.5.16",
+                "@types/jqueryui": "^1.12.16",
+                "@types/lodash": "^4.14.191",
+                "@vue/eslint-config-typescript": "^11.0.2",
                 "autoprefixer": "^10.2.5",
                 "axios": "^0.21.0",
                 "babel-loader": "^8.2.1",
@@ -62,7 +66,7 @@
                 "easygettext": "^2.17.0",
                 "es6-promise": "4.2.8",
                 "eslint": "^7.32.0",
-                "eslint-plugin-vue": "7.7.0",
+                "eslint-plugin-vue": "^9.10.0",
                 "eslint-webpack-plugin": "^3.1.1",
                 "expose-loader": "1.0.1",
                 "favico.js": "0.3.10",
@@ -101,6 +105,8 @@
                 "style-loader": "^2.0.0",
                 "svgo": "^2.3.1",
                 "tablesorter": "2.31.3",
+                "ts-loader": "^9.4.2",
+                "typescript": "^5.0.2",
                 "vrp-vue-resizable": "1.2.7",
                 "vue": "^2.6.12",
                 "vue-gettext": "^2.1.12",
@@ -2043,15 +2049,6 @@
                 "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
-        "node_modules/@ckeditor/ckeditor5-dev-utils/node_modules/array-union": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/@ckeditor/ckeditor5-dev-utils/node_modules/chalk": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
@@ -2932,6 +2929,7 @@
             "version": "30.5.0",
             "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-dev-webpack-plugin/-/ckeditor5-dev-webpack-plugin-30.5.0.tgz",
             "integrity": "sha512-mErNKfGd8XBjJxB7K7yCDnNq4pLQKbEjwJHf9g2EW4gOD1U55rgPc1XpmgfxhMj44QQ8YOZXAQ/Y/55AN7GATA==",
+            "deprecated": "This package is no longer maintained. Please, read the migration path: https://github.com/ckeditor/ckeditor5-dev/releases/tag/v32.0.0.",
             "dev": true,
             "dependencies": {
                 "@ckeditor/ckeditor5-dev-utils": "^30.5.0",
@@ -3544,6 +3542,42 @@
                 "vuex": "^3.0.1"
             }
         },
+        "node_modules/@eslint-community/eslint-utils": {
+            "version": "4.4.0",
+            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+            "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+            "dev": true,
+            "dependencies": {
+                "eslint-visitor-keys": "^3.3.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "peerDependencies": {
+                "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+            }
+        },
+        "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+            "version": "3.4.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+            "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
+            "dev": true,
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
+        "node_modules/@eslint-community/regexpp": {
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz",
+            "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==",
+            "dev": true,
+            "engines": {
+                "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+            }
+        },
         "node_modules/@eslint/eslintrc": {
             "version": "0.4.3",
             "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
@@ -3846,6 +3880,7 @@
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
             "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
+            "deprecated": "This functionality has been moved to @npmcli/fs",
             "dev": true,
             "dependencies": {
                 "mkdirp": "^1.0.4",
@@ -3910,12 +3945,36 @@
                 "@types/node": "*"
             }
         },
+        "node_modules/@types/jquery": {
+            "version": "3.5.16",
+            "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz",
+            "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==",
+            "dev": true,
+            "dependencies": {
+                "@types/sizzle": "*"
+            }
+        },
+        "node_modules/@types/jqueryui": {
+            "version": "1.12.16",
+            "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.16.tgz",
+            "integrity": "sha512-6huAQDpNlso9ayaUT9amBOA3kj02OCeUWs+UvDmbaJmwkHSg/HLsQOoap/D5uveN9ePwl72N45Bl+Frp5xyG1Q==",
+            "dev": true,
+            "dependencies": {
+                "@types/jquery": "*"
+            }
+        },
         "node_modules/@types/json-schema": {
             "version": "7.0.9",
             "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
             "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
             "dev": true
         },
+        "node_modules/@types/lodash": {
+            "version": "4.14.191",
+            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+            "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
+            "dev": true
+        },
         "node_modules/@types/minimatch": {
             "version": "3.0.5",
             "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
@@ -3947,6 +4006,272 @@
             "dev": true,
             "optional": true
         },
+        "node_modules/@types/semver": {
+            "version": "7.3.13",
+            "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+            "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+            "dev": true
+        },
+        "node_modules/@types/sizzle": {
+            "version": "2.3.3",
+            "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
+            "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
+            "dev": true
+        },
+        "node_modules/@typescript-eslint/eslint-plugin": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz",
+            "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==",
+            "dev": true,
+            "dependencies": {
+                "@eslint-community/regexpp": "^4.4.0",
+                "@typescript-eslint/scope-manager": "5.57.0",
+                "@typescript-eslint/type-utils": "5.57.0",
+                "@typescript-eslint/utils": "5.57.0",
+                "debug": "^4.3.4",
+                "grapheme-splitter": "^1.0.4",
+                "ignore": "^5.2.0",
+                "natural-compare-lite": "^1.4.0",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "@typescript-eslint/parser": "^5.0.0",
+                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+            "version": "5.2.4",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+            "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+            "dev": true,
+            "engines": {
+                "node": ">= 4"
+            }
+        },
+        "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+            "version": "7.3.8",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+            "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@typescript-eslint/parser": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz",
+            "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/scope-manager": "5.57.0",
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/typescript-estree": "5.57.0",
+                "debug": "^4.3.4"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/scope-manager": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz",
+            "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/visitor-keys": "5.57.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            }
+        },
+        "node_modules/@typescript-eslint/type-utils": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz",
+            "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/typescript-estree": "5.57.0",
+                "@typescript-eslint/utils": "5.57.0",
+                "debug": "^4.3.4",
+                "tsutils": "^3.21.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "eslint": "*"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/types": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz",
+            "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==",
+            "dev": true,
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            }
+        },
+        "node_modules/@typescript-eslint/typescript-estree": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz",
+            "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/visitor-keys": "5.57.0",
+                "debug": "^4.3.4",
+                "globby": "^11.1.0",
+                "is-glob": "^4.0.3",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+            "version": "7.3.8",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+            "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@typescript-eslint/utils": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz",
+            "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==",
+            "dev": true,
+            "dependencies": {
+                "@eslint-community/eslint-utils": "^4.2.0",
+                "@types/json-schema": "^7.0.9",
+                "@types/semver": "^7.3.12",
+                "@typescript-eslint/scope-manager": "5.57.0",
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/typescript-estree": "5.57.0",
+                "eslint-scope": "^5.1.1",
+                "semver": "^7.3.7"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+            }
+        },
+        "node_modules/@typescript-eslint/utils/node_modules/semver": {
+            "version": "7.3.8",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+            "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@typescript-eslint/visitor-keys": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz",
+            "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/types": "5.57.0",
+                "eslint-visitor-keys": "^3.3.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            }
+        },
+        "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+            "version": "3.4.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+            "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
+            "dev": true,
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
         "node_modules/@vue/compiler-core": {
             "version": "3.2.31",
             "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz",
@@ -4059,6 +4384,30 @@
             "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
             "dev": true
         },
+        "node_modules/@vue/eslint-config-typescript": {
+            "version": "11.0.2",
+            "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-11.0.2.tgz",
+            "integrity": "sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==",
+            "dev": true,
+            "dependencies": {
+                "@typescript-eslint/eslint-plugin": "^5.0.0",
+                "@typescript-eslint/parser": "^5.0.0",
+                "vue-eslint-parser": "^9.0.0"
+            },
+            "engines": {
+                "node": "^14.17.0 || >=16.0.0"
+            },
+            "peerDependencies": {
+                "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0",
+                "eslint-plugin-vue": "^9.0.0",
+                "typescript": "*"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
+            }
+        },
         "node_modules/@vue/reactivity-transform": {
             "version": "3.2.31",
             "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz",
@@ -4480,6 +4829,15 @@
             "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
             "dev": true
         },
+        "node_modules/array-union": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+            "dev": true,
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/asap": {
             "version": "2.0.6",
             "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -6524,21 +6882,24 @@
             }
         },
         "node_modules/eslint-plugin-vue": {
-            "version": "7.7.0",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.7.0.tgz",
-            "integrity": "sha512-mYz4bpLGv5jx6YG/GvKkqbGSfV7uma2u1P3mLA41Q5vQl8W1MeuTneB8tfsLq6xxxesFubcrOC0BZBJ5R+eaCQ==",
+            "version": "9.10.0",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.10.0.tgz",
+            "integrity": "sha512-2MgP31OBf8YilUvtakdVMc8xVbcMp7z7/iQj8LHVpXrSXHPXSJRUIGSPFI6b6pyCx/buKaFJ45ycqfHvQRiW2g==",
             "dev": true,
             "dependencies": {
-                "eslint-utils": "^2.1.0",
+                "@eslint-community/eslint-utils": "^4.3.0",
                 "natural-compare": "^1.4.0",
-                "semver": "^7.3.2",
-                "vue-eslint-parser": "^7.6.0"
+                "nth-check": "^2.0.1",
+                "postcss-selector-parser": "^6.0.9",
+                "semver": "^7.3.5",
+                "vue-eslint-parser": "^9.0.1",
+                "xml-name-validator": "^4.0.0"
             },
             "engines": {
-                "node": ">=8.10"
+                "node": "^14.17.0 || >=16.0.0"
             },
             "peerDependencies": {
-                "eslint": "^6.2.0 || ^7.0.0"
+                "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0"
             }
         },
         "node_modules/eslint-plugin-vue/node_modules/semver": {
@@ -7174,13 +7535,13 @@
             }
         },
         "node_modules/focus-trap": {
-            "version": "6.7.3",
-            "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.7.3.tgz",
-            "integrity": "sha512-8xCEKndV4KrseGhFKKKmczVA14yx1/hnmFICPOjcFjToxCJYj/NHH43tPc3YE/PLnLRNZoFug0EcWkGQde/miQ==",
+            "version": "6.9.4",
+            "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz",
+            "integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==",
             "dev": true,
             "peer": true,
             "dependencies": {
-                "tabbable": "^5.2.1"
+                "tabbable": "^5.3.3"
             }
         },
         "node_modules/focus-trap-vue": {
@@ -7370,12 +7731,47 @@
                 "node": ">=4"
             }
         },
+        "node_modules/globby": {
+            "version": "11.1.0",
+            "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+            "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+            "dev": true,
+            "dependencies": {
+                "array-union": "^2.1.0",
+                "dir-glob": "^3.0.1",
+                "fast-glob": "^3.2.9",
+                "ignore": "^5.2.0",
+                "merge2": "^1.4.1",
+                "slash": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/globby/node_modules/ignore": {
+            "version": "5.2.4",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+            "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+            "dev": true,
+            "engines": {
+                "node": ">= 4"
+            }
+        },
         "node_modules/graceful-fs": {
             "version": "4.2.9",
             "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
             "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
             "dev": true
         },
+        "node_modules/grapheme-splitter": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+            "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+            "dev": true
+        },
         "node_modules/growly": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@@ -8948,6 +9344,12 @@
             "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
             "dev": true
         },
+        "node_modules/natural-compare-lite": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+            "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+            "dev": true
+        },
         "node_modules/neo-async": {
             "version": "2.6.2",
             "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -12020,6 +12422,7 @@
             "version": "1.4.8",
             "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
             "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+            "deprecated": "Please use @jridgewell/sourcemap-codec instead",
             "dev": true,
             "optional": true
         },
@@ -12045,6 +12448,7 @@
             "version": "0.1.8",
             "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
             "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+            "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
             "dev": true
         },
         "node_modules/stackblur-canvas": {
@@ -12326,9 +12730,9 @@
             }
         },
         "node_modules/tabbable": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.2.1.tgz",
-            "integrity": "sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ==",
+            "version": "5.3.3",
+            "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz",
+            "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==",
             "dev": true,
             "peer": true
         },
@@ -12601,9 +13005,9 @@
             "optional": true
         },
         "node_modules/ts-loader": {
-            "version": "9.3.1",
-            "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz",
-            "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==",
+            "version": "9.4.2",
+            "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz",
+            "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==",
             "dev": true,
             "dependencies": {
                 "chalk": "^4.1.0",
@@ -12704,6 +13108,27 @@
             "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
             "dev": true
         },
+        "node_modules/tsutils": {
+            "version": "3.21.0",
+            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+            "dev": true,
+            "dependencies": {
+                "tslib": "^1.8.1"
+            },
+            "engines": {
+                "node": ">= 6"
+            },
+            "peerDependencies": {
+                "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+            }
+        },
+        "node_modules/tsutils/node_modules/tslib": {
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+            "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+            "dev": true
+        },
         "node_modules/type-check": {
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -12729,17 +13154,16 @@
             }
         },
         "node_modules/typescript": {
-            "version": "4.8.2",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
-            "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
+            "version": "5.0.2",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
+            "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
             "dev": true,
-            "peer": true,
             "bin": {
                 "tsc": "bin/tsc",
                 "tsserver": "bin/tsserver"
             },
             "engines": {
-                "node": ">=4.2.0"
+                "node": ">=12.20"
             }
         },
         "node_modules/unbox-primitive": {
@@ -12939,50 +13363,90 @@
             "dev": true
         },
         "node_modules/vue-eslint-parser": {
-            "version": "7.11.0",
-            "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
-            "integrity": "sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==",
+            "version": "9.1.1",
+            "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.1.tgz",
+            "integrity": "sha512-C2aI/r85Q6tYcz4dpgvrs4wH/MqVrRAVIdpYedrxnATDHHkb+TroeRcDpKWGZCx/OcECMWfz7tVwQ8e+Opy6rA==",
             "dev": true,
             "dependencies": {
-                "debug": "^4.1.1",
-                "eslint-scope": "^5.1.1",
-                "eslint-visitor-keys": "^1.1.0",
-                "espree": "^6.2.1",
+                "debug": "^4.3.4",
+                "eslint-scope": "^7.1.1",
+                "eslint-visitor-keys": "^3.3.0",
+                "espree": "^9.3.1",
                 "esquery": "^1.4.0",
                 "lodash": "^4.17.21",
-                "semver": "^6.3.0"
+                "semver": "^7.3.6"
             },
             "engines": {
-                "node": ">=8.10"
+                "node": "^14.17.0 || >=16.0.0"
             },
             "funding": {
                 "url": "https://github.com/sponsors/mysticatea"
             },
             "peerDependencies": {
-                "eslint": ">=5.0.0"
+                "eslint": ">=6.0.0"
+            }
+        },
+        "node_modules/vue-eslint-parser/node_modules/acorn": {
+            "version": "8.8.2",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+            "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+            "dev": true,
+            "bin": {
+                "acorn": "bin/acorn"
+            },
+            "engines": {
+                "node": ">=0.4.0"
+            }
+        },
+        "node_modules/vue-eslint-parser/node_modules/eslint-scope": {
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+            "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+            "dev": true,
+            "dependencies": {
+                "esrecurse": "^4.3.0",
+                "estraverse": "^5.2.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
             }
         },
         "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
-            "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+            "version": "3.4.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+            "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
             "dev": true,
             "engines": {
-                "node": ">=4"
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
             }
         },
         "node_modules/vue-eslint-parser/node_modules/espree": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
-            "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+            "version": "9.5.1",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
+            "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
             "dev": true,
             "dependencies": {
-                "acorn": "^7.1.1",
-                "acorn-jsx": "^5.2.0",
-                "eslint-visitor-keys": "^1.1.0"
+                "acorn": "^8.8.0",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^3.4.0"
             },
             "engines": {
-                "node": ">=6.0.0"
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
+        "node_modules/vue-eslint-parser/node_modules/estraverse": {
+            "version": "5.3.0",
+            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+            "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+            "dev": true,
+            "engines": {
+                "node": ">=4.0"
             }
         },
         "node_modules/vue-eslint-parser/node_modules/lodash": {
@@ -12991,6 +13455,21 @@
             "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
             "dev": true
         },
+        "node_modules/vue-eslint-parser/node_modules/semver": {
+            "version": "7.3.8",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+            "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
         "node_modules/vue-gettext": {
             "version": "2.1.12",
             "resolved": "https://registry.npmjs.org/vue-gettext/-/vue-gettext-2.1.12.tgz",
@@ -13417,6 +13896,15 @@
             "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
             "dev": true
         },
+        "node_modules/xml-name-validator": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
+            "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
+            "dev": true,
+            "engines": {
+                "node": ">=12"
+            }
+        },
         "node_modules/yallist": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@@ -14801,12 +15289,6 @@
                         "color-convert": "^2.0.1"
                     }
                 },
-                "array-union": {
-                    "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-                    "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-                    "dev": true
-                },
                 "chalk": {
                     "version": "3.0.0",
                     "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
@@ -15823,6 +16305,29 @@
                 "@elan-ev/reststate-client": "^1.0.0"
             }
         },
+        "@eslint-community/eslint-utils": {
+            "version": "4.4.0",
+            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+            "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+            "dev": true,
+            "requires": {
+                "eslint-visitor-keys": "^3.3.0"
+            },
+            "dependencies": {
+                "eslint-visitor-keys": {
+                    "version": "3.4.0",
+                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+                    "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
+                    "dev": true
+                }
+            }
+        },
+        "@eslint-community/regexpp": {
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz",
+            "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==",
+            "dev": true
+        },
         "@eslint/eslintrc": {
             "version": "0.4.3",
             "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
@@ -16118,12 +16623,36 @@
                 "@types/node": "*"
             }
         },
+        "@types/jquery": {
+            "version": "3.5.16",
+            "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz",
+            "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==",
+            "dev": true,
+            "requires": {
+                "@types/sizzle": "*"
+            }
+        },
+        "@types/jqueryui": {
+            "version": "1.12.16",
+            "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.16.tgz",
+            "integrity": "sha512-6huAQDpNlso9ayaUT9amBOA3kj02OCeUWs+UvDmbaJmwkHSg/HLsQOoap/D5uveN9ePwl72N45Bl+Frp5xyG1Q==",
+            "dev": true,
+            "requires": {
+                "@types/jquery": "*"
+            }
+        },
         "@types/json-schema": {
             "version": "7.0.9",
             "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
             "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
             "dev": true
         },
+        "@types/lodash": {
+            "version": "4.14.191",
+            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+            "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
+            "dev": true
+        },
         "@types/minimatch": {
             "version": "3.0.5",
             "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
@@ -16155,6 +16684,164 @@
             "dev": true,
             "optional": true
         },
+        "@types/semver": {
+            "version": "7.3.13",
+            "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+            "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+            "dev": true
+        },
+        "@types/sizzle": {
+            "version": "2.3.3",
+            "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
+            "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
+            "dev": true
+        },
+        "@typescript-eslint/eslint-plugin": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz",
+            "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==",
+            "dev": true,
+            "requires": {
+                "@eslint-community/regexpp": "^4.4.0",
+                "@typescript-eslint/scope-manager": "5.57.0",
+                "@typescript-eslint/type-utils": "5.57.0",
+                "@typescript-eslint/utils": "5.57.0",
+                "debug": "^4.3.4",
+                "grapheme-splitter": "^1.0.4",
+                "ignore": "^5.2.0",
+                "natural-compare-lite": "^1.4.0",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            },
+            "dependencies": {
+                "ignore": {
+                    "version": "5.2.4",
+                    "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+                    "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+                    "dev": true
+                },
+                "semver": {
+                    "version": "7.3.8",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+                    "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+                    "dev": true,
+                    "requires": {
+                        "lru-cache": "^6.0.0"
+                    }
+                }
+            }
+        },
+        "@typescript-eslint/parser": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz",
+            "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/scope-manager": "5.57.0",
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/typescript-estree": "5.57.0",
+                "debug": "^4.3.4"
+            }
+        },
+        "@typescript-eslint/scope-manager": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz",
+            "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/visitor-keys": "5.57.0"
+            }
+        },
+        "@typescript-eslint/type-utils": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz",
+            "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/typescript-estree": "5.57.0",
+                "@typescript-eslint/utils": "5.57.0",
+                "debug": "^4.3.4",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/types": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz",
+            "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==",
+            "dev": true
+        },
+        "@typescript-eslint/typescript-estree": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz",
+            "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/visitor-keys": "5.57.0",
+                "debug": "^4.3.4",
+                "globby": "^11.1.0",
+                "is-glob": "^4.0.3",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            },
+            "dependencies": {
+                "semver": {
+                    "version": "7.3.8",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+                    "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+                    "dev": true,
+                    "requires": {
+                        "lru-cache": "^6.0.0"
+                    }
+                }
+            }
+        },
+        "@typescript-eslint/utils": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz",
+            "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==",
+            "dev": true,
+            "requires": {
+                "@eslint-community/eslint-utils": "^4.2.0",
+                "@types/json-schema": "^7.0.9",
+                "@types/semver": "^7.3.12",
+                "@typescript-eslint/scope-manager": "5.57.0",
+                "@typescript-eslint/types": "5.57.0",
+                "@typescript-eslint/typescript-estree": "5.57.0",
+                "eslint-scope": "^5.1.1",
+                "semver": "^7.3.7"
+            },
+            "dependencies": {
+                "semver": {
+                    "version": "7.3.8",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+                    "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+                    "dev": true,
+                    "requires": {
+                        "lru-cache": "^6.0.0"
+                    }
+                }
+            }
+        },
+        "@typescript-eslint/visitor-keys": {
+            "version": "5.57.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz",
+            "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.57.0",
+                "eslint-visitor-keys": "^3.3.0"
+            },
+            "dependencies": {
+                "eslint-visitor-keys": {
+                    "version": "3.4.0",
+                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+                    "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
+                    "dev": true
+                }
+            }
+        },
         "@vue/compiler-core": {
             "version": "3.2.31",
             "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz",
@@ -16260,6 +16947,17 @@
                 }
             }
         },
+        "@vue/eslint-config-typescript": {
+            "version": "11.0.2",
+            "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-11.0.2.tgz",
+            "integrity": "sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/eslint-plugin": "^5.0.0",
+                "@typescript-eslint/parser": "^5.0.0",
+                "vue-eslint-parser": "^9.0.0"
+            }
+        },
         "@vue/reactivity-transform": {
             "version": "3.2.31",
             "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz",
@@ -16609,6 +17307,12 @@
                 }
             }
         },
+        "array-union": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+            "dev": true
+        },
         "asap": {
             "version": "2.0.6",
             "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -18235,15 +18939,18 @@
             }
         },
         "eslint-plugin-vue": {
-            "version": "7.7.0",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.7.0.tgz",
-            "integrity": "sha512-mYz4bpLGv5jx6YG/GvKkqbGSfV7uma2u1P3mLA41Q5vQl8W1MeuTneB8tfsLq6xxxesFubcrOC0BZBJ5R+eaCQ==",
+            "version": "9.10.0",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.10.0.tgz",
+            "integrity": "sha512-2MgP31OBf8YilUvtakdVMc8xVbcMp7z7/iQj8LHVpXrSXHPXSJRUIGSPFI6b6pyCx/buKaFJ45ycqfHvQRiW2g==",
             "dev": true,
             "requires": {
-                "eslint-utils": "^2.1.0",
+                "@eslint-community/eslint-utils": "^4.3.0",
                 "natural-compare": "^1.4.0",
-                "semver": "^7.3.2",
-                "vue-eslint-parser": "^7.6.0"
+                "nth-check": "^2.0.1",
+                "postcss-selector-parser": "^6.0.9",
+                "semver": "^7.3.5",
+                "vue-eslint-parser": "^9.0.1",
+                "xml-name-validator": "^4.0.0"
             },
             "dependencies": {
                 "semver": {
@@ -18616,13 +19323,13 @@
             }
         },
         "focus-trap": {
-            "version": "6.7.3",
-            "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.7.3.tgz",
-            "integrity": "sha512-8xCEKndV4KrseGhFKKKmczVA14yx1/hnmFICPOjcFjToxCJYj/NHH43tPc3YE/PLnLRNZoFug0EcWkGQde/miQ==",
+            "version": "6.9.4",
+            "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz",
+            "integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==",
             "dev": true,
             "peer": true,
             "requires": {
-                "tabbable": "^5.2.1"
+                "tabbable": "^5.3.3"
             }
         },
         "focus-trap-vue": {
@@ -18751,12 +19458,40 @@
             "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
             "dev": true
         },
+        "globby": {
+            "version": "11.1.0",
+            "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+            "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+            "dev": true,
+            "requires": {
+                "array-union": "^2.1.0",
+                "dir-glob": "^3.0.1",
+                "fast-glob": "^3.2.9",
+                "ignore": "^5.2.0",
+                "merge2": "^1.4.1",
+                "slash": "^3.0.0"
+            },
+            "dependencies": {
+                "ignore": {
+                    "version": "5.2.4",
+                    "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+                    "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+                    "dev": true
+                }
+            }
+        },
         "graceful-fs": {
             "version": "4.2.9",
             "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
             "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
             "dev": true
         },
+        "grapheme-splitter": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+            "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+            "dev": true
+        },
         "growly": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@@ -19956,6 +20691,12 @@
             "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
             "dev": true
         },
+        "natural-compare-lite": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+            "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+            "dev": true
+        },
         "neo-async": {
             "version": "2.6.2",
             "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -22532,9 +23273,9 @@
             }
         },
         "tabbable": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.2.1.tgz",
-            "integrity": "sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ==",
+            "version": "5.3.3",
+            "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz",
+            "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==",
             "dev": true,
             "peer": true
         },
@@ -22742,9 +23483,9 @@
             "optional": true
         },
         "ts-loader": {
-            "version": "9.3.1",
-            "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz",
-            "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==",
+            "version": "9.4.2",
+            "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz",
+            "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==",
             "dev": true,
             "requires": {
                 "chalk": "^4.1.0",
@@ -22813,6 +23554,23 @@
             "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
             "dev": true
         },
+        "tsutils": {
+            "version": "3.21.0",
+            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+            "dev": true,
+            "requires": {
+                "tslib": "^1.8.1"
+            },
+            "dependencies": {
+                "tslib": {
+                    "version": "1.14.1",
+                    "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+                    "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+                    "dev": true
+                }
+            }
+        },
         "type-check": {
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -22829,11 +23587,10 @@
             "dev": true
         },
         "typescript": {
-            "version": "4.8.2",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
-            "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
-            "dev": true,
-            "peer": true
+            "version": "5.0.2",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
+            "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
+            "dev": true
         },
         "unbox-primitive": {
             "version": "1.0.1",
@@ -22999,42 +23756,73 @@
             "dev": true
         },
         "vue-eslint-parser": {
-            "version": "7.11.0",
-            "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
-            "integrity": "sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==",
+            "version": "9.1.1",
+            "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.1.tgz",
+            "integrity": "sha512-C2aI/r85Q6tYcz4dpgvrs4wH/MqVrRAVIdpYedrxnATDHHkb+TroeRcDpKWGZCx/OcECMWfz7tVwQ8e+Opy6rA==",
             "dev": true,
             "requires": {
-                "debug": "^4.1.1",
-                "eslint-scope": "^5.1.1",
-                "eslint-visitor-keys": "^1.1.0",
-                "espree": "^6.2.1",
+                "debug": "^4.3.4",
+                "eslint-scope": "^7.1.1",
+                "eslint-visitor-keys": "^3.3.0",
+                "espree": "^9.3.1",
                 "esquery": "^1.4.0",
                 "lodash": "^4.17.21",
-                "semver": "^6.3.0"
+                "semver": "^7.3.6"
             },
             "dependencies": {
+                "acorn": {
+                    "version": "8.8.2",
+                    "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+                    "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+                    "dev": true
+                },
+                "eslint-scope": {
+                    "version": "7.1.1",
+                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+                    "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+                    "dev": true,
+                    "requires": {
+                        "esrecurse": "^4.3.0",
+                        "estraverse": "^5.2.0"
+                    }
+                },
                 "eslint-visitor-keys": {
-                    "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
-                    "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+                    "version": "3.4.0",
+                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+                    "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
                     "dev": true
                 },
                 "espree": {
-                    "version": "6.2.1",
-                    "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
-                    "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+                    "version": "9.5.1",
+                    "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
+                    "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
                     "dev": true,
                     "requires": {
-                        "acorn": "^7.1.1",
-                        "acorn-jsx": "^5.2.0",
-                        "eslint-visitor-keys": "^1.1.0"
+                        "acorn": "^8.8.0",
+                        "acorn-jsx": "^5.3.2",
+                        "eslint-visitor-keys": "^3.4.0"
                     }
                 },
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                },
                 "lodash": {
                     "version": "4.17.21",
                     "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
                     "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
                     "dev": true
+                },
+                "semver": {
+                    "version": "7.3.8",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+                    "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+                    "dev": true,
+                    "requires": {
+                        "lru-cache": "^6.0.0"
+                    }
                 }
             }
         },
@@ -23348,6 +24136,12 @@
             "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
             "dev": true
         },
+        "xml-name-validator": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
+            "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
+            "dev": true
+        },
         "yallist": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
diff --git a/package.json b/package.json
index 3909abba7a3a9cfd4ea8232cec0121c90422b462..8ab2d815fb2cc94828cbda66920a3f2aa531525f 100644
--- a/package.json
+++ b/package.json
@@ -57,6 +57,10 @@
         "@fullcalendar/resource-timeline": "^4.3.0",
         "@fullcalendar/timegrid": "^4.3.0",
         "@popperjs/core": "^2.11.2",
+        "@types/jquery": "^3.5.16",
+        "@types/jqueryui": "^1.12.16",
+        "@types/lodash": "^4.14.191",
+        "@vue/eslint-config-typescript": "^11.0.2",
         "autoprefixer": "^10.2.5",
         "axios": "^0.21.0",
         "babel-loader": "^8.2.1",
@@ -71,7 +75,7 @@
         "easygettext": "^2.17.0",
         "es6-promise": "4.2.8",
         "eslint": "^7.32.0",
-        "eslint-plugin-vue": "7.7.0",
+        "eslint-plugin-vue": "^9.10.0",
         "eslint-webpack-plugin": "^3.1.1",
         "expose-loader": "1.0.1",
         "favico.js": "0.3.10",
@@ -110,6 +114,8 @@
         "style-loader": "^2.0.0",
         "svgo": "^2.3.1",
         "tablesorter": "2.31.3",
+        "ts-loader": "^9.4.2",
+        "typescript": "^5.0.2",
         "vrp-vue-resizable": "1.2.7",
         "vue": "^2.6.12",
         "vue-gettext": "^2.1.12",
diff --git a/resources/assets/javascripts/bootstrap/application.js b/resources/assets/javascripts/bootstrap/application.js
index f97dd90e04897dd0bd8b034c0cea57c7f2f48644..1f0561e0ce52b8feeb9dcc151f95c2d274ed72d2 100644
--- a/resources/assets/javascripts/bootstrap/application.js
+++ b/resources/assets/javascripts/bootstrap/application.js
@@ -1,5 +1,5 @@
 import { $gettext } from '../lib/gettext.js';
-import eventBus from "../lib/event-bus";
+import eventBus from "../lib/event-bus.ts";
 
 /* ------------------------------------------------------------------------
  * application.js
diff --git a/resources/assets/javascripts/bootstrap/multi_select.js b/resources/assets/javascripts/bootstrap/multi_select.js
index 38fa362d61fcdabdd7e58d1c431696ce28912467..9e817b8f6a419c72a5fbecf30654fb6b16d9cea5 100644
--- a/resources/assets/javascripts/bootstrap/multi_select.js
+++ b/resources/assets/javascripts/bootstrap/multi_select.js
@@ -1,5 +1,5 @@
 import { $gettext } from '../lib/gettext.js';
-import eventBus from "../lib/event-bus";
+import eventBus from "../lib/event-bus.ts";
 
 eventBus.on('studip:set-locale', () => {
     $.extend($.ui.multiselect, {
diff --git a/resources/assets/javascripts/chunks/vue.js b/resources/assets/javascripts/chunks/vue.js
index 53748c99733d484c8693a1d528c726f21d8ff77a..cf95ed3c5f73c5fbf9766ddc2b64ec2c2b5baf75 100644
--- a/resources/assets/javascripts/chunks/vue.js
+++ b/resources/assets/javascripts/chunks/vue.js
@@ -1,7 +1,7 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import Router from "vue-router";
-import eventBus from '../lib/event-bus.js';
+import eventBus from '../lib/event-bus.ts';
 import GetTextPlugin from 'vue-gettext';
 import { getLocale, getVueConfig } from '../lib/gettext.js';
 import PortalVue from 'portal-vue';
diff --git a/resources/assets/javascripts/init.js b/resources/assets/javascripts/init.js
index e01f84e56630a5a376c2dce6ea62342773075e00..a37a466a52bb696f2bf58173c53217d003b2b329 100644
--- a/resources/assets/javascripts/init.js
+++ b/resources/assets/javascripts/init.js
@@ -16,13 +16,13 @@ import CalendarDialog from './lib/calendar_dialog.js';
 import Clipboard from './lib/clipboard.js';
 import Cookie from './lib/cookie.js';
 import CourseWizard from './lib/course_wizard.js';
-import createURLHelper from './lib/url_helper.js';
+import { createURLHelper } from './lib/url_helper.ts';
 import CSS from './lib/css.js';
 import Dates from './lib/dates.js';
 import Dialog from './lib/dialog.js';
 import DragAndDropUpload from './lib/drag_and_drop_upload.js';
 import enrollment from './lib/enrollment.js';
-import eventBus from './lib/event-bus.js';
+import eventBus from './lib/event-bus.ts';
 import extractCallback from './lib/extract_callback.js';
 import Files from './lib/files.js';
 import FilesDashboard from './lib/files_dashboard.js';
diff --git a/resources/assets/javascripts/lib/calendar.js b/resources/assets/javascripts/lib/calendar.js
index bfe00543b7396a1b36c87878d1a68433443a8813..2f1cd672a40ef757880dc72dda9930d0c6234def 100644
--- a/resources/assets/javascripts/lib/calendar.js
+++ b/resources/assets/javascripts/lib/calendar.js
@@ -1,5 +1,5 @@
 import { $gettext } from '../lib/gettext.js';
-import eventBus from "./event-bus";
+import eventBus from "./event-bus.ts";
 
 eventBus.on('studip:set-locale', () => {
     Calendar.day_names = [
diff --git a/resources/assets/javascripts/lib/event-bus.d.ts b/resources/assets/javascripts/lib/event-bus.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..812c73858035880d9ae6aaff809f3cec6506e1dd
--- /dev/null
+++ b/resources/assets/javascripts/lib/event-bus.d.ts
@@ -0,0 +1,2 @@
+declare const eventBus: import("mitt").Emitter;
+export default eventBus;
diff --git a/resources/assets/javascripts/lib/event-bus.js b/resources/assets/javascripts/lib/event-bus.ts
similarity index 100%
rename from resources/assets/javascripts/lib/event-bus.js
rename to resources/assets/javascripts/lib/event-bus.ts
diff --git a/resources/assets/javascripts/lib/forum.js b/resources/assets/javascripts/lib/forum.js
index fbada1f9ed05ff034d4d4437342324dbf18c070a..8dcc076f93c85cc78dd9d402b21aad58b20573c1 100644
--- a/resources/assets/javascripts/lib/forum.js
+++ b/resources/assets/javascripts/lib/forum.js
@@ -1,5 +1,5 @@
 import { $gettext } from "./gettext.js";
-import eventBus from "./event-bus";
+import eventBus from "./event-bus.ts";
 
 eventBus.on('studip:set-locale', () => {
     Forum.warning_text = $gettext('Wenn Sie die Seite verlassen, gehen ihre Änderungen verloren!');
diff --git a/resources/assets/javascripts/lib/gettext.js b/resources/assets/javascripts/lib/gettext.js
index 0e3eb9aab4f2cf3a7720f323035a734df6c8762f..5742466a60ccc441436666fca1d7d3a70b946a7b 100644
--- a/resources/assets/javascripts/lib/gettext.js
+++ b/resources/assets/javascripts/lib/gettext.js
@@ -1,6 +1,6 @@
 import { translate } from 'vue-gettext';
 import defaultTranslations from '../../../../locale/de/LC_MESSAGES/js-resources.json';
-import eventBus from './event-bus.js';
+import eventBus from './event-bus.ts';
 
 const DEFAULT_LANG = 'de_DE';
 const DEFAULT_LANG_NAME = 'Deutsch';
diff --git a/resources/assets/javascripts/lib/url_helper.d.ts b/resources/assets/javascripts/lib/url_helper.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ec8920ec9bfbd0aa9901500b548d4b1fe849fa3d
--- /dev/null
+++ b/resources/assets/javascripts/lib/url_helper.d.ts
@@ -0,0 +1,33 @@
+/**
+ * This class helps to handle URLs of hyperlinks and change their parameters.
+ * For example a javascript-page may open an item and the user expects other links
+ * on the same page to "know" that this item is now open. But because we don't use
+ * PHP session-variables here, this is difficult to use. This class can help. You
+ * can overwrite the href-attribute of the link by:
+ *
+ *  [code]
+ *  link.href = STUDIP.URLHelper.getURL("adresse.php?hello=world#anchor");
+ *  [/code]
+ * Returns something like:
+ * "http://uni-adresse.de/studip/adresse.php?hello=world&mandatory=parameter#anchor"
+ */
+declare class URLHelper {
+    base_url: string;
+    parameters: Record<string, string>;
+    constructor(base_url?: string, parameters?: {});
+    /**
+     * returns a readily encoded URL with the mandatory parameters and additionally passed
+     * parameters.
+     *
+     * @param url string: any url-string
+     * @param param_object map: associative object for extra values
+     * @param ignore_params boolean: ignore previously bound parameters
+     * @return: url with all necessary and additional parameters, encoded
+     */
+    getURL(url: string, param_object: any, ignore_params: boolean): string;
+}
+export declare function createURLHelper(config: {
+    base_url?: string;
+    parameters?: Record<string, string>;
+}): URLHelper;
+export {};
diff --git a/resources/assets/javascripts/lib/url_helper.js b/resources/assets/javascripts/lib/url_helper.ts
similarity index 79%
rename from resources/assets/javascripts/lib/url_helper.js
rename to resources/assets/javascripts/lib/url_helper.ts
index 0aa08c3539c5dee41ec90b661ea6b1b268cdc2c3..b9ebbf60d9005699d0b9907482ac8dca9616ab05 100644
--- a/resources/assets/javascripts/lib/url_helper.js
+++ b/resources/assets/javascripts/lib/url_helper.ts
@@ -13,7 +13,10 @@
  */
 
 class URLHelper {
-    constructor(base_url = null, parameters = {}) {
+    base_url: string;
+    parameters: Record<string, string>;
+
+    constructor(base_url = "", parameters = {}) {
         //the base url for all links
         this.base_url = base_url;
 
@@ -30,7 +33,7 @@ class URLHelper {
      * @param ignore_params boolean: ignore previously bound parameters
      * @return: url with all necessary and additional parameters, encoded
      */
-    getURL(url, param_object, ignore_params) {
+    getURL(url: string, param_object: any, ignore_params: boolean): string {
         let result;
 
         if (url === '' || url.match(/^[?#]/)) {
@@ -40,14 +43,14 @@ class URLHelper {
         }
 
         if (!ignore_params) {
-            for (let key in this.parameters) {
+            for (const key in this.parameters) {
                 if (!result.searchParams.has(key)) {
                     result.searchParams.set(key, this.parameters[key]);
                 }
             }
         }
 
-        for (let key in param_object) {
+        for (const key in param_object) {
             if (param_object[key] !== null) {
                 result.searchParams.set(key, param_object[key]);
             } else {
@@ -59,6 +62,6 @@ class URLHelper {
     }
 }
 
-export default function createURLHelper(config) {
-    return new URLHelper(config && config.base_url, config && config.parameters);
+export function createURLHelper(config: { base_url?: string, parameters?: Record<string, string>}): URLHelper {
+    return new URLHelper(config?.base_url, config?.parameters);
 }
diff --git a/resources/assets/javascripts/studip-ui.js b/resources/assets/javascripts/studip-ui.js
index fdb32553151b542c92265059e1f3d21b3284c8c4..41897b204b94e5b3d17c2e88b15dbde60fae38f6 100644
--- a/resources/assets/javascripts/studip-ui.js
+++ b/resources/assets/javascripts/studip-ui.js
@@ -1,5 +1,5 @@
 import { $gettext } from './lib/gettext.js';
-import eventBus from "./lib/event-bus";
+import eventBus from "./lib/event-bus.ts";
 
 /**
  * This file contains extensions/adjustments for jQuery UI.
diff --git a/resources/studip.d.ts b/resources/studip.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ec8fef976240e59684d18ee3de1eb3cf657cc4d
--- /dev/null
+++ b/resources/studip.d.ts
@@ -0,0 +1,24 @@
+import { Emitter } from 'mitt';
+import { URLHelper } from './assets/javascripts/lib/url_helper.d.ts';
+export {};
+
+declare global {
+    interface Window {
+        STUDIP: {
+            wysiwyg_enabled: boolean;
+            INSTALLED_LANGUAGES: { [name: string]: InstalledLanguage };
+            ABSOLUTE_URI_STUDIP: string;
+            ASSETS_URL: string;
+            CSRF_TOKEN: { name: string; value: string };
+            URLHelper: URLHelper;
+            eventBus: Emitter;
+        };
+    }
+}
+
+export interface InstalledLanguage {
+    name: string;
+    path: string;
+    picture: string;
+    selected: boolean;
+}
diff --git a/resources/vue-shims.d.ts b/resources/vue-shims.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b62fca43a92f607887d6a9e104a9ce05f4020a3
--- /dev/null
+++ b/resources/vue-shims.d.ts
@@ -0,0 +1,5 @@
+declare module '*.vue' {
+    import "vue-gettext/types";
+    import Vue from 'vue';
+    export default Vue;
+}
diff --git a/resources/vue/components/StudipIcon.vue b/resources/vue/components/StudipIcon.vue
index 3a2ac79889bf77ba21fa93389309407729416cb0..a08bdfaa475a4985cdb098281095415b25443561 100644
--- a/resources/vue/components/StudipIcon.vue
+++ b/resources/vue/components/StudipIcon.vue
@@ -1,66 +1,77 @@
 <template>
-    <input v-if="name" type="image" :name="name" :src="url"
-           :width="size" :height="size" v-bind="$attrs" v-on="$listeners">
-    <img v-else :src="url" :width="size" :height="size" v-bind="$attrs" v-on="$listeners">
+    <input
+        v-if="name"
+        type="image"
+        :name="name"
+        :src="url"
+        :width="size"
+        :height="size"
+        v-bind="$attrs"
+        v-on="$listeners"
+    />
+    <img v-else :src="url" :width="size" :height="size" v-bind="$attrs" v-on="$listeners" />
 </template>
 
-<script>
-    export default {
-        name: 'studip-icon',
-        props: {
-            shape: String,
-            role: {
-                type: String,
-                required: false,
-                default: 'clickable'
-            },
-            size: {
-                required: false,
-                default: 16
-            },
-            name: {
-                type: String,
-                required: false
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+    name: 'studip-icon',
+    props: {
+        shape: String,
+        role: {
+            type: String,
+            required: false,
+            default: 'clickable',
+        },
+        size: {
+            type: Number,
+            required: false,
+            default: 16,
+        },
+        name: {
+            type: String,
+            required: false,
+        },
+    },
+    computed: {
+        url(): string {
+            if (this.shape.indexOf('http') === 0) {
+                return this.shape;
             }
+            var path = this.shape.split('+').reverse().join('/');
+            return `${window.STUDIP.ASSETS_URL}images/icons/${this.color}/${path}.svg`;
         },
-        computed: {
-            url: function () {
-                if (this.shape.indexOf("http") === 0) {
-                    return this.shape;
-                }
-                var path = this.shape.split('+').reverse().join('/');
-                return `${STUDIP.ASSETS_URL}images/icons/${this.color}/${path}.svg`;
-            },
-            color: function () {
-                switch (this.role) {
-                    case 'info':
-                        return 'black';
+        color(): string {
+            switch (this.role) {
+                case 'info':
+                    return 'black';
 
-                    case 'inactive':
-                        return 'grey';
+                case 'inactive':
+                    return 'grey';
 
-                    case 'accept':
-                    case 'status-green':
-                        return 'green';
+                case 'accept':
+                case 'status-green':
+                    return 'green';
 
-                    case 'attention':
-                    case 'new':
-                    case 'status-red':
-                        return 'red';
+                case 'attention':
+                case 'new':
+                case 'status-red':
+                    return 'red';
 
-                    case 'info_alt':
-                        return 'white';
+                case 'info_alt':
+                    return 'white';
 
-                    case 'status-yellow':
-                        return 'yellow';
+                case 'status-yellow':
+                    return 'yellow';
 
-                    case 'sort':
-                    case 'clickable':
-                    case 'navigation':
-                    default:
-                        return 'blue';
-                }
+                case 'sort':
+                case 'clickable':
+                case 'navigation':
+                default:
+                    return 'blue';
             }
-        }
-    }
+        },
+    },
+});
 </script>
diff --git a/resources/vue/components/responsive/NavigationItem.vue b/resources/vue/components/responsive/NavigationItem.vue
index c227771648c5de0e414305429b3e32efa1514361..32878dc303668231aa83c5f58d291de7ba12a6dc 100644
--- a/resources/vue/components/responsive/NavigationItem.vue
+++ b/resources/vue/components/responsive/NavigationItem.vue
@@ -1,86 +1,95 @@
 <template>
-    <li v-if="item.visible" class="navigation-item" :class="{'navigation-item-active': active}">
+    <li v-if="item.visible" class="navigation-item" :class="{ 'navigation-item-active': active }">
         <template v-if="hasChildren()">
             <div class="navigation-title">
-                <a :href="item.url" :title="navigateToText(item.title)"
-                   :aria-label="navigateToText(item.title)" tabindex="0">
+                <a
+                    :href="item.url"
+                    :title="navigateToText(item.title)"
+                    :aria-label="navigateToText(item.title)"
+                    tabindex="0"
+                >
                     <span class="navigation-icon">
                         <studip-icon v-if="isCourse" shape="seminar" role="info_alt" size="24" alt=""></studip-icon>
-                        <img v-if="item.icon" :src="iconUrl" width="24" alt="">
+                        <img v-if="item.icon" :src="iconUrl" width="24" alt="" />
                     </span>
                     <span class="navigation-text">
                         {{ item.title }}
                     </span>
                 </a>
             </div>
-            <button class="styleless navigation-in"
-                    :title="openNavigationText(item.title)"
-                    :aria-label="openNavigationText(item.title)"
-                    @click="moveTo(item.path)" @keydown.prevent.enter="moveTo(item.path)" @keydown.prevent.space="moveTo(item.path)">
+            <button
+                class="styleless navigation-in"
+                :title="openNavigationText(item.title)"
+                :aria-label="openNavigationText(item.title)"
+                @click="moveTo(item.path)"
+                @keydown.prevent.enter="moveTo(item.path)"
+                @keydown.prevent.space="moveTo(item.path)"
+            >
                 <studip-icon shape="arr_1right" role="info_alt" size="20" alt=""></studip-icon>
             </button>
         </template>
         <div v-else class="navigation-title">
-            <a :href="item.url" tabindex="0" :title="navigateToText(item.title)"
-               :aria-label="navigateToText(item.title)">
+            <a
+                :href="item.url"
+                tabindex="0"
+                :title="navigateToText(item.title)"
+                :aria-label="navigateToText(item.title)"
+            >
                 <studip-icon v-if="isCourse" shape="seminar" role="info_alt" size="24" alt=""></studip-icon>
-                <img v-if="item.icon" :src="iconUrl" width="24" alt="">
+                <img v-if="item.icon" :src="iconUrl" width="24" alt="" />
                 {{ item.title }}
             </a>
         </div>
     </li>
 </template>
 
-<script>
+<script lang="ts">
+import Vue, { PropType } from 'vue';
 import StudipIcon from '../StudipIcon.vue';
 
-export default {
+export default Vue.extend({
     name: 'NavigationItem',
     components: { StudipIcon },
     props: {
         item: {
             type: Object,
-            required: true
+            required: true,
         },
         active: {
             type: Boolean,
-            default: false
+            default: false,
         },
         isCourse: {
             type: Boolean,
-            default: false
-        }
+            default: false,
+        },
     },
     computed: {
         iconUrl() {
             if (this.item.icon && !this.item.icon.match(/^https?:\/\//)) {
-                return STUDIP.ASSETS_URL + this.item.icon;
+                return window.STUDIP.ASSETS_URL + this.item.icon;
             }
             return this.item.icon;
-        }
+        },
     },
     methods: {
-        getUrl(url) {
-            return STUDIP.URLHelper.getURL(url);
+        getUrl(url: string) {
+            return window.STUDIP.URLHelper.getURL(url);
         },
-        moveTo(path) {
-            STUDIP.eventBus.emit('responsive-navigation-move-to', path);
+        moveTo(path: string) {
+            window.STUDIP.eventBus.emit('responsive-navigation-move-to', path);
         },
         hasChildren() {
             return this.item.children && Object.keys(this.item.children).length > 0;
         },
-        navigateToText(itemTitle) {
-            return this.$gettextInterpolate(
-                this.$gettext('Navigiere zu %{ title }'),
-                { title: itemTitle }
-            );
+        navigateToText(itemTitle: string) {
+            return this.$gettextInterpolate(this.$gettext('Navigiere zu %{ title }'), { title: itemTitle });
         },
-        openNavigationText(itemTitle) {
-            return this.$gettextInterpolate(
-                this.$gettext('Unternavigation zu %{ title } öffnen'),
-                { title: itemTitle }
-            );
-        }
-    }
-}
+        openNavigationText(itemTitle: string): string {
+            return this.$gettextInterpolate(this.$gettext('Unternavigation zu %{ title } öffnen'), {
+                title: itemTitle,
+            });
+        },
+    },
+});
 </script>
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..55b45dc2e0fa2d508c766a69d453be0517c3410f
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,10 @@
+{
+    "compilerOptions": {
+        "target": "es2015",
+        "strict": true,
+        "module": "es2015",
+        "moduleResolution": "node"
+    },
+    "include": ["resources/**/*.ts", "resources/**/*.vue"],
+    "exclude": ["node_modules"]
+}
diff --git a/webpack.common.js b/webpack.common.js
index 2846f1d5a54ececb194b2da10209fb8f4ec40cf4..d71aff6da8a07de8e4e72f4ef372196ae5b69b67 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -104,6 +104,14 @@ module.exports = {
                     }
                 ]
             },
+            {
+                test: /\.ts$/,
+                loader: 'ts-loader',
+                exclude: /node_modules/,
+                options: {
+                    appendTsSuffixTo: [/\.vue$/],
+                },
+            },
             {
                 test: /\.js$/,
                 exclude: /node_modules|ckeditor/,