Compare commits

..

160 Commits

Author SHA1 Message Date
Ferdinand Thiessen e8c0001d17 fix(ci): Fix build step
continuous-integration/woodpecker the build was successful Details
2021-12-08 15:32:31 +01:00
Ferdinand Thiessen 5c8637965a feat(ci): More testing
continuous-integration/woodpecker the build failed Details
2021-12-08 15:29:41 +01:00
Ferdinand Thiessen 308d348755 feat(ci): Added woodpecker CI
continuous-integration/woodpecker the build was successful Details
2021-12-08 15:17:25 +01:00
Ferdinand Thiessen 2425e6cf2f fix(boot): Fix navigation guards so users get redirected after logging in 2021-12-06 13:14:42 +01:00
Ferdinand Thiessen a9edc12494 fix(api): Allow userid as parameter for avatarURL 2021-12-06 12:51:47 +01:00
Ferdinand Thiessen 1525de1469 chore(deps): Update dependencies 2021-12-06 00:41:13 +01:00
Ferdinand Thiessen 6a75d1bf51 chore(format): Fix formatting, enforce prettier style 2021-12-06 00:40:50 +01:00
Ferdinand Thiessen f9f66e7172 chore(api): Update dependencies, cleanup, tag new version
No need for prettier stuff, it is done by flaschengeists package.json
2021-12-05 23:57:37 +01:00
Ferdinand Thiessen e9c0086859 feat(api): Add component for displaying an users avatar with fallback image 2021-12-05 23:35:32 +01:00
Ferdinand Thiessen b2c70a6657 feat(api): user store decides if data is outdated based on the last update rather then last local changes. 2021-12-05 20:57:57 +01:00
Ferdinand Thiessen f27212f60e feat(api): user store now handels deleted users.
`.users` now is a getter that filters out deleted users.
For all users, including deleted, use `_users` property (should not be needed as `getUser` will return the needed information as well).
2021-12-05 20:57:15 +01:00
Ferdinand Thiessen 9eb5412c14 fix(api): Session is required to load current user 2021-12-05 20:51:44 +01:00
Ferdinand Thiessen 8e552ba508 feat(app): Set lifetime to 14 days on capacitor.
Do not annoy users on capacitory apps with daily logging in again
2021-12-05 13:45:50 +01:00
Ferdinand Thiessen 49c3ec74ba fix(api): Load current user in login function of mainStore 2021-12-05 13:45:50 +01:00
Ferdinand Thiessen 83f32ea82a feat(api): Get current session 2021-12-05 13:30:44 +01:00
Ferdinand Thiessen 656d7a9e3c feat(api): Add delete user function to user store 2021-12-02 21:32:43 +01:00
Ferdinand Thiessen 8fca175d39 chore(api) Tag a new api version 2021-11-29 18:18:00 +01:00
Ferdinand Thiessen 6c219c5226 feat(api) Added function to get the URL of an user avatar 2021-11-29 17:23:55 +01:00
Ferdinand Thiessen cb43b8a39b fix(core) Token should be added to headers instead of replacing them 2021-11-29 17:20:26 +01:00
Tim Gröger acf1816b55 [core] logout on capicitor in drawer 2021-11-28 14:46:00 +01:00
Ferdinand Thiessen 02f60335d4 [api] tag new version 2021-11-27 02:47:14 +01:00
Ferdinand Thiessen d9267bcc0a [api] Save whole session in PersistantStore. 2021-11-27 02:44:40 +01:00
Ferdinand Thiessen 6732921ff7 [core] Improved backend setup on login page 2021-11-27 01:31:43 +01:00
Ferdinand Thiessen 7a705d5f9a [core] Ensure everything is initialized in the correct order.
Make sure api is initialized before making any requests.
2021-11-27 01:18:58 +01:00
Ferdinand Thiessen 368ca23c56 General cleanup of unused code and small fixes 2021-11-27 00:49:12 +01:00
Tim Gröger d82e025700 Merge branch 'capacitor' into develop 2021-11-26 22:14:51 +01:00
Tim Gröger 07e1966471 [capacitor] disable allowLinkPreview for ios 2021-11-26 22:13:35 +01:00
Ferdinand Thiessen 29c085bd2c [core] Save baseURL into PersistentStorage 2021-11-26 20:55:45 +01:00
Ferdinand Thiessen 1b152b52f5 [core] Save session token in PersistentStorage. 2021-11-26 20:40:35 +01:00
Ferdinand Thiessen 6769e18ffa [api] Add PersistentStorage
Wrapper for LocalStorage on browsers and Storage plugin on capacitor
2021-11-26 20:40:35 +01:00
Ferdinand Thiessen 88dd96c937 [app] Use capacitor instead of cordova 2021-11-26 20:40:26 +01:00
Ferdinand Thiessen 4887bc261b [stores] Minor cleanup 2021-11-26 18:11:18 +01:00
Ferdinand Thiessen d516839ad4 [utils] Add placeholder to datetime utils 2021-11-26 11:14:15 +01:00
Ferdinand Thiessen c9df257bbf [core] Fix minor linting error 2021-11-26 01:39:09 +01:00
Tim Gröger 053fdae384 [api] revert user ssp 2021-11-25 12:32:50 +01:00
Ferdinand Thiessen 6fd3f045f8 [core] Fix notifications dismiss function 2021-11-24 15:54:42 +01:00
Ferdinand Thiessen 2d167ebbae [deps] yarn.lock is not needed as it is overwritten when adding plugins 2021-11-24 15:35:26 +01:00
Ferdinand Thiessen a8578e2803 [core] Notifications can now be dismissed without triggering a reject 2021-11-24 15:28:53 +01:00
Ferdinand Thiessen e4889ddac2 [api] Add datetime util for start-end ranges 2021-11-23 16:00:18 +01:00
Ferdinand Thiessen 664def40fc [docs] Add notes on cordova, different browser targets 2021-11-23 15:59:16 +01:00
Ferdinand Thiessen ade6d06eb6 [core] Minify requests 2021-11-22 22:59:50 +01:00
Tim Gröger 53f053a294 [api] add filter for get_users 2021-11-22 15:08:28 +01:00
Tim Gröger cc29893e04 Merge remote-tracking branch 'origin/develop' into develop 2021-11-21 19:43:49 +01:00
Ferdinand Thiessen 42800a9d99 [deps] Update dependencies, node 12 is close to unmaintained 2021-11-21 15:31:02 +01:00
Ferdinand Thiessen f4650ffdeb [api] update dependencies + new release 2021-11-21 15:11:25 +01:00
Ferdinand Thiessen 1158525abb [api] Add clone function to utils 2021-11-21 15:08:58 +01:00
Ferdinand Thiessen 04e3c57397 [clean] Replace unneeded computed with initialized ref 2021-11-21 11:19:08 +01:00
Tim Gröger 2fc411d51d [UI] Show menu drawer if on desktop 2021-11-21 11:13:51 +01:00
Tim Gröger 6061b37887 [users] delete avatar 2021-11-20 22:59:51 +01:00
Tim Gröger efde9a2ee7 [cleanup] remove logs 2021-11-19 23:12:30 +01:00
Tim Gröger e96d15bc66 [chore] show menu drawer auto if on desktop 2021-11-19 23:10:56 +01:00
Tim Gröger dad88ec766 [api][fix] fixed setting roles 2021-11-19 23:10:28 +01:00
Ferdinand Thiessen 3e091fd02b [plugins] Fix bug where not all plugins are loaded 2021-11-19 14:06:29 +01:00
Ferdinand Thiessen fca79c36ef [api] Pass Date objects to IsoDateInput validators instead of string. 2021-11-16 23:57:57 +01:00
Ferdinand Thiessen 34fcdbdb7f [deps] Match dependencies with API 2021-11-16 21:40:56 +01:00
Ferdinand Thiessen d84796b09d [api] Fix dependencies and release new version 2021-11-16 21:36:42 +01:00
Ferdinand Thiessen 62af4f5026 [cleaup] No need for computed if directly derefed 2021-11-16 14:23:18 +01:00
Tim Gröger 36d6fdfb94 [fix] return correct permissions 2021-11-16 11:20:11 +01:00
Ferdinand Thiessen a30da50b1d [deps] FIX require correct version of types package 2021-11-12 10:31:01 +01:00
Ferdinand Thiessen 53951daa25 [notification] Ignore notifications for missing plugins, identify plugins by ID rather then name. 2021-11-11 15:27:57 +01:00
Ferdinand Thiessen 59920e23a5 [cleanup] Minor style cleanup + use MDIv6 2021-11-11 15:26:57 +01:00
Ferdinand Thiessen 5952c9b7f2 [deps] Update dependencies, Quasar is now more stable 2021-11-11 11:53:11 +01:00
Ferdinand Thiessen 73f50e9f4f [cleanup] Fix some warnings of the vue eslint plugin 2021-11-11 11:52:20 +01:00
Ferdinand Thiessen dfb924bb3f [API] Update dependencies, fix error checking
Typescript now defaults to unknown instead of any for Errors (catch).
Implemented helper function to check AxiosErros.
2021-11-11 11:35:11 +01:00
Ferdinand Thiessen bc9dba1c7b [cleanup] Fix some minor formatting 2021-11-11 11:11:06 +01:00
Ferdinand Thiessen 1132bfd129 [deps] Update to rc pinia and fix TypeScript version for ESLint 2021-08-30 14:21:53 +02:00
Ferdinand Thiessen fe1fae10f5 [plugins]: Allow ordering menu links, fixes #10 2021-07-29 18:26:38 +02:00
Ferdinand Thiessen 1c36399ac0 chore(config): Enable HMR for plugins 2021-07-02 15:18:18 +02:00
Tim Gröger a38954cf70 Merge branch 'develop' of flaschengeist.dev:Flaschengeist/flaschengeist-frontend into develop 2021-06-29 09:37:48 +02:00
Ferdinand Thiessen 35d8433e23 [chore] Quasar is out of beta! (And pinia out of alpha) 2021-06-26 17:27:31 +02:00
groegert 731cc20a06 [core] removed some prettier lines
fixes #9
2021-05-27 12:53:18 +02:00
groegert c38032085f [core] added computation in EssentialExpansionLink
fixes #9
2021-05-27 12:35:25 +02:00
Ferdinand Thiessen 22f47bd34e [docs][core] Move devel docs to wiki, use correct api package 2021-05-26 18:49:36 +02:00
Tim Gröger 16fd9201ae Merge pull request 'Seperated plugin and api types into subprojects' (#2) from seperate_plugins into develop
Reviewed-on: Flaschengeist/flaschengeist-frontend#2
2021-05-26 12:12:44 +00:00
Ferdinand Thiessen 873fee3301 [docs] Updated readme on how to install plugins 2021-05-25 22:09:26 +02:00
Ferdinand Thiessen 1802081ad2 Merge branch 'develop' into seperate_plugins 2021-05-25 22:01:13 +02:00
Ferdinand Thiessen 631e78acb3 [core] minor cleanup 2021-05-25 21:55:22 +02:00
Ferdinand Thiessen d422380adc [core] Fixed menu link title generation 2021-05-25 21:54:49 +02:00
Ferdinand Thiessen 0c279289b2 [test] enable all plugins 2021-05-25 21:54:09 +02:00
Ferdinand Thiessen 979eab05af [api] Fixed session loading 2021-05-25 21:52:26 +02:00
Ferdinand Thiessen fd918f5bb7 [core] Added vendor (always) required plugins 2021-05-25 16:27:10 +02:00
Ferdinand Thiessen 068dbdcc7b [docs] README section about plugin development 2021-05-25 16:26:41 +02:00
Ferdinand Thiessen 8c9db67b95 [core] Seperated all plugins from the main source tree 2021-05-25 16:13:15 +02:00
groegert 86bad83e53 [core] added computation when accessing promised store in EssentialExpansionLink
fixes #9
2021-05-25 12:46:54 +02:00
groegert 625ac55b0a [core] prevent recursive logouts on htto-401
fixes #7
2021-05-24 19:30:28 +02:00
groegert 9940589d1a [core] prevent recursive logouts on htto-401
fixes #7
2021-05-24 19:21:49 +02:00
groegert f2b7f3a3b4 [core] call api.delete(`auth/${token}`) within a valid session
fixes: #7
2021-05-21 10:17:56 +02:00
Ferdinand Thiessen f9c9f6efbe [core] Seperated plugin and api types into subproject 2021-05-21 01:42:41 +02:00
Ferdinand Thiessen 0873b2da22 [core][plugin] Fixed compatibility with Pinia
* API BREAK! Menu link title now must be a string or a function return a string
* Pinia unwraps Refs so we had to get rid of the ComputedRef
* Use current typescript
2021-05-20 20:31:37 +02:00
groegert 734a3e51c9 [core] added some hints to ease the initial development setup 2021-05-20 16:27:40 +00:00
Ferdinand Thiessen cf1a5cc922 [core][deps] Updated deps and fix typescript errors 2021-05-19 15:37:50 +02:00
Ferdinand Thiessen 6e503ed38f [deps] Upgrade dependencies for webpack 5 2021-04-28 15:28:05 +02:00
Ferdinand Thiessen 4cbff6b077 [deps]: Update quasar, now uses webpack5 (Node14+ support!) 2021-04-27 15:16:58 +02:00
Ferdinand Thiessen 2b42dad617 [deps] Updated dependencies, dropped calendar submodule in favor of alpha release 2021-04-22 23:16:00 +02:00
Ferdinand Thiessen 8b6c400689 pricelist: Fixed wrong default value for modelValue 2021-04-22 23:14:11 +02:00
Tim Gröger 5174e7fea3 [core] some style loginpage 2021-04-19 10:12:18 +02:00
Tim Gröger 95867428a8 [core] draggable shortcutlinks 2021-04-18 23:43:16 +02:00
Tim Gröger 3c7d711f59 [core] dynamic shortcutlinks 2021-04-18 23:26:54 +02:00
Tim Gröger 81c5b10101 [core] change style of menulinks in drawer 2021-04-18 22:33:32 +02:00
Tim Gröger a8a6cd8814 Merge branch 'feature/pricelist' into develop 2021-04-17 18:32:06 +02:00
Tim Gröger 18d0098bb3 [pricelist][#6] draggable change of order of pricelist columns 2021-04-17 18:26:21 +02:00
Tim Gröger be347225c4 [pricelist] some more style 2021-04-17 14:44:25 +02:00
Tim Gröger e2b46d96b9 [pricelist] clean style tags 2021-04-17 14:17:42 +02:00
Tim Gröger 6e74105f38 [pricelist] clean styele extraIngredients 2021-04-17 13:58:27 +02:00
Tim Gröger ae5212bbfc [pricelist] clean style drinkType 2021-04-17 13:40:03 +02:00
Tim Gröger 2a11964c4b [pricelist][electron] add electron 2021-04-17 12:36:19 +02:00
Tim Gröger e0bf8f77bf [pricelist][fix] real fix for loading pictures in cordova 2021-04-16 17:19:34 +02:00
Tim Gröger c76da59290 [pricelist][fix] cordova loading pictures 2021-04-16 16:50:58 +02:00
Tim Gröger 52ae8fce29 [pricelist] add fullscreen for pricelist 2021-04-15 23:07:03 +02:00
Tim Gröger f7a6f3fbe1 [pricelist] add useroption for pricelist_view 2021-04-15 22:54:40 +02:00
Tim Gröger 8ee5c891a5 [pricelist] add pricelist as list 2021-04-15 22:04:33 +02:00
Tim Gröger 479dfd658a [pricelist] add some more permissions 2021-04-15 15:40:40 +02:00
Tim Gröger 97dcc8e602 Merge remote-tracking branch 'origin/develop' into feature/pricelist 2021-04-15 15:36:35 +02:00
Tim Gröger a376fd7cc2 [pricelist] fix update volume when ingredients changed 2021-04-15 15:35:08 +02:00
Tim Gröger 8b21ccf978 [pricelist] add permissions 2021-04-14 22:42:09 +02:00
Tim Gröger cee6eda585 [pricelist] delete visibleColumns 2021-04-14 20:11:44 +02:00
Tim Gröger dc948e6f11 [pricelist][prettier] some style up 2021-04-14 19:44:53 +02:00
Tim Gröger 86bb722623 [pricelist] no change of cost_per_volume if volumes has ingredients 2021-04-14 19:43:32 +02:00
Tim Gröger 0df2677b1b [pricelist](issue #4) add warning when price is less then min_price 2021-04-14 19:39:28 +02:00
Tim Gröger 43397fe3a7 [pricelist] dont show 'add ingredients' if cost_per_volume exists 2021-04-14 19:13:47 +02:00
Tim Gröger 851c5a0588 [pricelist] sync min_prices if changing 2021-04-14 18:53:17 +02:00
Tim Gröger 0626cf993f [pricelist] cleanup some code 2021-04-13 16:20:32 +02:00
Tim Gröger 9b0679278c [pricelist][cocktailbuilder] fix new ingredient component 2021-04-12 06:45:18 +02:00
Tim Gröger b40b1064e7 [pricelist][calculation] can add new drink 2021-04-11 23:11:43 +02:00
Tim Gröger 06256f651a [pricelist][calculation] modify picture 2021-04-11 22:08:59 +02:00
Tim Gröger e90dc4c306 [pricelist][calculation] stable version of new view 2021-04-11 16:29:11 +02:00
Tim Gröger 8c321fb8ca [pricelist] modify ingredients without saving 2021-04-10 23:05:03 +02:00
Tim Gröger 459a9fea08 [pricelist] fix copy object of state 2021-04-10 00:14:39 +02:00
Tim Gröger 7a3a151688 [pricelist] cleanup some code 2021-04-09 23:49:49 +02:00
Tim Gröger 1c64dbbaf6 [pricelist][calculation] add edit-button 2021-04-06 22:45:33 +02:00
Ferdinand Thiessen 4e340e5bea [core] Updates dependencies 2021-04-06 16:04:17 +02:00
Tim Gröger 89cd109587 [pricelist][calculation] fixed overloade 2021-04-04 23:20:53 +02:00
Ferdinand Thiessen 010ad6e107 [notifications] Fixed icon names 2021-04-04 22:55:11 +02:00
Tim Gröger f5b370e743 [pricelist][calculation] update grid view 2021-04-03 22:39:06 +02:00
Tim Gröger 741216ac3e Merge remote-tracking branch 'origin/develop' into feature/pricelist 2021-04-03 20:51:41 +02:00
Tim Gröger 284652b002 [pricelist][calculation] start add grid view 2021-04-02 22:30:06 +02:00
Tim Gröger 736ea04b4a [pricelist][search] add help 2021-04-02 19:32:08 +02:00
Tim Gröger 5d1df48b9a [pricelist][fix] fixed issues from merge 3eea079871 2021-04-02 14:06:03 +02:00
Tim Gröger 7289a1724d [pricelist][tags] add tags 2021-04-01 22:39:54 +02:00
Tim Gröger 909275727a [pricelist][chore] minor cleanup 2021-04-01 11:15:21 +02:00
Tim Gröger 8ecbddc6ca Merge branch 'develop' into feature/pricelist 2021-03-31 15:21:35 +02:00
Tim Gröger f25651a71e [pricelist][receipt] change to table with grid, add search 2021-03-31 15:17:43 +02:00
Tim Gröger fb14df0c43 [pricelist] add search 2021-03-31 14:18:55 +02:00
Tim Gröger 6cdc143aa9 [pricelist] some styling on pricelist 2021-03-30 22:32:18 +02:00
Tim Gröger 7089ee4d62 [pricelist][receipt] some more styling 2021-03-30 22:16:12 +02:00
Tim Gröger aadfca2d31 Merge branch 'develop' into feature/pricelist 2021-03-30 20:43:54 +02:00
Tim Gröger a7d32d6f7c [pricelist][styling] style up receipts 2021-03-30 15:40:02 +02:00
Tim Gröger 1b478d7680 Merge remote-tracking branch 'origin/develop' into feature/pricelist 2021-03-30 09:59:27 +02:00
Tim Gröger d185b84823 [pricelist] receipt as list, fixed some merge issues 2021-03-29 22:35:54 +02:00
Tim Gröger 0d044b505a [pricelist] fix some merge issues 2021-03-29 21:29:04 +02:00
Tim Gröger 3eea079871 Merge remote-tracking branch 'origin/develop' into feature/pricelist 2021-03-29 20:22:50 +02:00
Tim Gröger 30e101c364 [pricelist] add Receipts 2021-03-29 12:50:50 +02:00
Tim Gröger cf0f453b7c [pricelist][reciepts] first try for reciepts 2021-03-28 20:34:06 +02:00
Tim Gröger 24aec1a98c [pricelist] add Cocktailbuilder 2021-03-28 19:53:04 +02:00
Tim Gröger 8eecb70df0 [pricelist] add public (outer) pricelist withoud login 2021-03-28 16:43:30 +02:00
Tim Gröger 59d6023462 [pricelist] add picture and visiblity for user pricelist 2021-03-28 13:40:41 +02:00
Tim Gröger f58e0c382c [pricelist][fix] new price will be shown after adding it 2021-03-28 13:08:41 +02:00
Tim Gröger 3d20292898 [pricelist][picture] update picture if changed, add no-image.svg 2021-03-28 11:34:36 +02:00
Tim Gröger aa82b9029a Merge branch 'develop' into feature/pricelist 2021-03-27 22:17:07 +01:00
Tim Gröger d42c6dcce1 [pricelist] delete drink pictures 2021-03-25 23:14:49 +01:00
184 changed files with 1767 additions and 19309 deletions

View File

@ -17,11 +17,11 @@ module.exports = {
project: resolve(__dirname, './tsconfig.json'),
tsconfigRootDir: __dirname,
ecmaVersion: 2019, // Allows for the parsing of modern ECMAScript features
sourceType: 'module' // Allows for the use of imports
sourceType: 'module', // Allows for the use of imports
},
env: {
browser: true
browser: true,
},
// Rules order is important, please avoid shuffling them
@ -44,7 +44,7 @@ module.exports = {
// https://github.com/prettier/eslint-config-prettier#installation
// usage with Prettier, provided by 'eslint-config-prettier'.
'prettier', //'plugin:prettier/recommended'
'plugin:prettier/recommended',
],
plugins: [
@ -54,10 +54,6 @@ module.exports = {
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
// required to lint *.vue files
'vue',
// https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
// Prettier has not been included as plugin to avoid performance impact
// add it as an extension for your IDE
],
globals: {
@ -70,19 +66,26 @@ module.exports = {
__QUASAR_SSR_PWA__: true,
process: true,
Capacitor: true,
chrome: true
chrome: true,
},
// add your custom rules here
rules: {
'prefer-promise-reject-errors': 'off',
// VueStuff
// Defaults to error on eslint-plugin-vue 8.0.3, but let us be not too strict with names
'vue/multi-word-component-names': 'off',
// TypeScript
quotes: ['warn', 'single', { avoidEscape: true }],
// Rejects on promises should always be of the Error type (and allow empty rejects as well)
'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }],
// Allow " if ' is contained inside the string, so we can avoid escaping
quotes: ['error', 'single', { avoidEscape: true }],
// TypeScript, let us be not too strict
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
// allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
}
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
},
};

3
.gitignore vendored
View File

@ -4,6 +4,7 @@ node_modules
# We use yarn, so ignore npm
package-lock.json
yarn.lock
# Quasar core related directories
.quasar
@ -17,6 +18,8 @@ package-lock.json
# Capacitor related directories and files
/src-capacitor/www
/src-capacitor/android
/src-capacitor/ios
/src-capacitor/node_modules
# BEX related directories and files

4
.gitmodules vendored
View File

@ -1,4 +0,0 @@
[submodule "deps/quasar-ui-qcalendar"]
path = deps/quasar-ui-qcalendar
url = https://github.com/susnux/quasar-ui-qcalendar
branch = quasar2

View File

@ -3,6 +3,6 @@
module.exports = {
plugins: [
// to edit target browsers: use "browserslist" field in package.json
require('autoprefixer')
]
}
require('autoprefixer'),
],
};

16
.woodpecker/lint.yml Normal file
View File

@ -0,0 +1,16 @@
pipeline:
install:
image: node:lts-alpine
commands:
- yarn install
lint:
image: node:lts-alpine
commands:
- yarn lint
build:
image: node:lts-alpine
commands:
- yarn quasar build
branches: [main, develop]

106
README.md
View File

@ -1,62 +1,88 @@
# Flaschengeist (frontend)
![status-badge](http://os-sc.org:8000/api/badges/ferfissimo/flaschengeist-frontend/status.svg)
Modular student club administration system, licensed under the MIT license.
## Installation
### Requirements
```
"engines": {
"node": ">= 14.18.1",
"npm": ">= 6.14.12",
"yarn": ">= 1.22.0"
}
```
So on debian (buster and bullseye) you will need to install node.js and yarn beside the debian packages to meet the needed versions.
```bash
pushd ~/opt
wget https://nodejs.org/dist/latest-v16.x/node-v16.13.0-linux-x64.tar.xz
tar -xJf node-v16.13.0-linux-x64.tar.xz
export PATH="$(pwd)/node-v16.13.0-linux-x64/bin":"$PATH"
npm i -g yarn
npm i -g @quasar/cli
popd
```
### Install the dependencies
```bash
yarn install
```
Be aware npm might not work.
### Configure Plugins
You can activate and deactive Plugins in `src/boot/plugins.ts`.
You have to set the name of the Plugin into `config.loadModules`.
#### Installing a plugin
Simply add it as a dependency and install it, for example installing the `pricelist`-plugin:
```sh
yarn add '@flaschengeist/pricelist'
yarn install
```
#### Enable / Disable a plugin
After installing a plugin you will have to enable it,
this is done by adding it to the `plugin.config.js` file.
For the example above the file should look like:
```js
module.exports = [
// pricelist plugin:
'@flaschengeist/pricelist',
];
```
Remember to rebuild the project
### Configure Backend
The application is using the API of [the backend](https://flaschengeist.dev/Flaschengeist/flaschengeist)
This access needs to be configured in `src/config.ts'->config.baseURL
- either you do have a proxy webserver that maps the '/api' to the backend (http://localhost:5000) or
- you do directly configure the backend there:`baseURL: 'http://localhost:5000'`. Be aware not committing this configuration.
### Build the application
```bash
```sh
yarn quasar build
```
### Notes on mobile apps (Cordova)
For mobile applications older web engines should or must be supported,
as manufaturer often do not update their phones, so for building cordova apps set the `BROWSERSLIST_ENV` environment variable to
`BROWSERSLIST_ENV=cordova`.
This will produce ECDMAscript compatible with iOS 13+ and Android Webview 76 (relased October 2019).
## Development
### Icons used
We are using the `mdi-v5` icon set, so feel free to use any icon from it.
A list can be found [here](https://materialdesignicons.com/)
### Commands useful for development
#### Start the app in development mode
Provides hot-code reloading, error reporting, etc.
```bash
yarn quasar dev
```
#### File linting
```bash
yarn run lint
```
### Plugins
#### Build a Plugin
A Flaschengeist-Frontend-Plugin should be placed in `src/plugins`.
It needs a `plugin.ts` File which exports a plugin with the following interface:
```
name: string;
mainRoutes?: PluginRouteConfig[];
outRoutes?: PluginRouteConfig[];
requiredModules: string[];
version: string;
```
You have to import `FG_Plugin` from `plugins.d.ts`.
Please refer to our [development wiki](https://flaschengeist.dev/Flaschengeist/flaschengeist/wiki/Development).

View File

@ -40,7 +40,7 @@
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue';
import { date as q_date } from 'quasar';
import { stringIsDate, stringIsTime, stringIsDateTime, Validator } from 'src/utils/validators';
import { stringIsDate, stringIsTime, stringIsDateTime, Validator } from '..';
export default defineComponent({
name: 'IsoDateInput',
@ -54,7 +54,7 @@ export default defineComponent({
label: { type: String, default: 'Datum' },
readonly: Boolean,
rules: {
type: Array as PropType<Validator[]>,
type: Array as PropType<Validator<Date>[]>,
default: () => [],
},
},
@ -62,7 +62,22 @@ export default defineComponent({
setup(props, { emit, attrs }) {
const customRules = computed(() => [
props.type == 'date' ? stringIsDate : props.type == 'time' ? stringIsTime : stringIsDateTime,
...props.rules,
(value?: string) => {
if (props.rules.length > 0 && !!value) {
let date: Date | undefined = undefined;
if (props.type == 'date') date = modifyDate(value);
else if (props.type == 'time') date = modifyTime(value);
else {
const split = value.split(' ');
date = modifyTime(split[1], modifyDate(split[0]));
}
for (const rule of props.rules) {
const r = rule(date);
if (typeof r === 'string') return r;
}
return true;
}
},
]);
const clearable = computed(() =>

View File

@ -0,0 +1,46 @@
<template>
<q-avatar>
<slot :avatarURL="avatarURL(modelValue)">
<q-img :src="avatarURL(modelValue)" style="min-width: 100%; min-height: 100%">
<template #error>
<img :src="fallback" style="height: 100%" />
</template>
</q-img>
</slot>
</q-avatar>
</template>
<script lang="ts">
import { PropType, defineComponent } from 'vue';
import { avatarURL } from '@flaschengeist/api';
/**
* Display an avatar for an user
*
* Slots:
* default - scope: {avatarURL}
*/
export default defineComponent({
name: 'UserAvatar',
props: {
modelValue: {
type: [Object, String] as PropType<FG.User | string>,
required: true,
},
showZoom: {
type: Boolean,
default: false,
},
fallback: {
type: String,
default: 'no-image.svg',
},
},
emits: ['error'],
setup() {
return {
avatarURL,
};
},
});
</script>

5
api/components/index.ts Normal file
View File

@ -0,0 +1,5 @@
import IsoDateInput from './IsoDateInput.vue';
import PasswordInput from './PasswordInput.vue';
import UserAvatar from './UserAvatar.vue';
export { IsoDateInput, PasswordInput, UserAvatar };

10
api/index.ts Normal file
View File

@ -0,0 +1,10 @@
export { api, pinia } from './src/internal';
export * from './src/stores/';
export * from './src/utils/datetime';
export * from './src/utils/permission';
export * from './src/utils/persistent';
export * from './src/utils/user';
export * from './src/utils/validators';
export * from './src/utils/misc';

28
api/package.json Normal file
View File

@ -0,0 +1,28 @@
{
"license": "MIT",
"version": "1.0.0-alpha.7",
"name": "@flaschengeist/api",
"author": "Tim Gröger <flaschengeist@wu5.de>",
"homepage": "https://flaschengeist.dev/Flaschengeist",
"description": "Modular student club administration system",
"bugs": {
"url": "https://flaschengeist.dev/Flaschengeist/flaschengeist/issues"
},
"main": "./src/index.ts",
"peerDependencies": {
"@quasar/app": "^3.2.4",
"flaschengeist": "^2.0.0-alpha.1",
"pinia": "^2.0.6"
},
"devDependencies": {
"@flaschengeist/types": "^1.0.0-alpha.10",
"@types/node": "^14.18.00",
"typescript": "^4.5.2"
},
"prettier": {
"singleQuote": true,
"semi": true,
"printWidth": 100,
"arrowParens": "always"
}
}

6
api/shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
//https://github.com/vuejs/vue-next/issues/3130
declare module '*.vue' {
import { ComponentOptions } from 'vue';
const component: ComponentOptions;
export default component;
}

6
api/src/internal.ts Normal file
View File

@ -0,0 +1,6 @@
import axios from 'axios';
import { createPinia } from 'pinia';
export const api = axios.create();
export const pinia = createPinia();

23
api/src/stores/index.ts Normal file
View File

@ -0,0 +1,23 @@
import { AxiosError } from 'axios';
/**
* Check if error is an AxiosError, and optional if a specific status was returned
*
* @param error Thrown error to check
* @param status If set, check if this error has set thouse status code
*/
export function isAxiosError(error: unknown, status?: number) {
// Check if it is an axios error (with axios 1.0 `error instanceof AxiosError` will be possible)
if (typeof error !== 'object' || !error || !('isAxiosError' in error)) return false;
// Check status code if status was given
if (status !== undefined)
return (
(<AxiosError>error).response !== undefined && (<AxiosError>error).response?.status === status
);
return true;
}
export * from './main';
export * from './session';
export * from './user';

161
api/src/stores/main.ts Normal file
View File

@ -0,0 +1,161 @@
import { FG_Plugin } from '@flaschengeist/types';
import { fixSession, useSessionStore, useUserStore } from '.';
import { AxiosResponse } from 'axios';
import { api } from '../internal';
import { defineStore } from 'pinia';
import { PersistentStorage } from '../utils/persistent';
function reviveSession() {
return PersistentStorage.get<FG.Session>('fg_session').then((s) => fixSession(s || undefined));
}
function clearPersistant() {
void PersistentStorage.remove('fg_session');
}
export function saveSession(session?: FG.Session) {
if (session === undefined) return clearPersistant();
PersistentStorage.set('fg_session', session).catch(() =>
console.error('Could not save token to storage')
);
}
export const useMainStore = defineStore({
id: 'main',
state: () => ({
session: undefined as FG.Session | undefined,
user: undefined as FG.User | undefined,
notifications: [] as Array<FG_Plugin.Notification>,
shortcuts: [] as Array<FG_Plugin.MenuLink>,
}),
getters: {
loggedIn(): boolean {
return this.session !== undefined;
},
currentUser(): FG.User {
if (this.user === undefined) throw 'Not logged in, this should not be called';
return this.user;
},
currentSession(): FG.Session {
if (this.session === undefined) throw 'Not logged in, this should not be called';
return this.session;
},
permissions(): string[] {
return this.user?.permissions || [];
},
},
actions: {
/** Ininitalize store from saved session
* Updates session and loads current user
*/
async init() {
const sessionStore = useSessionStore();
const userStore = useUserStore();
try {
this.session = await reviveSession();
if (this.session !== undefined) {
this.session = await sessionStore.getSession(this.session.token);
if (this.session !== undefined) this.user = await userStore.getUser(this.session.userid);
}
} catch (error) {
console.warn('Could not load token from storage', error);
}
},
async login(userid: string, password: string) {
const userStore = useUserStore();
try {
const { data } = await api.post<FG.Session>('/auth', { userid, password });
this.session = fixSession(data);
this.user = await userStore.getUser(data.userid, true);
return true;
} catch ({ response }) {
this.handleLoggedOut();
return (<AxiosResponse | undefined>response)?.status || false;
}
},
async logout() {
if (!this.session || !this.session.token) return false;
try {
const token = this.session.token;
await api.delete(`/auth/${token}`);
} catch (error) {
return false;
} finally {
this.handleLoggedOut();
}
return true;
},
async requestReset(userid: string) {
return await api
.post('/auth/reset', { userid })
.then(() => true)
.catch(() => false);
},
async resetPassword(token: string, password: string) {
return await api
.post('/auth/reset', { token, password })
.then(() => true)
.catch(({ response }) =>
response && 'status' in response ? (<AxiosResponse>response).status : false
);
},
async loadNotifications(flaschengeist: FG_Plugin.Flaschengeist) {
const { data } = await api.get<FG.Notification[]>('/notifications', {
params:
this.notifications.length > 0
? { from: this.notifications[this.notifications.length - 1].time }
: {},
});
const notes = [] as FG_Plugin.Notification[];
data.forEach((n) => {
n.time = new Date(n.time);
const plugin = flaschengeist?.plugins.filter((p) => p.id === n.plugin)[0];
if (!plugin) console.debug('Could not find a parser for this notification', n);
else notes.push(plugin.notification(n));
});
this.notifications.push(...notes);
return notes;
},
async removeNotification(id: number) {
const idx = this.notifications.findIndex((n) => n.id === id);
if (idx >= 0)
try {
this.notifications.splice(idx, 1);
await api.delete(`/notifications/${id}`);
} catch (error) {
if (this.notifications.length > idx)
this.notifications.splice(idx, this.notifications.length - idx - 1);
}
},
async getShortcuts() {
const { data } = await api.get<Array<FG_Plugin.MenuLink>>(
`users/${this.currentUser.userid}/shortcuts`
);
this.shortcuts = data;
},
async setShortcuts() {
await api.put(`users/${this.currentUser.userid}/shortcuts`, this.shortcuts);
},
handleLoggedOut() {
this.$reset();
void clearPersistant();
},
},
});
export default () => useMainStore;

71
api/src/stores/session.ts Normal file
View File

@ -0,0 +1,71 @@
import { AxiosResponse } from 'axios';
import { defineStore } from 'pinia';
import { api } from '../internal';
import { isAxiosError, useMainStore } from '.';
export function fixSession(s?: FG.Session) {
return !s ? s : Object.assign(s, { expires: new Date(s.expires) });
}
export const useSessionStore = defineStore({
id: 'sessions',
state: () => ({}),
getters: {},
actions: {
async getSession(token: string) {
return await api
.get(`/auth/${token}`)
.then(({ data }: AxiosResponse<FG.Session>) => data)
.catch(() => undefined);
},
async getSessions() {
try {
const { data } = await api.get<FG.Session[]>('/auth');
data.forEach(fixSession);
const mainStore = useMainStore();
const currentSession = data.find((session) => {
return session.token === mainStore.session?.token;
});
if (currentSession) {
mainStore.session = currentSession;
}
return data;
} catch (error) {
return [] as FG.Session[];
}
},
async deleteSession(token: string) {
const mainStore = useMainStore();
if (token === mainStore.session?.token) return mainStore.logout();
try {
await api.delete(`/auth/${token}`);
return true;
} catch (error) {
// Ignore 401, as this means we are already logged out, throw all other
if (!isAxiosError(error, 401)) throw error;
}
return false;
},
async updateSession(lifetime: number, token: string) {
try {
const { data } = await api.put<FG.Session>(`auth/${token}`, { value: lifetime });
fixSession(data);
const mainStore = useMainStore();
if (mainStore.session?.token == data.token) mainStore.session = data;
return true;
} catch (error) {
return false;
}
},
},
});

211
api/src/stores/user.ts Normal file
View File

@ -0,0 +1,211 @@
import { defineStore } from 'pinia';
import { api } from '../internal';
import { isAxiosError, useMainStore } from '.';
export function fixUser(u?: FG.User) {
return !u ? u : Object.assign(u, { birthday: u.birthday ? new Date(u.birthday) : undefined });
}
/**
* Check if state is outdated / dirty
* Value is considered outdated after 15 minutes
* @param updated Time of last updated (in milliseconds see Date.now())
* @returns True if outdated, false otherwise
*/
function isDirty(updated: number) {
return Date.now() - updated > 15 * 60 * 1000;
}
export const useUserStore = defineStore({
id: 'users',
state: () => ({
roles: [] as FG.Role[],
permissions: [] as FG.Permission[],
// list of all users, include deleted ones, use `users` getter for list of active ones
_users: [] as FG.User[],
// Internal flags for deciding if lists need to force-loaded
_dirty_users: 0,
_dirty_roles: 0,
}),
getters: {
users(state) {
return state._users.filter((u) => !u.deleted);
},
},
actions: {
/** Simply filter all users by ID */
findUser(userid: string) {
return this._users.find((user) => user.userid === userid);
},
/** Retrieve user by ID
* @param userid ID of user to retrieve
* @param force If set to true the user is loaded from backend even when a local copy is available
* @returns Retrieved user (Promise) or raise an error
* @throws Probably an AxiosError if loading failed
*/
async getUser(userid: string, force = false) {
const idx = this._users.findIndex((user) => user.userid === userid);
if (force || idx === -1 || isDirty(this._dirty_users)) {
try {
const { data } = await api.get<FG.User>(`/users/${userid}`);
fixUser(data);
if (idx === -1) this._users.push(data);
else this._users[idx] = data;
return data;
} catch (error) {
// Ignore 404, throw all other
if (!isAxiosError(error, 404)) throw error;
}
} else {
return this._users[idx];
}
},
/** Retrieve list of all users
* @param force If set to true a fresh users list is loaded from backend even when a local copy is available
* @returns Array of retrieved users (Promise)
* @throws Probably an AxiosError if loading failed
*/
async getUsers(force = false) {
if (force || isDirty(this._dirty_users)) {
const { data } = await api.get<FG.User[]>('/users');
data.forEach(fixUser);
this._users = data;
this._dirty_users = Date.now();
}
return this._users;
},
/** Save modifications of user on backend
* @param user Modified user to save
* @throws Probably an AxiosError if request failed (404 = Invalid userid, 400 = Invalid data)
*/
async updateUser(user: FG.User) {
await api.put(`/users/${user.userid}`, user);
// Modifcation accepted by backend
// Save modifications back to our users list
const idx = this._users.findIndex((u) => u.userid === user.userid);
if (idx > -1) this._users[idx] = user;
// If user was current user, save modifications back to the main store
const mainStore = useMainStore();
if (user.userid === mainStore.user?.userid) mainStore.user = user;
},
/** Register a new user
* @param user User to register (id not set)
* @returns The registered user (id set)
* @throws Probably an AxiosError if request failed
*/
async createUser(user: FG.User) {
const { data } = await api.post<FG.User>('/users', user);
this._users.push(<FG.User>fixUser(data));
return data;
},
/** Delete an user
* Throws if failed and resolves void if succeed
*
* @param user User or ID of user to delete
* @throws Probably an AxiosError if request failed
*/
async deleteUser(user: FG.User | string) {
if (typeof user === 'object') user = user.userid;
await api.delete(`/users/${user}`);
this._users = this._users.filter((u) => u.userid != user);
},
/** Upload an avatar for an user
* Throws if failed and resolves void if succeed
*
* @param user User or ID of user
* @param file Avatar file to upload
* @throws Probably an AxiosError if request failed
*/
async uploadAvatar(user: FG.User | string, file: string | File) {
if (typeof user === 'object') user = user.userid;
const formData = new FormData();
formData.append('file', file);
await api.post(`/users/${user}/avatar`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
},
/** Delete avatar of an user
* @param user User or ID of user
* @throws Probably an AxiosError if request failed
*/
async deleteAvatar(user: FG.User | string) {
if (typeof user === 'object') user = user.userid;
await api.delete(`/users/${user}/avatar`);
},
/** Retrieve list of all permissions
* @param force If set to true a fresh list is loaded from backend even when a local copy is available
* @returns Array of retrieved permissions (Promise)
* @throws Probably an AxiosError if request failed
*/
async getPermissions(force = false) {
if (force || this.permissions.length === 0) {
const { data } = await api.get<FG.Permission[]>('/roles/permissions');
this.permissions = data;
}
return this.permissions;
},
/** Retrieve list of all roles
* @param force If set to true a fresh list is loaded from backend even when a local copy is available
* @returns Array of retrieved roles (Promise)
* @throws Probably an AxiosError if request failed
*/
async getRoles(force = false) {
if (force || isDirty(this._dirty_roles)) {
const { data } = await api.get<FG.Role[]>('/roles');
this.roles = data;
this._dirty_roles = Date.now();
}
return this.roles;
},
/** Save modifications of role on the backend
* @param role role to save
* @throws Probably an AxiosError if request failed
*/
async updateRole(role: FG.Role) {
await api.put(`/roles/${role.id}`, role);
const idx = this.roles.findIndex((r) => r.id === role.id);
if (idx != -1) this.roles[idx] = role;
else this._dirty_roles = 0;
},
/** Create a new role
* @param role Role to create (ID not set)
* @returns Created role (ID set)
* @throws Probably an AxiosError if request failed
*/
async newRole(role: FG.Role) {
const { data } = await api.post<FG.Role>('/roles', role);
this.roles.push(data);
return data;
},
/** Delete a role
* @param role Role or ID of role to delete
* @throws Probably an AxiosError if request failed (409 if role still in use)
*/
async deleteRole(role: FG.Role | number) {
if (typeof role === 'object') role = role.id;
await api.delete(`/roles/${role}`);
this.roles = this.roles.filter((r) => r.id !== role);
},
},
});

View File

@ -17,12 +17,23 @@ export function formatDateTime(
return dateTimeFormat.format(date);
}
export function asDate(date?: Date) {
return date ? formatDateTime(date, true) : '';
export function asDate(date?: Date, placeholder = '') {
return date ? formatDateTime(date, true) : placeholder;
}
export function asHour(date?: Date) {
return date ? formatDateTime(date, false, true) : '';
export function asHour(date?: Date, placeholder = '') {
return date ? formatDateTime(date, false, true) : placeholder;
}
export function formatStartEnd(start: Date, end?: Date) {
const today = asDate(new Date());
const startDate = asDate(start);
const endDate = end ? asDate(end) : '';
return (
(today !== startDate ? `${startDate}, ` : '') +
asHour(start) +
(end ? ' - ' + (endDate !== startDate ? `${endDate}, ` : '') + asHour(end) : '')
);
}
export function startOfWeek(date: Date, startMonday = true) {

3
api/src/utils/misc.ts Normal file
View File

@ -0,0 +1,3 @@
export function clone<T>(o: T): T {
return <T>JSON.parse(JSON.stringify(o));
}

View File

@ -1,4 +1,4 @@
import { useMainStore } from 'src/stores';
import { useMainStore } from '../stores';
export function hasPermission(permission: string) {
const store = useMainStore();

View File

@ -0,0 +1,35 @@
import { LocalStorage, Platform } from 'quasar';
import { Storage } from '@capacitor/storage';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type PersitentTypes = Date | RegExp | number | boolean | string | object;
export class PersistentStorage {
static clear() {
if (Platform.is.capacitor) return Storage.clear();
else return Promise.resolve(LocalStorage.clear());
}
static remove(key: string) {
if (Platform.is.capacitor) return Storage.remove({ key: key });
else return Promise.resolve(LocalStorage.remove(key));
}
static set(key: string, value: PersitentTypes) {
if (Platform.is.capacitor) return Storage.set({ key, value: JSON.stringify(value) });
else return Promise.resolve(LocalStorage.set(key, value));
}
static get<T extends PersitentTypes>(key: string) {
if (Platform.is.capacitor)
return Storage.get({ key }).then((v) =>
v.value === null ? null : (JSON.parse(v.value) as T)
);
else return Promise.resolve(LocalStorage.getItem<T>(key));
}
static keys() {
if (Platform.is.capacitor) return Storage.keys().then((v) => v.keys);
else return Promise.resolve(LocalStorage.getAllKeys());
}
}

6
api/src/utils/user.ts Normal file
View File

@ -0,0 +1,6 @@
import { api } from '../internal';
export function avatarURL(user: FG.User | string, thumbnail = true) {
if (typeof user === 'object') user = user.userid;
return `${api.defaults?.baseURL || ''}/users/${user}/avatar${thumbnail ? '?thumbnail' : ''}`;
}

View File

@ -1,4 +1,4 @@
export type Validator = (value: unknown) => boolean | string;
export type Validator<T = unknown> = (value?: T | null) => boolean | string;
export function notEmpty(val: unknown) {
return !!val || 'Feld darf nicht leer sein!';

16
api/tsconfig.json Normal file
View File

@ -0,0 +1,16 @@
{
"extends": "@quasar/app/tsconfig-preset",
"target": "esnext",
"compilerOptions": {
"baseUrl": "./",
"lib": [
"es2020",
"dom"
],
"types": [
"@flaschengeist/types",
"@quasar/app",
"node"
]
}
}

View File

@ -1,6 +1,4 @@
/* eslint-env node */
module.exports = {
presets: [
'@quasar/babel-preset-app'
]
}
presets: ['@quasar/babel-preset-app'],
};

@ -1 +0,0 @@
Subproject commit 000c043ce6cb4a082d8bde4ff2b8c955eade10a4

View File

@ -2,39 +2,45 @@
"private": true,
"license": "MIT",
"version": "2.0.0-alpha.1",
"productName": "Flaschengeist",
"name": "flaschengeist-frontend",
"productName": "flaschengeist-frontend",
"name": "flaschengeist",
"author": "Tim Gröger <flaschengeist@wu5.de>",
"homepage": "https://flaschengeist.dev/Flaschengeist",
"description": "Modular student club administration system",
"bugs": {
"url" : "https://flaschengeist.dev/Flaschengeist/flaschengeist-frontend/issues"
"url": "https://flaschengeist.dev/Flaschengeist/flaschengeist/issues"
},
"scripts": {
"format": "prettier --config ./package.json --write '{,!(node_modules)/**/}*.ts'",
"lint": "eslint --ext .js,.ts,.vue ./src"
"format": "prettier --config ./package.json --write '{,!(node_modules|dist|.*)/**/}*.{js,ts,vue}'",
"lint": "eslint --ext .js,.ts,.vue ./src ./api"
},
"dependencies": {
"axios": "^0.21.1",
"cordova": "^10.0.0",
"pinia": "^2.0.0-alpha.10",
"quasar": "^2.0.0-beta.11"
"@flaschengeist/api": "file:./api",
"@flaschengeist/users": "^1.0.0-alpha.3",
"axios": "^0.24.0",
"pinia": "^2.0.6",
"quasar": "^2.3.3"
},
"devDependencies": {
"@quasar/app": "^3.0.0-beta.10",
"@quasar/extras": "^1.10.2",
"@quasar/quasar-app-extension-qcalendar": "file:deps/quasar-ui-qcalendar/app-extension",
"@types/node": "^12.20.7",
"@types/webpack": "^4.41.27",
"@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "^4.20.0",
"@typescript-eslint/parser": "^4.20.0",
"eslint": "^7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-vue": "^7.8.0",
"eslint-webpack-plugin": "^2.5.3",
"prettier": "^2.2.1",
"typescript": "^4.2.3"
"@capacitor/core": "^3.3.2",
"@capacitor/storage": "^1.2.3",
"@flaschengeist/types": "^1.0.0-alpha.10",
"@quasar/app": "^3.2.4",
"@quasar/extras": "^1.12.2",
"@types/node": "^14.18.0",
"@types/webpack": "^5.28.0",
"@types/webpack-env": "^1.16.3",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"eslint": "^8.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.1.1",
"eslint-webpack-plugin": "^3.1.1",
"modify-source-webpack-plugin": "^3.0.0",
"prettier": "^2.5.1",
"typescript": "^4.5.2",
"vuedraggable": "^4.1.0"
},
"prettier": {
"singleQuote": true,
@ -42,19 +48,25 @@
"printWidth": 100,
"arrowParens": "always"
},
"browserslist": [
"last 10 Chrome versions",
"last 10 Firefox versions",
"last 4 Edge versions",
"last 4 Safari versions",
"last 8 Android versions",
"last 1 ChromeAndroid versions",
"last 1 FirefoxAndroid versions",
"last 6 iOS versions"
],
"browserslist": {
"defaults": [
"Firefox esr",
"last 6 Chrome versions",
"last 4 Firefox versions",
"last 4 Edge versions",
"last 4 Safari versions",
"last 4 ChromeAndroid versions",
"last 1 FirefoxAndroid versions"
],
"cordova": [
"iOS >= 13.0",
"Android >= 76",
"ChromeAndroid >= 76"
]
},
"engines": {
"node": ">= 12.0.0",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
"node": ">= 14.18.1",
"npm": ">= 6.14.12",
"yarn": ">= 1.22.0"
}
}

6
plugin.config.js Normal file
View File

@ -0,0 +1,6 @@
// You can add your plugins here
module.exports = [
// '@flaschengeist/balance',
// '@flaschengeist/schedule',
// '@flaschengeist/pricelist',
]

168
public/no-image.svg Normal file
View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1024"
height="1024"
viewBox="0 0 270.93333 270.93334"
version="1.1"
id="svg37"
inkscape:version="1.0.2 (e86c8708, 2021-01-15)"
sodipodi:docname="no-image.svg">
<defs
id="defs31">
<rect
x="-328.72475"
y="24.854798"
width="167.56944"
height="62.537879"
id="rect1100" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.66"
inkscape:cx="-222.85714"
inkscape:cy="248.57143"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="2560"
inkscape:window-height="1303"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1" />
<metadata
id="metadata34">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<circle
id="path10"
cx="135.46666"
cy="135.46666"
style="fill:#1976d2;fill-opacity:1;stroke-width:0.265065;opacity:1"
r="135.46666" />
<path
id="path897"
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:2.4226772;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 443.15234 56.630859 A 66.428573 82.142858 16.845913 0 0 371.42188 118.32031 A 66.428573 82.142858 16.845913 0 0 411.19531 216.18945 A 66.428573 82.142858 16.845913 0 0 417.72266 217.72852 C 381.34438 302.48672 370.45756 410.53422 348.14648 499.98438 C 297.07736 687.66963 128.47878 622.66455 146.45508 716.38281 C 160.50823 789.6481 350.53291 863.07431 404.40039 881.20117 C 404.36927 881.70781 404.3327 882.22702 404.30664 882.7207 C 402.76028 912.46642 410.7207 918.72461 410.7207 918.72461 L 432.67188 918.59766 C 432.67187 918.59766 438.27004 922.75802 441.00195 922.53125 C 443.73387 922.30455 446.94531 918.40625 446.94531 918.40625 L 516.89062 924.79297 C 516.89062 924.79297 519.31971 928.09007 521.125 928.27148 C 522.93029 928.45267 525.90234 925.73828 525.90234 925.73828 L 547.53125 926.69531 C 547.53125 926.69531 549.70216 931.12195 551.70508 931.54492 C 553.70725 931.97129 555.09081 928.73815 557.0293 929.03711 C 572.07401 931.3732 576.56924 937.03281 582.65039 957.60156 C 587.77505 974.93535 595.22123 992.9761 628.75781 1000.5176 C 648.78447 1005.021 775.66385 1000.6487 849.12305 998.74219 C 849.12305 998.74219 858.5188 1005.9328 870.60547 1002.9863 C 910.19976 993.33421 919.78542 952.33706 923.33398 921.09961 C 926.88262 889.86212 910.49308 842.14037 892.4043 835.26367 C 874.31552 828.38693 867.54688 834.25781 867.54688 834.25781 C 794.38713 828.15886 695.31802 794.91067 642.43555 796.74805 C 623.72658 797.39809 605.92942 809.14688 595.65625 826.28125 C 588.66186 837.94703 583.48245 859.20701 563.14258 859.07812 C 560.89588 859.11237 559.32296 855.73577 557.25 855.80078 C 555.17708 855.86568 552.45117 858.87891 552.45117 858.87891 L 531.66797 857.41211 C 531.66797 857.41211 529.50203 853.62212 527.45508 853.38477 C 525.40816 853.14741 521.82422 856.70312 521.82422 856.70312 L 449.90234 850.62305 C 449.90234 850.62305 447.13702 845.72836 444.7168 844.78711 C 442.29665 843.84582 436.68945 846.35352 436.68945 846.35352 L 415.74219 842.4082 C 415.74219 842.4082 407.89779 846.84558 405.02539 873.69922 C 358.98121 845.1153 229.07948 771.28872 265.40039 726.04102 C 306.49077 674.8517 472.92361 721.17976 650.12695 656.71875 C 726.82706 628.35646 797.61671 580.25753 845.84766 519.08398 A 66.376657 87.827348 48.964508 0 0 927.6875 519.24805 A 66.376657 87.827348 48.964508 0 0 980.98047 413.88477 A 66.376657 87.827348 48.964508 0 0 907.37109 380.61328 C 911.18565 353.15829 910.56576 324.56748 904.71094 295.1582 C 874.19541 141.87518 734.80037 48.0882 582.23438 78.189453 C 572.33148 80.143182 562.48437 82.604632 552.73047 85.566406 C 533.35813 91.448951 516.25153 99.658419 501.06836 109.80859 A 66.428573 82.142858 16.845913 0 0 458.80469 58.953125 A 66.428573 82.142858 16.845913 0 0 443.15234 56.630859 z M 598.64062 188.20703 C 604.22194 188.22929 609.06312 189.70004 612.92773 192.57031 C 630.98057 205.9773 623.87627 246.11384 597.05859 282.2168 C 570.24164 318.31869 533.86885 336.71569 515.81836 323.30664 C 497.76711 309.89888 504.87302 269.76201 531.68945 233.66016 C 549.9558 209.06922 573.57677 191.68513 592.82031 188.66992 L 592.82227 188.66992 C 594.83831 188.35408 596.78019 188.19961 598.64062 188.20703 z M 778.42969 278.44141 C 784.01155 278.46343 788.85382 279.93226 792.71875 282.80273 C 810.7689 296.21155 803.66213 336.34605 776.8457 372.44727 C 750.02943 408.54893 713.65672 426.94663 695.60547 413.53906 C 677.55528 400.13024 684.66205 359.99578 711.47852 323.89453 C 729.74482 299.3036 753.36587 281.91757 772.60938 278.90234 C 774.62562 278.58637 776.56907 278.43406 778.42969 278.44141 z M 582.87695 399.91016 C 586.53338 399.95128 589.93604 400.53593 593.03711 401.66406 C 620.67041 411.71655 618.60959 461.69743 588.43555 513.29883 C 558.26146 564.90004 511.39926 598.58305 483.76562 588.53125 C 456.13229 578.47876 458.1931 528.49788 488.36719 476.89648 C 510.90103 438.36065 543.79364 408.38759 571.19336 401.41992 C 575.31072 400.37297 579.22053 399.86903 582.87695 399.91016 z M 643.83594 816.76172 C 685.1496 816.94824 851.34766 854.11133 851.34766 854.11133 C 851.34766 854.11133 688.31573 835.12065 650.18555 833.82812 C 635.17621 833.31932 591.27148 868.21875 591.27148 868.21875 C 591.27148 868.21875 622.20895 822.68111 636.20117 817.55664 C 637.73138 816.99622 640.33478 816.74591 643.83594 816.76172 z "
transform="scale(0.26458333)" />
<path
id="path10-8"
style="fill-opacity:1;stroke-width:3.64724414;fill:#ffffff;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ffffff;stroke-opacity:1;opacity:0.80057803"
d="M 512 0 A 511.99997 511.99997 0 0 0 0 512 A 511.99997 511.99997 0 0 0 512 1024 A 511.99997 511.99997 0 0 0 659.25 1002.3672 C 706.36552 1003.0651 793.17503 1000.1943 849.12305 998.74219 C 849.12305 998.74219 858.5188 1005.9328 870.60547 1002.9863 C 910.19976 993.33421 919.78542 952.33706 923.33398 921.09961 C 926.20746 895.80534 916.007 859.7095 902.41797 843.23633 A 511.99997 511.99997 0 0 0 1024 512 A 511.99997 511.99997 0 0 0 512 0 z "
transform="scale(0.26458333)" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.33699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect942-1"
width="76.028526"
height="73.388649"
x="-21.278112"
y="109.32571"
ry="3.5350549"
transform="rotate(-30.00892)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.391977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect944-7"
width="69.4505"
height="56.151112"
x="-17.909185"
y="113.14103"
ry="0"
transform="rotate(-30.00892)" />
<path
id="path10-3-94"
style="fill:#1976d2;fill-opacity:1;stroke-width:0.0683297"
d="m 68.884108,90.871044 a 34.92124,34.92124 0 0 0 -11.74769,43.865396 l 2.70637,4.68588 a 34.92124,34.92124 0 0 0 15.52651,12.5468 L 123.2496,124.31547 a 34.92124,34.92124 0 0 0 -2.38462,-18.10096 l -4.46922,-7.73814 A 34.92124,34.92124 0 0 0 73.568128,88.16575 Z" />
<path
id="path897-6-8"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:0.165241;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 69.039278,95.120659 a 5.6025989,4.5307973 76.836993 0 0 -2.13225,6.090461 5.6025989,4.5307973 76.836993 0 0 5.68756,4.42371 5.6025989,4.5307973 76.836993 0 0 0.43811,-0.13196 c 0.74268,6.24695 3.78537,13.00002 5.51895,19.04423 3.38604,12.82723 -8.78931,14.73905 -4.53067,19.66107 1.76551,2.04052 6.4553,2.39549 11.0381,2.16453 l 3.43497,-1.98389 c -3.77377,-0.36303 -7.4885,-1.26121 -7.11831,-3.66758 0.68073,-4.42505 12.09089,-7.36618 20.358052,-17.21816 3.5626,-4.29154 6.10303,-9.54716 6.86491,-14.80546 a 4.5272563,5.9903123 18.955588 0 0 4.83918,-2.78197 4.5272563,5.9903123 18.955588 0 0 -0.44664,-8.041018 4.5272563,5.9903123 18.955588 0 0 -5.48235,0.545791 c -0.71126,-1.751685 -1.72325,-3.419125 -3.07226,-4.956384 -7.031112,-8.012324 -18.463402,-8.796579 -26.447502,-1.814405 -0.51824,0.453207 -1.01578,0.934617 -1.49084,1.442271 -0.94352,1.008269 -1.67389,2.076631 -2.2244,3.194051 a 5.6025989,4.5307973 76.836993 0 0 -4.23087,-1.562013 5.6025989,4.5307973 76.836993 0 0 -1.00374,0.396734 z m 13.67184,2.467287 c 0.33015,-0.189526 0.66651,-0.267379 0.99269,-0.229688 1.52358,0.176032 2.47307,2.788932 2.12069,5.836062 -0.35237,3.04705 -1.87308,5.37436 -3.3966,5.19813 -1.52351,-0.17613 -2.47289,-2.78913 -2.12054,-5.83615 0.24002,-2.07551 1.04204,-3.90793 2.07575,-4.742444 l 1.7e-4,-9.5e-5 c 0.10831,-0.08739 0.21769,-0.162799 0.32783,-0.225833 z m 13.69685,-0.803574 c 0.33018,-0.189545 0.6664,-0.267533 0.9926,-0.229843 1.52349,0.176235 2.4729,2.789172 2.12054,5.836151 -0.35234,3.04702 -1.87298,5.37441 -3.39651,5.1983 -1.52348,-0.17624 -2.4729,-2.78917 -2.12054,-5.83617 0.24,-2.075497 1.04211,-3.908161 2.07582,-4.742688 0.10834,-0.0874 0.21795,-0.162716 0.32809,-0.22575 z m -7.40627,13.845038 c 0.21745,-0.12213 0.43816,-0.20399 0.65981,-0.24312 1.97501,-0.34891 3.55829,2.67343 3.53636,6.75042 -0.0219,4.077 -1.64072,7.66488 -3.61571,8.01383 -1.975,0.34891 -3.55819,-2.67326 -3.53627,-6.75027 0.0164,-3.04468 0.93655,-5.93703 2.31716,-7.28321 0.20748,-0.20228 0.42129,-0.36535 0.63865,-0.48765 z m 17.352832,21.22847 c -0.10315,0.0588 -0.20272,0.11824 -0.29832,0.17807 -1.05105,0.65671 -1.69275,1.90208 -1.75,3.22056 l 1.74663,-1.00878 c 0.10074,-0.33823 0.21509,-0.61452 0.34506,-0.77008 0.0713,-0.0853 0.2166,-0.18885 0.42393,-0.30733 0.72661,-0.41504 2.22115,-1.01463 3.95458,-1.65068 l 5.84666,-3.37678 c -3.78613,1.29335 -7.9478,2.39117 -10.26846,3.71516 z" />
<rect
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.33699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect942"
width="76.028526"
height="73.388649"
x="97.497429"
y="66.694847"
ry="3.5350549" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.391977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect944"
width="69.4505"
height="56.151112"
x="100.86639"
y="70.51017"
ry="0" />
<path
id="path10-3"
style="fill:#1976d2;fill-opacity:1;stroke-width:0.0683297"
d="M 132.97782,70.510038 A 34.92124,34.92124 0 0 0 100.8663,102.61974 v 5.41128 a 34.92124,34.92124 0 0 0 7.17007,18.63021 h 55.29238 a 34.92124,34.92124 0 0 0 6.98797,-16.86711 v -8.93604 A 34.92124,34.92124 0 0 0 138.38694,70.510038 Z" />
<path
id="path897-6"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:0.165241;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 130.9868,74.267588 a 4.5307973,5.6025989 16.845913 0 0 -4.89247,4.20761 4.5307973,5.6025989 16.845913 0 0 2.71268,6.675244 4.5307973,5.6025989 16.845913 0 0 0.44538,0.10485 c -2.4812,5.78097 -3.22383,13.15053 -4.74557,19.251518 -3.4832,12.80118 -14.98258,8.3674 -13.7565,14.75951 0.5083,2.64997 4.39189,5.30288 8.47586,7.39491 h 3.96671 c -3.08632,-2.20176 -5.85386,-4.8374 -4.32979,-6.73605 2.80259,-3.4914 14.15415,-0.33165 26.2404,-4.72825 5.23137,-1.93447 10.05977,-5.215 13.34938,-9.38737 a 4.5272563,5.9903123 48.964508 0 0 5.58183,0.0112 4.5272563,5.9903123 48.964508 0 0 3.63483,-7.186478 4.5272563,5.9903123 48.964508 0 0 -5.0204,-2.26929 c 0.26017,-1.87259 0.21778,-3.82264 -0.18155,-5.82851 -2.08133,-10.454754 -11.58886,-16.851564 -21.9947,-14.798494 -0.67543,0.13326 -1.34705,0.3013 -2.01232,0.50331 -1.32131,0.40122 -2.4881,0.96108 -3.52367,1.65338 a 4.5307973,5.6025989 16.845913 0 0 -2.8825,-3.46863 4.5307973,5.6025989 16.845913 0 0 -1.0676,-0.15845 z m 10.60512,8.974304 c 0.38068,10e-4 0.71089,0.10181 0.97449,0.29758 1.2313,0.91443 0.74671,3.65194 -1.08241,6.11436 -1.82906,2.46235 -4.30989,3.71712 -5.54104,2.80255 -1.23119,-0.91448 -0.74644,-3.65202 1.08259,-6.11436 1.24587,-1.67724 2.85684,-2.8629 4.16936,-3.06855 h 1.8e-4 c 0.1375,-0.0215 0.26994,-0.0321 0.39683,-0.0316 z m 12.26265,6.15442 c 0.38072,0.001 0.71088,0.10162 0.97449,0.2974 1.23112,0.91456 0.74644,3.65206 -1.08258,6.11436 -1.82902,2.46234 -4.30984,3.71721 -5.54104,2.80274 -1.23112,-0.91456 -0.74645,-3.65206 1.08258,-6.11437 1.24586,-1.67724 2.85702,-2.86307 4.16954,-3.06873 0.13752,-0.0215 0.27011,-0.0319 0.39701,-0.0314 z m -13.33783,8.28494 c 0.24939,0.003 0.48145,0.0425 0.69297,0.11947 1.88474,0.68563 1.74421,4.094668 -0.31382,7.614168 -2.05805,3.51949 -5.25426,5.8168 -7.13902,5.13121 -1.88474,-0.68563 -1.74422,-4.09448 0.31382,-7.61399 1.53693,-2.62835 3.78032,-4.672758 5.64914,-5.147988 0.28082,-0.0714 0.54752,-0.10567 0.79691,-0.10287 z m 4.40955,27.061498 c -0.11872,-7e-4 -0.23468,0.001 -0.34739,0.005 -1.2386,0.043 -2.41713,0.80049 -3.12612,1.9136 h 2.01701 c 0.2564,-0.24251 0.4936,-0.42457 0.68395,-0.49428 0.10436,-0.0382 0.28201,-0.0552 0.52081,-0.0541 0.83678,0.004 2.43085,0.23225 4.25002,0.54842 h 6.75175 c -3.92545,-0.7736 -8.07829,-1.90434 -10.75003,-1.91848 z" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.33699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect942-6"
width="76.028526"
height="73.388649"
x="183.4511"
y="-21.159952"
ry="3.5350549"
transform="rotate(27.418518)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.391977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect944-6"
width="69.4505"
height="56.151112"
x="186.82002"
y="-17.344629"
ry="0"
transform="rotate(27.418518)" />
<path
id="path10-3-9"
style="fill:#1976d2;fill-opacity:1;stroke-width:0.0683297"
d="m 202.32517,85.418659 a 34.92124,34.92124 0 0 0 -43.2904,13.715795 l -2.49182,4.803416 a 34.92124,34.92124 0 0 0 -2.21435,19.83912 l 49.0812,25.46141 a 34.92124,34.92124 0 0 0 13.97007,-11.7545 l 4.11493,-7.93223 A 34.92124,34.92124 0 0 0 207.12667,87.90949 Z" />
<path
id="path897-6-3"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:0.165241;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 198.82751,87.837273 a 4.5307973,5.6025989 44.264431 0 0 -6.28043,1.482039 4.5307973,5.6025989 44.264431 0 0 -0.6659,7.174546 4.5307973,5.6025989 44.264431 0 0 0.34706,0.298162 c -4.86454,3.98902 -8.91733,10.18876 -13.07755,14.90366 -8.9867,9.75921 -17.15262,0.52818 -19.00775,6.76684 -0.76908,2.58635 1.45663,6.72959 4.11849,10.46723 l 3.52111,1.82662 c -1.72575,-3.37564 -2.96872,-6.98962 -0.74155,-7.97318 4.09551,-1.80864 12.71689,6.22341 25.47003,7.88625 5.5345,0.69181 11.33116,0.003 16.17256,-2.18564 a 4.5272563,5.9903123 76.383026 0 0 4.94964,2.5803 4.5272563,5.9903123 76.383026 0 0 6.5358,-4.70541 4.5272563,5.9903123 76.383026 0 0 -3.41147,-4.3262 c 1.09325,-1.54243 1.95359,-3.29295 2.5228,-5.25738 2.96674,-10.23876 -2.52713,-20.295083 -12.70946,-23.264393 -0.66092,-0.192737 -1.33447,-0.352844 -2.01803,-0.479873 -1.35764,-0.252295 -2.65117,-0.292618 -3.88921,-0.154954 a 4.5307973,5.6025989 44.264431 0 0 -0.96143,-4.406339 4.5307973,5.6025989 44.264431 0 0 -0.87472,-0.632269 z m 5.28126,12.849707 c 0.33746,0.17619 0.58416,0.41773 0.72799,0.71289 0.67191,1.37871 -1.01884,3.58556 -3.7764,4.92908 -2.75748,1.34349 -5.53743,1.31492 -6.20913,-0.0638 -0.67178,-1.3787 1.01911,-3.58551 3.77656,-4.929 1.87826,-0.91512 3.85425,-1.22576 5.11402,-0.80391 l 1.7e-4,8e-5 c 0.13196,0.0442 0.25439,0.0958 0.3668,0.15469 z m 8.05112,11.10986 c 0.33749,0.17621 0.58422,0.41755 0.72807,0.71273 0.67168,1.37874 -1.01913,3.58554 -3.77655,4.929 -2.75744,1.3435 -5.53743,1.31502 -6.20922,-0.0637 -0.67169,-1.37874 1.01912,-3.58554 3.77655,-4.92901 1.87826,-0.91512 3.8545,-1.22583 5.11428,-0.80399 0.13197,0.0442 0.25445,0.0961 0.36687,0.15495 z m -15.65465,1.21237 c 0.21999,0.1175 0.4078,0.25943 0.56011,0.42515 1.3573,1.47651 -0.33727,4.43789 -3.7848,6.61434 -3.44753,2.17643 -7.34258,2.74386 -8.69992,1.26738 -1.3573,-1.47651 0.33717,-4.43772 3.78471,-6.61418 2.57461,-1.62536 5.50741,-2.40706 7.38513,-1.96834 0.28216,0.0659 0.53468,0.15833 0.75477,0.27565 z m -8.54725,26.05213 c -0.10506,-0.0553 -0.20878,-0.10718 -0.31067,-0.15553 -1.11927,-0.53219 -2.51422,-0.40249 -3.65614,0.2591 l 1.79043,0.92881 c 0.33927,-0.0972 0.63366,-0.14958 0.83473,-0.12381 0.11023,0.0142 0.27575,0.0809 0.48722,0.19181 0.74094,0.38887 2.05083,1.32553 3.52006,2.44389 l 5.9933,3.10909 c -3.12826,-2.49432 -6.2939,-5.41036 -8.65901,-6.65322 z" />
<text
xml:space="preserve"
id="text1098"
style="font-style:normal;font-weight:normal;font-size:22.57779999999999987px;line-height:1.35;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1100);fill:#000000;fill-opacity:1;stroke:none;"
x="52.690414"
y="0"
transform="translate(380.03788,147.12437)"><tspan
x="-284.65002"
y="47.162986"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:condensed;font-size:22.5778px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold Condensed';text-align:center;text-anchor:middle">Kein Bild </tspan></tspan><tspan
x="-292.36704"
y="78.223231"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:condensed;font-size:22.5778px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold Condensed';text-align:center;text-anchor:middle">vorhanden</tspan></tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -8,12 +8,12 @@
/* eslint-env node */
/* eslint-disable @typescript-eslint/no-var-requires */
const ESLintPlugin = require('eslint-webpack-plugin')
const ESLintPlugin = require('eslint-webpack-plugin');
const { ModifySourcePlugin } = require('modify-source-webpack-plugin');
const { configure } = require('quasar/wrappers');
module.exports = configure(function (/* ctx */) {
return {
// https://quasar.dev/quasar-cli/supporting-ts
// https://quasar.dev/quasar-cli/supporting-ts
supportTS: {
tsCheckerConfig: {
@ -21,7 +21,7 @@ module.exports = configure(function (/* ctx */) {
enabled: true,
files: './src/**/*.{ts,tsx,js,jsx,vue}',
},
}
},
},
// https://quasar.dev/quasar-cli/prefetch-feature
@ -30,7 +30,7 @@ module.exports = configure(function (/* ctx */) {
// app boot file (/src/boot)
// --> boot files are part of "main.js"
// https://quasar.dev/quasar-cli/boot-files
boot: ['axios', 'store', 'plugins', 'loading', 'login'],
boot: ['axios', 'store', 'plugins', 'login', 'init'],
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
css: ['app.scss'],
@ -39,10 +39,10 @@ module.exports = configure(function (/* ctx */) {
extras: [
// 'eva-icons',
// 'fontawesome-v5',
// 'ionicons-v4',
// 'ionicons-v5',
// 'line-awesome',
// 'material-icons',
'mdi-v5',
'mdi-v6',
// 'themify',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
@ -60,10 +60,8 @@ module.exports = configure(function (/* ctx */) {
// Applies only if "transpile" is set to true.
// transpileDependencies: [],
// rtl: false, // https://quasar.dev/options/rtl-support
// preloadChunks: true,
// showProgress: false,
// gzip: true,
// rtl: false,
// analyze: true,
// Options below are automatically set depending on the env, set them if you want to override
@ -71,34 +69,59 @@ module.exports = configure(function (/* ctx */) {
// https://quasar.dev/quasar-cli/handling-webpack
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
chainWebpack (chain) {
chain.plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{
extensions: [ 'ts', 'js', 'vue' ],
exclude: 'node_modules'
}])
},
chainWebpack(chain) {
chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [
{
extensions: ['ts', 'js', 'vue'],
exclude: ['node_modules', 'src-capacitor'],
},
]);
chain.plugin('modify-source-webpack-plugin').use(ModifySourcePlugin, [
{
rules: [
{
test: /plugins\.ts$/,
modify: (src, filename) => {
const custom_plgns = require('./plugin.config.js');
const required_plgns = require('./src/vendor-plugin.config.js');
return src.replace(
/\/\* *INSERT_PLUGIN_LIST *\*\//,
[...custom_plgns, ...required_plgns]
.map((v) => `import("${v}").catch(() => "${v}")`)
.join(',')
);
},
},
],
},
]);
chain.merge({
snapshot: {
managedPaths: [],
},
});
},
},
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
devServer: {
https: false,
port: 8080,
open: false // opens browser window automatically
open: false, // opens browser window automatically
watchFiles: { paths: ['/node_modules/@flaschengeist/**/*'] },
},
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
framework: {
iconSet: 'mdi-v5', // Quasar icon set
iconSet: 'mdi-v6', // Quasar icon set
lang: 'de', // Quasar language pack
config: {
dark: 'auto',
loadingBar: {
position: 'top',
color: 'warning',
size: '5px'
}
size: '5px',
},
},
// For special cases outside of where the auto-import stategy can have an impact
@ -109,13 +132,7 @@ module.exports = configure(function (/* ctx */) {
// directives: [],
// Quasar plugins
plugins: [
'LocalStorage',
'SessionStorage',
'Loading',
'Notify',
'LoadingBar'
]
plugins: ['LocalStorage', 'SessionStorage', 'Dialog', 'Loading', 'Notify', 'LoadingBar'],
},
// animations: 'all', // --- includes all animations
@ -124,7 +141,7 @@ module.exports = configure(function (/* ctx */) {
// https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
ssr: {
pwa: false
pwa: false,
},
// https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa
@ -143,20 +160,20 @@ module.exports = configure(function (/* ctx */) {
{
src: 'flaschengeist-logo.svg',
sizes: 'any',
type: 'image/svg+xml'
type: 'image/svg+xml',
},
{
src: 'favicon-128x128.png',
sizes: '128x128',
type: 'image/png'
type: 'image/png',
},
{
src: 'favicon-256x256.png',
sizes: '256x256',
type: 'image/png'
type: 'image/png',
},
]
}
],
},
},
// Full list of options: https://quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
@ -166,7 +183,7 @@ module.exports = configure(function (/* ctx */) {
// Full list of options: https://quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
capacitor: {
hideSplashscreen: true
hideSplashscreen: true,
},
// Full list of options: https://quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
@ -175,13 +192,11 @@ module.exports = configure(function (/* ctx */) {
packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store
// appBundleId: '',
// appCategoryType: '',
// osxSign: '',
// protocol: 'myapp://path',
// Windows only
// win32metadata: { ... }
},
@ -189,16 +204,16 @@ module.exports = configure(function (/* ctx */) {
builder: {
// https://www.electron.build/configuration/configuration
appId: 'flaschengeist-frontend'
appId: 'flaschengeist-frontend',
},
// More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
nodeIntegration: true,
extendWebpack (/* cfg */) {
extendWebpack(/* cfg */) {
// do something with Electron main process Webpack cfg
// chainWebpack also available besides this extendWebpack
}
}
}
},
},
};
});

View File

@ -1,3 +0,0 @@
{
"@quasar/qcalendar": {}
}

View File

@ -1,9 +1,10 @@
/* eslint-disable */
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import 'quasar/dist/types/feature-flag';
declare module 'quasar/dist/types/feature-flag' {
interface QuasarFeatureFlags {
store: true;
capacitor: true;
}
}

View File

@ -0,0 +1,10 @@
{
"appId": "dev.flaschengeist",
"appName": "flaschengeist-frontend",
"bundledWebRuntime": false,
"npmClient": "yarn",
"webDir": "www",
"ios": {
"allowsLinkPreview": false
}
}

View File

@ -0,0 +1,16 @@
{
"name": "flaschengeist",
"version": "2.0.0-alpha.1",
"description": "Modular student club administration system",
"author": "Tim Gröger <flaschengeist@wu5.de>",
"private": true,
"dependencies": {
"@capacitor/android": "^3.3.2",
"@capacitor/app": "^1.0.0",
"@capacitor/cli": "^3.0.0",
"@capacitor/core": "^3.0.0",
"@capacitor/ios": "^3.0.0-beta.0",
"@capacitor/splash-screen": "^1.0.0",
"@capacitor/storage": "^1.2.3"
}
}

View File

@ -1,8 +0,0 @@
.DS_Store
# Generated by package manager
node_modules/
# Generated by Cordova
/plugins/
/platforms/

View File

@ -1,76 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="de.wu5.flaschengeist" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>Flaschengeist</name>
<description>Dynamischen Managementsystem für Studentenclubs</description>
<author email="dev@cordova.apache.org" href="http://cordova.io">
Apache Cordova Team
</author>
<content src="index.html" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
<icon density="ldpi" src="res/android/ldpi.png" />
<icon density="mdpi" src="res/android/mdpi.png" />
<icon density="hdpi" src="res/android/hdpi.png" />
<icon density="xhdpi" src="res/android/xhdpi.png" />
<icon density="xxhdpi" src="res/android/xxhdpi.png" />
<icon density="xxxhdpi" src="res/android/xxxhdpi.png" />
<splash density="land-ldpi" src="res/screen/android/splash-land-ldpi.png" />
<splash density="port-ldpi" src="res/screen/android/splash-port-ldpi.png" />
<splash density="land-mdpi" src="res/screen/android/splash-land-mdpi.png" />
<splash density="port-mdpi" src="res/screen/android/splash-port-mdpi.png" />
<splash density="land-hdpi" src="res/screen/android/splash-land-hdpi.png" />
<splash density="port-hdpi" src="res/screen/android/splash-port-hdpi.png" />
<splash density="land-xhdpi" src="res/screen/android/splash-land-xhdpi.png" />
<splash density="port-xhdpi" src="res/screen/android/splash-port-xhdpi.png" />
<splash density="land-xxhdpi" src="res/screen/android/splash-land-xxhdpi.png" />
<splash density="port-xxhdpi" src="res/screen/android/splash-port-xxhdpi.png" />
<splash density="land-xxxhdpi" src="res/screen/android/splash-land-xxxhdpi.png" />
<splash density="port-xxxhdpi" src="res/screen/android/splash-port-xxxhdpi.png" />
</platform>
<platform name="ios">
<allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" />
<icon height="57" src="res/ios/icon.png" width="57" />
<icon height="114" src="res/ios/icon@2x.png" width="114" />
<icon height="40" src="res/ios/icon-20@2x.png" width="40" />
<icon height="60" src="res/ios/icon-20@3x.png" width="60" />
<icon height="29" src="res/ios/icon-29.png" width="29" />
<icon height="58" src="res/ios/icon-29@2x.png" width="58" />
<icon height="87" src="res/ios/icon-29@3x.png" width="87" />
<icon height="80" src="res/ios/icon-40@2x.png" width="80" />
<icon height="120" src="res/ios/icon-60@2x.png" width="120" />
<icon height="180" src="res/ios/icon-60@3x.png" width="180" />
<icon height="20" src="res/ios/icon-20.png" width="20" />
<icon height="40" src="res/ios/icon-40.png" width="40" />
<icon height="50" src="res/ios/icon-50.png" width="50" />
<icon height="100" src="res/ios/icon-50@2x.png" width="100" />
<icon height="72" src="res/ios/icon-72.png" width="72" />
<icon height="144" src="res/ios/icon-72@2x.png" width="144" />
<icon height="76" src="res/ios/icon-76.png" width="76" />
<icon height="152" src="res/ios/icon-76@2x.png" width="152" />
<icon height="167" src="res/ios/icon-83.5@2x.png" width="167" />
<icon height="1024" src="res/ios/icon-1024.png" width="1024" />
<icon height="48" src="res/ios/icon-24@2x.png" width="48" />
<icon height="55" src="res/ios/icon-27.5@2x.png" width="55" />
<icon height="88" src="res/ios/icon-44@2x.png" width="88" />
<icon height="172" src="res/ios/icon-86@2x.png" width="172" />
<icon height="196" src="res/ios/icon-98@2x.png" width="196" />
<splash src="res/screen/ios/Default@2x~iphone~anyany.png" />
<splash src="res/screen/ios/Default@2x~iphone~comany.png" />
<splash src="res/screen/ios/Default@2x~iphone~comcom.png" />
<splash src="res/screen/ios/Default@3x~iphone~anyany.png" />
<splash src="res/screen/ios/Default@3x~iphone~anycom.png" />
<splash src="res/screen/ios/Default@3x~iphone~comany.png" />
<splash src="res/screen/ios/Default@2x~ipad~anyany.png" />
<splash src="res/screen/ios/Default@2x~ipad~comany.png" />
</platform>
<allow-navigation href="about:*" />
<preference name="SplashMaintainAspectRatio" value="true" />
</widget>

View File

@ -1,858 +0,0 @@
{
"name": "de.wu5.flaschengeist",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@netflix/nerror": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.3.tgz",
"integrity": "sha512-b+MGNyP9/LXkapreJzNUzcvuzZslj/RGgdVVJ16P2wSlYatfLycPObImqVJSmNAdyeShvNeM/pl3sVZsObFueg==",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"extsprintf": "^1.4.0",
"lodash": "^4.17.15"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
"integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "2.0.3",
"run-parallel": "^1.1.9"
}
},
"@nodelib/fs.stat": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
"integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
"dev": true
},
"@nodelib/fs.walk": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
"integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
"dev": true,
"requires": {
"@nodelib/fs.scandir": "2.1.3",
"fastq": "^1.6.0"
}
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
},
"android-versions": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/android-versions/-/android-versions-1.6.0.tgz",
"integrity": "sha512-ojC2Ig7b/KJ6iNtR8e4bacmOsJyEkoERk3CKMIsnH7kJz5z6551NMbrVaRb7KXYavu1d74Uhml/bfcmqT3nAcg==",
"dev": true,
"requires": {
"semver": "^5.7.1"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
}
}
},
"ansi": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
"integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=",
"dev": true
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
},
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
"dev": true
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true
},
"big-integer": {
"version": "1.6.48",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==",
"dev": true
},
"bplist-creator": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz",
"integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==",
"dev": true,
"requires": {
"stream-buffers": "~2.2.0"
}
},
"bplist-parser": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
"integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
"dev": true,
"requires": {
"big-integer": "^1.6.44"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"cordova-android": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-9.0.0.tgz",
"integrity": "sha512-2ZEgApK4LPMYW0zh/mLAH3CabzCaKE0yxQTzA2wTf0Eo2HHTJnRtDCf9spGf3nPOkubyXS6+pvzz5QzNHpVTqQ==",
"dev": true,
"requires": {
"android-versions": "^1.5.0",
"cordova-common": "^4.0.1",
"execa": "^4.0.2",
"fs-extra": "^9.0.1",
"nopt": "^4.0.3",
"properties-parser": "^0.3.1",
"which": "^2.0.2"
}
},
"cordova-common": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-4.0.2.tgz",
"integrity": "sha512-od7aNShyuBajzPY83mUEO8tERwwWdFklXETHiXP5Ft87CWeo/tSuwNPFztyTy8XYc74yXdogXKPTJeUHuVzB8Q==",
"dev": true,
"requires": {
"@netflix/nerror": "^1.1.3",
"ansi": "^0.3.1",
"bplist-parser": "^0.2.0",
"cross-spawn": "^7.0.1",
"elementtree": "^0.1.7",
"endent": "^1.4.1",
"fast-glob": "^3.2.2",
"fs-extra": "^9.0.0",
"glob": "^7.1.6",
"plist": "^3.0.1",
"q": "^1.5.1",
"read-chunk": "^3.2.0",
"strip-bom": "^4.0.0",
"underscore": "^1.9.2"
}
},
"cordova-ios": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/cordova-ios/-/cordova-ios-6.1.1.tgz",
"integrity": "sha512-WHNvjVhkuwRpq95rISVXtcRyd6UGZapbmU+hO/CAn1c0AIT5WnO8mg2mOjv0WDNa0mt/V5P+N2Vig1UWwfxa5Q==",
"dev": true,
"requires": {
"cordova-common": "^4.0.2",
"fs-extra": "^9.0.0",
"ios-sim": "^8.0.2",
"nopt": "^4.0.3",
"plist": "^3.0.1",
"semver": "^7.3.2",
"unorm": "^1.6.0",
"which": "^2.0.2",
"xcode": "^3.0.1",
"xml-escape": "^1.1.0"
}
},
"cordova-plugin-splashscreen": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.0.tgz",
"integrity": "sha512-pm4ZtJKQY4bCGXVeIInbGrXilryTevYSKgfvoQJpW9UClOWKAxSsYf2/4G2u1vcn492svOSL42OSa2MhujBWEQ==",
"dev": true
},
"cordova-plugin-whitelist": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/cordova-plugin-whitelist/-/cordova-plugin-whitelist-1.3.4.tgz",
"integrity": "sha512-EYC5eQFVkoYXq39l7tYKE6lEjHJ04mvTmKXxGL7quHLdFPfJMNzru/UYpn92AOfpl3PQaZmou78C7EgmFOwFQQ==",
"dev": true
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
"dev": true
},
"elementtree": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz",
"integrity": "sha1-mskb5uUvtuYkTE5UpKw+2K6OKcA=",
"dev": true,
"requires": {
"sax": "1.1.4"
}
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
}
},
"endent": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/endent/-/endent-1.4.1.tgz",
"integrity": "sha512-buHTb5c8AC9NshtP6dgmNLYkiT+olskbq1z6cEGvfGCF3Qphbu/1zz5Xu+yjTDln8RbxNhPoUyJ5H8MSrp1olQ==",
"dev": true,
"requires": {
"dedent": "^0.7.0",
"fast-json-parse": "^1.0.3",
"objectorarray": "^1.0.4"
}
},
"execa": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
"get-stream": "^5.0.0",
"human-signals": "^1.1.1",
"is-stream": "^2.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
"signal-exit": "^3.0.2",
"strip-final-newline": "^2.0.0"
}
},
"extsprintf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz",
"integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=",
"dev": true
},
"fast-glob": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
"integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.0",
"merge2": "^1.3.0",
"micromatch": "^4.0.2",
"picomatch": "^2.2.1"
}
},
"fast-json-parse": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz",
"integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==",
"dev": true
},
"fastq": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz",
"integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==",
"dev": true,
"requires": {
"reusify": "^1.0.4"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"fs-extra": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
"dev": true,
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^1.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pump": "^3.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"human-signals": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"ios-sim": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/ios-sim/-/ios-sim-8.0.2.tgz",
"integrity": "sha512-P7nEG771bfd+JoMRjnis1gpZOkjTUUxu+4Ek1Z+eoaEEoT9byllU9pxfQ8Df7hL3gSkIQxNwTSLhos2I8tWUQA==",
"dev": true,
"requires": {
"bplist-parser": "^0.0.6",
"nopt": "1.0.9",
"plist": "^3.0.1",
"simctl": "^2"
},
"dependencies": {
"bplist-parser": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.0.6.tgz",
"integrity": "sha1-ONo0cYF9+dRKs4kuJ3B7u9daEbk=",
"dev": true
},
"nopt": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.9.tgz",
"integrity": "sha1-O8DXy6e/sNWmdtvtfA6+SKT9RU4=",
"dev": true,
"requires": {
"abbrev": "1"
}
}
}
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
},
"is-glob": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
"dev": true
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
},
"dependencies": {
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true
}
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"dev": true
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
}
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"nopt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
"dev": true,
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
},
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"requires": {
"path-key": "^3.0.0"
}
},
"objectorarray": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.4.tgz",
"integrity": "sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w==",
"dev": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
"requires": {
"mimic-fn": "^2.1.0"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true
},
"plist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
"integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==",
"dev": true,
"requires": {
"base64-js": "^1.2.3",
"xmlbuilder": "^9.0.7",
"xmldom": "0.1.x"
}
},
"properties-parser": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.3.1.tgz",
"integrity": "sha1-ExbpU5/7/ZOEXjabIRAiq9R4dxo=",
"dev": true,
"requires": {
"string.prototype.codepointat": "^0.2.0"
}
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
"dev": true
},
"read-chunk": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-3.2.0.tgz",
"integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==",
"dev": true,
"requires": {
"pify": "^4.0.1",
"with-open-file": "^0.1.6"
}
},
"reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true
},
"run-parallel": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz",
"integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==",
"dev": true
},
"sax": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
"integrity": "sha1-dLbTPJrh4AFRDxeakRaFiPGu2qk=",
"dev": true
},
"semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
"dev": true
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
"shelljs": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz",
"integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=",
"dev": true
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true
},
"simctl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/simctl/-/simctl-2.0.0.tgz",
"integrity": "sha512-5rB7rN4N3b0z0nFdy9eczVssXqrv2aAgdVRksPVqVoiDtvXmfzNvebp3EMdId2sAUzXIflarQlx4P0hjVQEzKQ==",
"dev": true,
"requires": {
"shelljs": "^0.2.6",
"tail": "^0.4.0"
}
},
"simple-plist": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz",
"integrity": "sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg==",
"dev": true,
"requires": {
"bplist-creator": "0.0.8",
"bplist-parser": "0.2.0",
"plist": "^3.0.1"
}
},
"stream-buffers": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
"integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=",
"dev": true
},
"string.prototype.codepointat": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
"integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==",
"dev": true
},
"strip-bom": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
"integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
"dev": true
},
"strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
"dev": true
},
"tail": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/tail/-/tail-0.4.0.tgz",
"integrity": "sha1-0p3nJ1DMmdseBTr/E8NZ7PtxMAI=",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"underscore": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz",
"integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==",
"dev": true
},
"universalify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
"dev": true
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==",
"dev": true
},
"uuid": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
"dev": true
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
},
"with-open-file": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.7.tgz",
"integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==",
"dev": true,
"requires": {
"p-finally": "^1.0.0",
"p-try": "^2.1.0",
"pify": "^4.0.1"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"xcode": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz",
"integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==",
"dev": true,
"requires": {
"simple-plist": "^1.1.0",
"uuid": "^7.0.3"
}
},
"xml-escape": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.1.0.tgz",
"integrity": "sha1-OQTBQ/qOs6ADDsZG0pAqLxtwbEQ=",
"dev": true
},
"xmlbuilder": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
"dev": true
},
"xmldom": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==",
"dev": true
}
}
}

View File

@ -1,31 +0,0 @@
{
"name": "de.wu5.flaschengeist",
"displayName": "Flaschengeist",
"version": "1.0.0",
"description": "A sample Apache Cordova application that responds to the deviceready event.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"ecosystem:cordova"
],
"author": "Apache Cordova Team",
"license": "Apache-2.0",
"devDependencies": {
"cordova-android": "^9.0.0",
"cordova-ios": "^6.1.1",
"cordova-plugin-splashscreen": "^6.0.0",
"cordova-plugin-whitelist": "^1.3.4"
},
"cordova": {
"plugins": {
"cordova-plugin-whitelist": {},
"cordova-plugin-splashscreen": {}
},
"platforms": [
"ios",
"android"
]
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -1,9 +1,10 @@
/* eslint-disable */
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import 'quasar/dist/types/feature-flag';
declare module 'quasar/dist/types/feature-flag' {
interface QuasarFeatureFlags {
cordova: true;
electron: true;
}
}

View File

@ -0,0 +1,56 @@
import { app, BrowserWindow, nativeTheme } from 'electron'
import path from 'path'
try {
if (process.platform === 'win32' && nativeTheme.shouldUseDarkColors === true) {
require('fs').unlinkSync(require('path').join(app.getPath('userData'), 'DevTools Extensions'))
}
} catch (_) { }
let mainWindow
function createWindow () {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
width: 1000,
height: 600,
useContentSize: true,
webPreferences: {
contextIsolation: true,
// More info: /quasar-cli/developing-electron-apps/electron-preload-script
preload: path.resolve(__dirname, process.env.QUASAR_ELECTRON_PRELOAD)
}
})
mainWindow.loadURL(process.env.APP_URL)
if (process.env.DEBUGGING) {
// if on DEV or Production with debug enabled
mainWindow.webContents.openDevTools()
} else {
// we're on production; no access to devtools pls
mainWindow.webContents.on('devtools-opened', () => {
mainWindow.webContents.closeDevTools()
})
}
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})

View File

@ -0,0 +1,17 @@
/**
* This file is used specifically for security reasons.
* Here you can access Nodejs stuff and inject functionality into
* the renderer thread (accessible there through the "window" object)
*
* WARNING!
* If you import anything from node_modules, then make sure that the package is specified
* in package.json > dependencies and NOT in devDependencies
*
* Example (injects window.myAPI.doAThing() into renderer thread):
*
* const { contextBridge } = require('electron')
*
* contextBridge.exposeInMainWorld('myAPI', {
* doAThing: () => {}
* })
*/

Binary file not shown.

BIN
src-electron/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -1,28 +1,77 @@
import config from 'src/config';
/**
* This boot file registers interceptors for axios
*/
import { useMainStore, api } from '@flaschengeist/api';
import { AxiosError } from 'axios';
import { boot } from 'quasar/wrappers';
import { LocalStorage, Notify } from 'quasar';
import axios, { AxiosError } from 'axios';
import { useMainStore } from 'src/stores';
import config from 'src/config';
import { clone } from '@flaschengeist/api';
const api = axios.create();
/**
* Minify data sent to backend server
*
* Drop unneeded entities which can be identified by ID.
*
* @param obj Object to minify
* @param cloned If this entity is already cloned (JSON En+Decoded)
* @returns Minified object (some types are converted, like a Date object is now a ISO string)
*/
function minify(entity: unknown, cloned = false) {
if (!cloned) entity = clone(entity);
if (typeof entity === 'object') {
const obj = entity as { [index: string]: unknown };
for (const prop in obj) {
if (obj.hasOwnProperty(prop) && !!obj[prop]) {
if (Array.isArray(obj[prop])) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
obj[prop] = (<Array<unknown>>obj[prop]).map((v) => minify(v, true));
} else if (
typeof obj[prop] === 'object' &&
Object.keys(<object>obj[prop]).includes('id') &&
typeof (<{ id: unknown }>obj[prop])['id'] === 'number' &&
!isNaN((<{ id: number }>obj[prop])['id'])
) {
obj[prop] = (<{ id: unknown }>obj[prop])['id'];
}
}
}
return obj;
}
return entity;
}
export default boot(({ router }) => {
api.defaults.baseURL = LocalStorage.getItem<string>('baseURL') || config.baseURL;
// Persisted value is read in plugins.ts boot file!
if (api.defaults.baseURL === undefined) api.defaults.baseURL = config.baseURL;
/***
* Intercept requests and insert Token if available
* Intercept requests
* - insert Token if available
* - minify JSON requests
*/
api.interceptors.request.use((config) => {
const store = useMainStore();
if (store.session?.token) {
config.headers = { Authorization: 'Bearer ' + store.session.token };
config.headers = Object.assign(config.headers || {}, {
Authorization: `Bearer ${store.session.token}`,
});
}
// Minify JSON requests
if (
!!config.data &&
(config.headers === undefined ||
config.headers['Content-Type'] === undefined ||
config.headers['Content-Type'] === 'application/json')
)
config.data = minify(config.data);
return config;
});
/***
* Intercept responses
* - filter 401 --> logout
* - filter 401 --> handleLoggedOut
* - filter timeout or 502-504 --> backendOffline
*/
api.interceptors.response.use(
@ -45,12 +94,11 @@ export default boot(({ router }) => {
query: { redirect: next },
});
} else if (e.response && e.response.status == 401) {
void store.logout();
if (current.name !== 'login') {
store.handleLoggedOut();
if (current.name != 'login') {
await router.push({
name: 'login',
params: { logout: 'logout' },
query: { redirect: current.path },
query: { redirect: current.fullPath },
});
}
}
@ -59,19 +107,3 @@ export default boot(({ router }) => {
}
);
});
export { api };
export const setBaseURL = (url: string) => {
LocalStorage.set('baseURL', url);
api.defaults.baseURL = url;
Notify.create({
message: 'Serveraddresse gespeichert',
position: 'bottom',
caption: `${url}`,
color: 'positive',
});
setTimeout(() => {
window.location.reload();
}, 5000);
};

87
src/boot/init.ts Normal file
View File

@ -0,0 +1,87 @@
/**
* This boot file initalizes the store from persistent storage and load all plugins
*/
import {
PersistentStorage,
api,
isAxiosError,
saveSession,
useMainStore,
} from '@flaschengeist/api';
import { Notify, Platform } from 'quasar';
import { loadPlugins } from './plugins';
import { boot } from 'quasar/wrappers';
import routes from 'src/router/routes';
async function loadBaseUrl() {
try {
const url = await PersistentStorage.get<string>('baseURL');
if (url !== null) api.defaults.baseURL = url;
} catch (e) {
console.warn('Could not load BaseURL', e);
}
}
class BackendError extends Error {}
/**
* Loading backend information
* @returns Backend object or null
*/
async function getBackend() {
const { data } = await api.get<FG.Backend>('/');
if (!data || typeof data !== 'object' || !('plugins' in data))
throw new BackendError('Invalid backend response received');
return data;
}
/**
* Boot file for loading baseURL + Session from PersistentStorage + loading and initializing all plugins
*/
export default boot(async ({ app, router }) => {
const store = useMainStore();
// FIRST(!) get the base URL
await loadBaseUrl();
// Init the store, load current session and user, if available
try {
await store.init();
} finally {
// Any changes on the session is written back to the persistent store
store.$subscribe((mutation, state) => {
saveSession(state.session);
});
}
// Load all plugins
try {
// Fetch backend data
const backend = await getBackend();
// Load enabled plugins
const flaschengeist = await loadPlugins(backend, routes);
// Add loaded routes to router
flaschengeist.routes.forEach((route) => router.addRoute(route));
// save plugins in VM-variable
app.provide('flaschengeist', flaschengeist);
} catch (error) {
// Handle errors from loading the backend information
if (error instanceof BackendError || isAxiosError(error)) {
router.isReady().finally(() => {
if (Platform.is.capacitor) void router.push({ name: 'setup_backend' });
else void router.push({ name: 'offline', params: { refresh: 1 } });
});
} else if (typeof error === 'string') {
// Handle plugin not found errors
void router.push({ name: 'error' });
Notify.create({
type: 'negative',
message: `Fehler beim Laden: Bitte wende dich an den Admin (${error})!`,
timeout: 10000,
progress: true,
});
} else {
console.error('Unknown error in init.ts:', error);
}
}
});

View File

@ -1,14 +0,0 @@
import { boot } from 'quasar/wrappers';
import { Loading } from 'quasar';
//import DarkCircularProgress from 'components/loading/DarkCircularProgress.vue';
// "async" is optional;
// more info on params: https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file
export default boot(() => {
Loading.setDefaults({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// spinner: DarkCircularProgress,
// TODO : Das funktioniert wohl erstmal nicht mehr... gibt ne exception
});
});

Some files were not shown because too many files have changed in this diff Show More