forked from verdnatura/hedera-web
refs #4922 Login, logout, home, layout style
This commit is contained in:
parent
042b8b0309
commit
0d0be4ee5f
|
@ -51,4 +51,4 @@
|
|||
}
|
||||
.new-text li {
|
||||
margin: 4px 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2060,6 +2060,7 @@
|
|||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-2.2.2.tgz",
|
||||
"integrity": "sha512-vngkvlIVV8ZJoyC5VqMvqJd2nvsx+qMN7pQjPiPjOrVndeiR7Dlue0k86Q8FsFUzyksW3HJZZi833ldxwbFzTA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@intlify/message-compiler": "^9.1.0",
|
||||
"@intlify/shared": "^9.1.0",
|
||||
|
@ -2140,6 +2141,7 @@
|
|||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/vue-i18n-loader/-/vue-i18n-loader-4.2.0.tgz",
|
||||
"integrity": "sha512-d7aBmMNWJskcZPT5rJH4h2XHe/PwNoJUaY0PGla9g+NSD4B0UR8LBKrp126nlaUfA74Xt0FEGvzCfG9KdC9KoA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@intlify/bundle-utils": "^2.2.2",
|
||||
"@intlify/shared": "^9.1.0",
|
||||
|
@ -2167,12 +2169,14 @@
|
|||
"node_modules/@intlify/vue-i18n-loader/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@intlify/vue-i18n-loader/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
|
@ -2184,6 +2188,7 @@
|
|||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
|
@ -2195,6 +2200,7 @@
|
|||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
|
@ -3693,6 +3699,7 @@
|
|||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
|
||||
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
@ -3713,6 +3720,7 @@
|
|||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
|
@ -4415,6 +4423,7 @@
|
|||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
|
@ -6084,6 +6093,7 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
|
@ -9041,6 +9051,7 @@
|
|||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-1.4.1.tgz",
|
||||
"integrity": "sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^7.4.1",
|
||||
"eslint-utils": "^2.1.0",
|
||||
|
@ -9056,6 +9067,7 @@
|
|||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
@ -9067,6 +9079,7 @@
|
|||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
},
|
||||
|
@ -9081,6 +9094,7 @@
|
|||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
|
@ -9089,6 +9103,7 @@
|
|||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
||||
"integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^7.1.1",
|
||||
"acorn-jsx": "^5.2.0",
|
||||
|
@ -9102,6 +9117,7 @@
|
|||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
|
@ -9251,7 +9267,8 @@
|
|||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
|
@ -14538,6 +14555,7 @@
|
|||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
@ -14546,6 +14564,7 @@
|
|||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-0.3.2.tgz",
|
||||
"integrity": "sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eslint-visitor-keys": "^1.3.0",
|
||||
"lodash": "^4.17.20",
|
||||
|
@ -14556,6 +14575,7 @@
|
|||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
|
@ -16055,6 +16075,7 @@
|
|||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-2.2.2.tgz",
|
||||
"integrity": "sha512-vngkvlIVV8ZJoyC5VqMvqJd2nvsx+qMN7pQjPiPjOrVndeiR7Dlue0k86Q8FsFUzyksW3HJZZi833ldxwbFzTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@intlify/message-compiler": "^9.1.0",
|
||||
"@intlify/shared": "^9.1.0",
|
||||
|
@ -16109,6 +16130,7 @@
|
|||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/vue-i18n-loader/-/vue-i18n-loader-4.2.0.tgz",
|
||||
"integrity": "sha512-d7aBmMNWJskcZPT5rJH4h2XHe/PwNoJUaY0PGla9g+NSD4B0UR8LBKrp126nlaUfA74Xt0FEGvzCfG9KdC9KoA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@intlify/bundle-utils": "^2.2.2",
|
||||
"@intlify/shared": "^9.1.0",
|
||||
|
@ -16120,12 +16142,14 @@
|
|||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
|
@ -16133,12 +16157,14 @@
|
|||
"json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"dev": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
|
@ -17350,7 +17376,8 @@
|
|||
"acorn": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
|
||||
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA=="
|
||||
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-import-assertions": {
|
||||
"version": "1.8.0",
|
||||
|
@ -17363,6 +17390,7 @@
|
|||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"acorn-walk": {
|
||||
|
@ -17882,7 +17910,8 @@
|
|||
"big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
|
@ -19114,7 +19143,8 @@
|
|||
"emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
|
@ -21303,6 +21333,7 @@
|
|||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-1.4.1.tgz",
|
||||
"integrity": "sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.4.1",
|
||||
"eslint-utils": "^2.1.0",
|
||||
|
@ -21314,12 +21345,14 @@
|
|||
"acorn": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
|
@ -21327,12 +21360,14 @@
|
|||
"eslint-visitor-keys": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"dev": true
|
||||
},
|
||||
"espree": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
||||
"integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.1.1",
|
||||
"acorn-jsx": "^5.2.0",
|
||||
|
@ -21342,7 +21377,8 @@
|
|||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -21459,7 +21495,8 @@
|
|||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
|
@ -25311,12 +25348,14 @@
|
|||
"yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true
|
||||
},
|
||||
"yaml-eslint-parser": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-0.3.2.tgz",
|
||||
"integrity": "sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.3.0",
|
||||
"lodash": "^4.17.20",
|
||||
|
@ -25326,7 +25365,8 @@
|
|||
"eslint-visitor-keys": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
"scripts": {
|
||||
"front": "webpack serve --open",
|
||||
"back": "cd ../salix && gulp backOnly",
|
||||
"db": "cd ../vn-database && myvc run",
|
||||
"db": "cd ../vn-database && myvc run -d",
|
||||
"build": "rm -rf build/ ; webpack",
|
||||
"clean": "rm -rf build/",
|
||||
"lint": "eslint --ext .js,.vue ./"
|
||||
|
|
|
@ -100,7 +100,18 @@ module.exports = configure(function (ctx) {
|
|||
type: 'http'
|
||||
},
|
||||
port: 8080,
|
||||
open: true // opens browser window automatically
|
||||
open: true, // opens browser window automatically
|
||||
|
||||
// static: __dirname,
|
||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||
// stats: { chunks: false },
|
||||
proxy: {
|
||||
'/api': 'http://localhost:3000',
|
||||
'/': {
|
||||
target: 'http://localhost/projects/hedera-web',
|
||||
bypass: (req) => req.path !== '/' ? req.path : null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-framework
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { boot } from 'quasar/wrappers'
|
||||
import { Connection } from '../js/db/connection'
|
||||
import axios from 'axios'
|
||||
|
||||
// Be careful when using SSR for cross-request state pollution
|
||||
|
@ -7,7 +8,18 @@ import axios from 'axios'
|
|||
// good idea to move this instance creation inside of the
|
||||
// "export default () => {}" function below (which runs individually
|
||||
// for each client)
|
||||
const api = axios.create({ baseURL: 'https://api.example.com' })
|
||||
const api = axios.create({
|
||||
baseURL: `//${location.hostname}:${location.port}/api/`
|
||||
})
|
||||
api.interceptors.request.use(function addToken (config) {
|
||||
const token = localStorage.getItem('vnToken')
|
||||
if (token) {
|
||||
config.headers.Authorization = token
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
const jApi = new Connection()
|
||||
|
||||
export default boot(({ app }) => {
|
||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||
|
@ -19,6 +31,8 @@ export default boot(({ app }) => {
|
|||
app.config.globalProperties.$api = api
|
||||
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
|
||||
// so you can easily perform requests against your app's API
|
||||
|
||||
app.config.globalProperties.$jApi = jApi
|
||||
})
|
||||
|
||||
export { api }
|
||||
export { api, jApi }
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
<template>
|
||||
<q-item
|
||||
clickable
|
||||
tag="a"
|
||||
target="_blank"
|
||||
:href="link"
|
||||
>
|
||||
<q-item-section
|
||||
v-if="icon"
|
||||
avatar
|
||||
>
|
||||
<q-icon :name="icon" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ title }}</q-item-label>
|
||||
<q-item-label caption>{{ caption }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EssentialLink',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
caption: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
link: {
|
||||
type: String,
|
||||
default: '#'
|
||||
},
|
||||
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
|
@ -2,9 +2,18 @@
|
|||
|
||||
@font-face {
|
||||
font-family: Poppins;
|
||||
src: url(./poppins.ttf);
|
||||
src: url(./poppins.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url(./opensans.ttf) format('truetype');
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Poppins', 'Verdana', 'Sans';
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.q-card {
|
||||
border-radius: 7px;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -14,7 +14,7 @@
|
|||
|
||||
$primary : #1A1A1A;
|
||||
$secondary : #26A69A;
|
||||
$accent : #8ed300;
|
||||
$accent : #8cc63f;
|
||||
|
||||
$dark : #1D1D1D;
|
||||
$dark-page : #121212;
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
import { JsonConnection } from '../vn/json-connection'
|
||||
import { ResultSet } from './result-set'
|
||||
|
||||
/**
|
||||
* Simulates a connection to a database by making asynchronous requests to a
|
||||
* remote REST service that returns the results in JSON format.
|
||||
* Using this class can perform any operation that can be done with a database,
|
||||
* like open/close a connection or selecion/updating queries.
|
||||
*
|
||||
* Warning! You should set a well defined dababase level privileges to use this
|
||||
* class or you could have a serious security hole in you application becasuse
|
||||
* the user can send any statement to the server. For example: DROP DATABASE
|
||||
*/
|
||||
const Flag = {
|
||||
NOT_NULL: 1,
|
||||
PRI_KEY: 2,
|
||||
AI: 512 | 2 | 1
|
||||
}
|
||||
|
||||
const Type = {
|
||||
BOOLEAN: 1,
|
||||
INTEGER: 3,
|
||||
DOUBLE: 4,
|
||||
STRING: 5,
|
||||
DATE: 8,
|
||||
DATE_TIME: 9
|
||||
}
|
||||
|
||||
export class Connection extends JsonConnection {
|
||||
static Flag = Flag
|
||||
static Type = Type
|
||||
|
||||
/**
|
||||
* Runs a SQL query on the database.
|
||||
*
|
||||
* @param {String} sql The SQL statement
|
||||
* @return {ResultSet} The result
|
||||
*/
|
||||
async execSql (sql) {
|
||||
const json = await this.send('core/query', { sql })
|
||||
const results = []
|
||||
let err
|
||||
|
||||
if (json) {
|
||||
try {
|
||||
if (json && json instanceof Array) {
|
||||
for (let i = 0; i < json.length; i++) {
|
||||
if (json[i] !== true) {
|
||||
const rows = json[i].data
|
||||
const columns = json[i].columns
|
||||
|
||||
const data = new Array(rows.length)
|
||||
results.push({
|
||||
data,
|
||||
columns,
|
||||
tables: json[i].tables
|
||||
})
|
||||
|
||||
for (let j = 0; j < rows.length; j++) {
|
||||
const row = data[j] = {}
|
||||
for (let k = 0; k < columns.length; k++) { row[columns[k].name] = rows[j][k] }
|
||||
}
|
||||
|
||||
for (let j = 0; j < columns.length; j++) {
|
||||
let castFunc = null
|
||||
const col = columns[j]
|
||||
|
||||
switch (col.type) {
|
||||
case Type.DATE:
|
||||
case Type.DATE_TIME:
|
||||
case Type.TIMESTAMP:
|
||||
castFunc = this.valueToDate
|
||||
break
|
||||
}
|
||||
|
||||
if (castFunc !== null) {
|
||||
if (col.def != null) { col.def = castFunc(col.def) }
|
||||
|
||||
for (let k = 0; k < data.length; k++) {
|
||||
if (data[k][col.name] != null) { data[k][col.name] = castFunc(data[k][col.name]) }
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { results.push(json[i]) }
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
|
||||
return new ResultSet(results, err)
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a query on the database.
|
||||
*
|
||||
* @param {String} query The SQL statement
|
||||
* @param {Object} params The query params
|
||||
* @return {ResultSet} The result
|
||||
*/
|
||||
async execQuery (query, params) {
|
||||
const sql = query.replace(/#\w+/g, function (key) {
|
||||
const value = params[key.substring(1)]
|
||||
return value ? this.renderValue(params) : key
|
||||
})
|
||||
|
||||
return await this.execSql(sql)
|
||||
}
|
||||
|
||||
async query (query, params) {
|
||||
const res = await this.execQuery(query, params)
|
||||
return res.fetchData()
|
||||
}
|
||||
|
||||
async getObject (query, params) {
|
||||
const res = await this.execQuery(query, params)
|
||||
return res.fetchObject()
|
||||
}
|
||||
|
||||
async getValue (query, params) {
|
||||
const res = await this.execQuery(query, params)
|
||||
return res.fetchValue()
|
||||
}
|
||||
|
||||
renderValue (v) {
|
||||
switch (typeof v) {
|
||||
case 'number':
|
||||
return v
|
||||
case 'boolean':
|
||||
return (v) ? 'TRUE' : 'FALSE'
|
||||
case 'string':
|
||||
return "'" + v.replace(this.regexp, this.replaceFunc) + "'"
|
||||
default:
|
||||
if (v instanceof Date) {
|
||||
if (!isNaN(v.getTime())) {
|
||||
const unixTime = parseInt(fixTz(v).getTime() / 1000)
|
||||
return 'DATE(FROM_UNIXTIME(' + unixTime + '))'
|
||||
} else { return '0000-00-00' }
|
||||
} else { return 'NULL' }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a value to date.
|
||||
*/
|
||||
valueToDate (value) {
|
||||
return fixTz(new Date(value))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Read time zone from db configuration
|
||||
const tz = { timeZone: 'Europe/Madrid' }
|
||||
const isLocal = Intl
|
||||
.DateTimeFormat()
|
||||
.resolvedOptions()
|
||||
.timeZone === tz.timeZone
|
||||
|
||||
function fixTz (date) {
|
||||
if (isLocal) return date
|
||||
|
||||
const localDate = new Date(date.toLocaleString('en-US', tz))
|
||||
const hasTime = localDate.getHours() ||
|
||||
localDate.getMinutes() ||
|
||||
localDate.getSeconds() ||
|
||||
localDate.getMilliseconds()
|
||||
|
||||
if (!hasTime) {
|
||||
date.setHours(date.getHours() + 12)
|
||||
date.setHours(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
return date
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
|
||||
import { Result } from './result'
|
||||
|
||||
/**
|
||||
* This class stores the database results.
|
||||
*/
|
||||
export class ResultSet {
|
||||
results = null
|
||||
error = null
|
||||
|
||||
/**
|
||||
* Initilizes the resultset object.
|
||||
*/
|
||||
constructor (results, error) {
|
||||
this.results = results
|
||||
this.error = error
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the query error.
|
||||
*
|
||||
* @return {Db.Err} the error or null if no errors hapened
|
||||
*/
|
||||
getError () {
|
||||
return this.error
|
||||
}
|
||||
|
||||
fetch () {
|
||||
if (this.error) { throw this.error }
|
||||
|
||||
if (this.results !== null &&
|
||||
this.results.length > 0) { return this.results.shift() }
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetchs the next result from the resultset.
|
||||
*
|
||||
* @return {Db.Result} the result or %null if error or there are no more results
|
||||
*/
|
||||
fetchResult () {
|
||||
const result = this.fetch()
|
||||
|
||||
if (result !== null) {
|
||||
if (result.data instanceof Array) { return new Result(result) } else { return true }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetchs the first row object from the next resultset.
|
||||
*
|
||||
* @return {Array} the row if success, %null otherwise
|
||||
*/
|
||||
fetchObject () {
|
||||
const result = this.fetch()
|
||||
|
||||
if (result !== null &&
|
||||
result.data instanceof Array &&
|
||||
result.data.length > 0) { return result.data[0] }
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetchs data from the next resultset.
|
||||
*
|
||||
* @return {Array} the data
|
||||
*/
|
||||
fetchData () {
|
||||
const result = this.fetch()
|
||||
|
||||
if (result !== null &&
|
||||
result.data instanceof Array) { return result.data }
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetchs the first row and column value from the next resultset.
|
||||
*
|
||||
* @return {Object} the value if success, %null otherwise
|
||||
*/
|
||||
fetchValue () {
|
||||
const row = this.fetchRow()
|
||||
|
||||
if (row instanceof Array && row.length > 0) { return row[0] }
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetchs the first row from the next resultset.
|
||||
*
|
||||
* @return {Array} the row if success, %null otherwise
|
||||
*/
|
||||
fetchRow () {
|
||||
const result = this.fetch()
|
||||
|
||||
if (result !== null &&
|
||||
result.data instanceof Array &&
|
||||
result.data.length > 0) {
|
||||
const object = result.data[0]
|
||||
const row = new Array(result.columns.length)
|
||||
for (let i = 0; i < row.length; i++) { row[i] = object[result.columns[i].name] }
|
||||
return row
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* This class stores a database result.
|
||||
*/
|
||||
export class Result {
|
||||
/**
|
||||
* Initilizes the result object.
|
||||
*/
|
||||
constructor (result) {
|
||||
this.data = result.data
|
||||
this.tables = result.tables
|
||||
this.columns = result.columns
|
||||
this.row = -1
|
||||
|
||||
if (this.columns) {
|
||||
this.columnMap = {}
|
||||
|
||||
for (let i = 0; i < this.columns.length; i++) {
|
||||
const col = this.columns[i]
|
||||
col.index = i
|
||||
this.columnMap[col.name] = col
|
||||
}
|
||||
} else { this.columnMap = null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value from de result.
|
||||
*
|
||||
* @param {String} columnName The column name
|
||||
* @return {Object} The cell value
|
||||
*/
|
||||
get (columnName) {
|
||||
return this.data[this.row][columnName]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a row.
|
||||
*
|
||||
* @return {Object} The cell value
|
||||
*/
|
||||
getObject () {
|
||||
return this.data[this.row]
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the result iterator.
|
||||
*/
|
||||
reset () {
|
||||
this.row = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the internal iterator to the next row.
|
||||
*/
|
||||
next () {
|
||||
this.row++
|
||||
|
||||
if (this.row >= this.data.length) { return false }
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
|
||||
import { VnObject } from './object'
|
||||
import { JsonException } from './json-exception'
|
||||
|
||||
/**
|
||||
* Handler for JSON rest connections.
|
||||
*/
|
||||
export class JsonConnection extends VnObject {
|
||||
_connected = false
|
||||
_requestsCount = 0
|
||||
token = null
|
||||
|
||||
/**
|
||||
* Executes the specified REST service with the given params and calls
|
||||
* the callback when response is received.
|
||||
*
|
||||
* @param {String} url The service path
|
||||
* @param {Object} params The params to pass to the service
|
||||
* @return {Object} The parsed JSON response
|
||||
*/
|
||||
async send (url, params) {
|
||||
if (!params) params = {}
|
||||
params.srv = `json:${url}`
|
||||
return this.sendWithUrl('POST', '.', params)
|
||||
}
|
||||
|
||||
async sendForm (form) {
|
||||
const params = {}
|
||||
const elements = form.elements
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
if (elements[i].name) { params[elements[i].name] = elements[i].value }
|
||||
}
|
||||
|
||||
return this.sendWithUrl('POST', form.action, params)
|
||||
}
|
||||
|
||||
async sendFormMultipart (form) {
|
||||
return this.request({
|
||||
method: 'POST',
|
||||
url: form.action,
|
||||
data: new FormData(form)
|
||||
})
|
||||
}
|
||||
|
||||
async sendFormData (formData) {
|
||||
return this.request({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
data: formData
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when REST response is received.
|
||||
*/
|
||||
async sendWithUrl (method, url, params) {
|
||||
const urlParams = new URLSearchParams(params)
|
||||
return this.request({
|
||||
method,
|
||||
url,
|
||||
data: urlParams.toString(),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async request (config) {
|
||||
const request = new XMLHttpRequest()
|
||||
request.open(config.method, config.url, true)
|
||||
|
||||
const token = localStorage.getItem('vnToken')
|
||||
if (token) { request.setRequestHeader('Authorization', token) }
|
||||
|
||||
const headers = config.headers
|
||||
if (headers) {
|
||||
for (const header in headers) { request.setRequestHeader(header, headers[header]) }
|
||||
}
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
request.onreadystatechange =
|
||||
() => this._onStateChange(request, resolve, reject)
|
||||
})
|
||||
|
||||
request.send(config.data)
|
||||
|
||||
this._requestsCount++
|
||||
|
||||
if (this._requestsCount === 1) { this.emit('loading-changed', true) }
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
_onStateChange (request, resolve, reject) {
|
||||
if (request.readyState !== 4) { return }
|
||||
|
||||
this._requestsCount--
|
||||
|
||||
if (this._requestsCount === 0) { this.emit('loading-changed', false) }
|
||||
|
||||
let data = null
|
||||
let error = null
|
||||
try {
|
||||
if (request.status === 0) {
|
||||
const err = new JsonException()
|
||||
err.message = 'The server does not respond, please check your Internet connection'
|
||||
err.statusCode = request.status
|
||||
throw err
|
||||
}
|
||||
|
||||
let contentType = null
|
||||
|
||||
try {
|
||||
contentType = request
|
||||
.getResponseHeader('Content-Type')
|
||||
.split(';')[0]
|
||||
.trim()
|
||||
} catch (err) {
|
||||
console.warn(err)
|
||||
}
|
||||
|
||||
if (contentType !== 'application/json') {
|
||||
const err = new JsonException()
|
||||
err.message = request.statusText
|
||||
err.statusCode = request.status
|
||||
throw err
|
||||
}
|
||||
|
||||
let json
|
||||
let jsData
|
||||
|
||||
if (request.responseText) { json = JSON.parse(request.responseText) }
|
||||
if (json) { jsData = json.data || json }
|
||||
|
||||
if (request.status >= 200 && request.status < 300) {
|
||||
data = jsData
|
||||
} else {
|
||||
let exception = jsData.exception
|
||||
const error = jsData.error
|
||||
const err = new JsonException()
|
||||
|
||||
if (exception) {
|
||||
exception = exception
|
||||
.replace(/\\/g, '.')
|
||||
.replace(/Exception$/, '')
|
||||
.replace(/^Vn\.Web\./, '')
|
||||
|
||||
err.exception = exception
|
||||
err.message = jsData.message
|
||||
err.code = jsData.code
|
||||
err.file = jsData.file
|
||||
err.line = jsData.line
|
||||
err.trace = jsData.trace
|
||||
err.statusCode = request.status
|
||||
} else if (error) {
|
||||
err.message = error.message
|
||||
err.code = error.code
|
||||
err.statusCode = request.status
|
||||
} else {
|
||||
err.message = request.statusText
|
||||
err.statusCode = request.status
|
||||
}
|
||||
|
||||
throw err
|
||||
}
|
||||
} catch (e) {
|
||||
data = null
|
||||
error = e
|
||||
}
|
||||
|
||||
if (error) {
|
||||
if (error.exception === 'SessionExpired') { this.clearToken() }
|
||||
|
||||
this.emit('error', error)
|
||||
reject(error)
|
||||
} else { resolve(data) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* This class stores the database errors.
|
||||
*/
|
||||
export class JsonException {
|
||||
constructor (exception, message, code, file, line, trace, statucCode) {
|
||||
this.name = 'JsonException'
|
||||
this.exception = exception
|
||||
this.message = message
|
||||
this.code = code
|
||||
this.file = file
|
||||
this.line = line
|
||||
this.trace = trace
|
||||
this.statusCode = statucCode
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
/**
|
||||
* The main base class. Manages the signal system. Objects based on this class
|
||||
* can be instantiated declaratively using XML.
|
||||
*/
|
||||
export class VnObject {
|
||||
/**
|
||||
* Tag to be used when the class instance is defined via XML. All classes
|
||||
* must define this attribute, even if it is not used.
|
||||
*/
|
||||
static Tag = 'vn-object'
|
||||
|
||||
/**
|
||||
* Class public properties.
|
||||
*/
|
||||
static Properties = {}
|
||||
|
||||
/*
|
||||
* Reference count.
|
||||
*/
|
||||
_refCount = 1
|
||||
|
||||
/*
|
||||
* Signal handlers data.
|
||||
*/
|
||||
_thisArg = null
|
||||
|
||||
/**
|
||||
* Initializes the object and sets all properties passed to the class
|
||||
* constructor.
|
||||
*
|
||||
* @param {Object} props The properties passed to the contructor
|
||||
*/
|
||||
constructor (props) {
|
||||
this.setProperties(props)
|
||||
}
|
||||
|
||||
initialize (props) {
|
||||
this.setProperties(props)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a group of object properties.
|
||||
*
|
||||
* @param {Object} props Properties
|
||||
*/
|
||||
setProperties (props) {
|
||||
for (const prop in props) { this[prop] = props[prop] }
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the object reference count.
|
||||
*/
|
||||
ref () {
|
||||
this._refCount++
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the object reference count.
|
||||
*/
|
||||
unref () {
|
||||
this._refCount--
|
||||
|
||||
if (this._refCount === 0) { this._destroy() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from @Vn.Builder when it finds a custom tag as a child of the
|
||||
* element.
|
||||
*
|
||||
* @param {Vn.Scope} scope The scope instance
|
||||
* @param {Node} node The custom tag child nodes
|
||||
*/
|
||||
loadXml () {}
|
||||
|
||||
/**
|
||||
* Called from @Vn.Builder when it finds a a child tag that isn't
|
||||
* associated to any property.
|
||||
*
|
||||
* @param {Object} child The child object instance
|
||||
*/
|
||||
appendChild () {}
|
||||
|
||||
/**
|
||||
* Conects a signal with a function.
|
||||
*
|
||||
* @param {string} id The signal identifier
|
||||
* @param {function} callback The callback
|
||||
* @param {Object} instance The instance
|
||||
*/
|
||||
on (id, callback, instance) {
|
||||
if (!(callback instanceof Function)) {
|
||||
console.warn('Vn.Object: Invalid callback for signal \'%s\'', id)
|
||||
return
|
||||
}
|
||||
|
||||
this._signalInit()
|
||||
let callbacks = this._thisArg.signals[id]
|
||||
|
||||
if (!callbacks) { callbacks = this._thisArg.signals[id] = [] }
|
||||
|
||||
callbacks.push({
|
||||
blocked: false,
|
||||
callback,
|
||||
instance
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks/Unlocks a signal emission to the specified object.
|
||||
*
|
||||
* @param {string} id The signal identifier
|
||||
* @param {function} callback The callback
|
||||
* @param {boolean} block %true for lock the signal, %false for unlock
|
||||
*/
|
||||
blockSignal (id, callback, block, instance) {
|
||||
if (!this._thisArg) { return }
|
||||
|
||||
const callbacks = this._thisArg.signals[id]
|
||||
|
||||
if (!callbacks) { return }
|
||||
|
||||
for (let i = 0; i < callbacks.length; i++) {
|
||||
if (callbacks[i].callback === callback &&
|
||||
callbacks[i].instance === instance) { callbacks[i].blocked = block }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a signal in the object.
|
||||
*
|
||||
* @param {string} id The signal identifier
|
||||
*/
|
||||
emit (id) {
|
||||
if (!this._thisArg) { return }
|
||||
|
||||
const callbacks = this._thisArg.signals[id]
|
||||
|
||||
if (!callbacks) { return }
|
||||
|
||||
const callbackArgs = []
|
||||
callbackArgs.push(this)
|
||||
|
||||
for (let i = 1; i < arguments.length; i++) { callbackArgs.push(arguments[i]) }
|
||||
|
||||
for (let i = 0; i < callbacks.length; i++) {
|
||||
if (!callbacks[i].blocked) { callbacks[i].callback.apply(callbacks[i].instance, callbackArgs) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects a signal from current object.
|
||||
*
|
||||
* @param {string} id The signal identifier
|
||||
* @param {function} callback The connected callback
|
||||
* @param {Object} instance The instance
|
||||
*/
|
||||
disconnect (id, callback, instance) {
|
||||
if (!this._thisArg) { return }
|
||||
|
||||
const callbacks = this._thisArg.signals[id]
|
||||
|
||||
if (callbacks) {
|
||||
for (let i = callbacks.length; i--;) {
|
||||
if (callbacks[i].callback === callback &&
|
||||
callbacks[i].instance === instance) { callbacks.splice(i, 1) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects all signals for the given instance.
|
||||
*
|
||||
* @param {Object} instance The instance
|
||||
*/
|
||||
disconnectByInstance (instance) {
|
||||
if (!this._thisArg) { return }
|
||||
|
||||
const signals = this._thisArg.signals
|
||||
|
||||
for (const signalId in signals) {
|
||||
const callbacks = signals[signalId]
|
||||
|
||||
if (callbacks) {
|
||||
for (let i = callbacks.length; i--;) {
|
||||
if (callbacks[i].instance === instance) { callbacks.splice(i, 1) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the object, this method should only be called before losing
|
||||
* the last reference to the object. It can be overwritten by child classes
|
||||
* but should always call the parent method.
|
||||
*/
|
||||
_destroy () {
|
||||
if (!this._thisArg) { return }
|
||||
|
||||
const links = this._thisArg.links
|
||||
|
||||
for (const key in links) { this._unlink(links[key]) }
|
||||
|
||||
this._thisArg = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the object with another object.
|
||||
*
|
||||
* @param {Object} prop The linked property
|
||||
* @param {Object} handlers The object events to listen with
|
||||
*/
|
||||
link (prop, handlers) {
|
||||
this._signalInit()
|
||||
const links = this._thisArg.links
|
||||
|
||||
for (const key in prop) {
|
||||
const newObject = prop[key]
|
||||
const oldObject = this[key]
|
||||
|
||||
if (oldObject) { this._unlink(oldObject) }
|
||||
|
||||
this[key] = newObject
|
||||
|
||||
if (newObject) {
|
||||
links[key] = newObject.ref()
|
||||
|
||||
for (const signal in handlers) { newObject.on(signal, handlers[signal], this) }
|
||||
} else if (oldObject) { links[key] = undefined }
|
||||
}
|
||||
}
|
||||
|
||||
_unlink (object) {
|
||||
if (!object) return
|
||||
object.disconnectByInstance(this)
|
||||
object.unref()
|
||||
}
|
||||
|
||||
_signalInit () {
|
||||
if (!this._thisArg) {
|
||||
this._thisArg = {
|
||||
signals: {},
|
||||
links: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<q-layout view="lHh Lpr lFf">
|
||||
<q-header elevated>
|
||||
<q-header reveal>
|
||||
<q-toolbar>
|
||||
<q-btn
|
||||
flat
|
||||
|
@ -12,30 +12,55 @@
|
|||
/>
|
||||
|
||||
<q-toolbar-title>
|
||||
Quasar App
|
||||
Home
|
||||
</q-toolbar-title>
|
||||
|
||||
<div>Quasar v{{ $q.version }}</div>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
|
||||
<q-drawer
|
||||
v-model="leftDrawerOpen"
|
||||
:width="250"
|
||||
show-if-above
|
||||
bordered
|
||||
>
|
||||
<q-list>
|
||||
<q-item-label
|
||||
header
|
||||
>
|
||||
Essential Links
|
||||
</q-item-label>
|
||||
|
||||
<EssentialLink
|
||||
v-for="link in essentialLinks"
|
||||
:key="link.title"
|
||||
v-bind="link"
|
||||
/>
|
||||
<q-toolbar class="logo">
|
||||
<img src="statics/logo-dark.svg">
|
||||
</q-toolbar>
|
||||
<div class="user-info">
|
||||
<div>
|
||||
<span id="user-name">{{user.nickname}}</span>
|
||||
<q-btn flat icon="logout" alt="_Exit" @click="logout()"/>
|
||||
</div>
|
||||
<div id="supplant" class="supplant">
|
||||
<span id="supplanted">{{supplantedUser}}</span>
|
||||
<q-btn flat icon="logout" alt="_Exit"/>
|
||||
</div>
|
||||
</div>
|
||||
<q-list
|
||||
v-for="item in essentialLinks"
|
||||
:key="item.id">
|
||||
<q-item
|
||||
v-if="!item.childs"
|
||||
:to="`/${item.path}`">
|
||||
<q-item-section>
|
||||
<q-item-label>{{item.description}}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-expansion-item
|
||||
v-if="item.childs"
|
||||
:label="item.description"
|
||||
expand-separator>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="subitem in item.childs"
|
||||
:key="subitem.id"
|
||||
:to="`/${subitem.path}`"
|
||||
class="q-pl-lg">
|
||||
<q-item-section>
|
||||
<q-item-label>{{subitem.description}}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-expansion-item>
|
||||
</q-list>
|
||||
</q-drawer>
|
||||
|
||||
|
@ -45,72 +70,125 @@
|
|||
</q-layout>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.q-toolbar {
|
||||
min-height: 64px;
|
||||
}
|
||||
.logo {
|
||||
background-color: $primary;
|
||||
justify-content: center;
|
||||
|
||||
& > img {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
.user-info {
|
||||
margin: 25px;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
border: 1px solid #eaeaea;
|
||||
|
||||
& > span {
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
}
|
||||
.q-btn {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 9px;
|
||||
border-radius: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: #1a1a1a;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.supplant {
|
||||
display: none;
|
||||
border-top: none;
|
||||
|
||||
&.show {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.q-drawer {
|
||||
.q-item {
|
||||
padding-left: 38px;
|
||||
}
|
||||
.q-list .q-list .q-item{
|
||||
padding-left: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import EssentialLink from 'components/EssentialLink.vue'
|
||||
|
||||
const linksList = [
|
||||
{
|
||||
title: 'Docs',
|
||||
caption: 'quasar.dev',
|
||||
icon: 'school',
|
||||
link: 'https://quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Github',
|
||||
caption: 'github.com/quasarframework',
|
||||
icon: 'code',
|
||||
link: 'https://github.com/quasarframework'
|
||||
},
|
||||
{
|
||||
title: 'Discord Chat Channel',
|
||||
caption: 'chat.quasar.dev',
|
||||
icon: 'chat',
|
||||
link: 'https://chat.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Forum',
|
||||
caption: 'forum.quasar.dev',
|
||||
icon: 'record_voice_over',
|
||||
link: 'https://forum.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Twitter',
|
||||
caption: '@quasarframework',
|
||||
icon: 'rss_feed',
|
||||
link: 'https://twitter.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Facebook',
|
||||
caption: '@QuasarFramework',
|
||||
icon: 'public',
|
||||
link: 'https://facebook.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Quasar Awesome',
|
||||
caption: 'Community Quasar projects',
|
||||
icon: 'favorite',
|
||||
link: 'https://awesome.quasar.dev'
|
||||
}
|
||||
]
|
||||
import { userStore } from 'stores/user'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MainLayout',
|
||||
|
||||
components: {
|
||||
EssentialLink
|
||||
},
|
||||
props: {},
|
||||
|
||||
setup () {
|
||||
const leftDrawerOpen = ref(false)
|
||||
|
||||
return {
|
||||
essentialLinks: linksList,
|
||||
user: userStore(),
|
||||
supplantedUser: ref(''),
|
||||
essentialLinks: ref(null),
|
||||
leftDrawerOpen,
|
||||
toggleLeftDrawer () {
|
||||
leftDrawerOpen.value = !leftDrawerOpen.value
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
await this.fetchData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchData () {
|
||||
const sections = await this.$jApi.query('SELECT * FROM myMenu')
|
||||
|
||||
const sectionMap = new Map()
|
||||
for (const section of sections) {
|
||||
sectionMap.set(section.id, section)
|
||||
}
|
||||
|
||||
const sectionTree = []
|
||||
for (const section of sections) {
|
||||
const parent = section.parentFk
|
||||
if (parent) {
|
||||
const parentSection = sectionMap.get(parent)
|
||||
if (!parentSection) continue
|
||||
let childs = parentSection.childs
|
||||
if (!childs) { childs = parentSection.childs = [] }
|
||||
childs.push(section)
|
||||
} else {
|
||||
sectionTree.push(section)
|
||||
}
|
||||
}
|
||||
|
||||
this.essentialLinks = sectionTree
|
||||
},
|
||||
|
||||
async logout () {
|
||||
this.user.logout()
|
||||
this.$router.push('/login')
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="q-pa-sm row items-start">
|
||||
<div
|
||||
class="new-card q-pa-sm"
|
||||
v-for="myNew in news"
|
||||
:key="myNew.id">
|
||||
<q-card>
|
||||
<q-img :src="`https://verdnatura.es/vn-image-data/news/full/${myNew.image}`">
|
||||
</q-img>
|
||||
<q-card-section>
|
||||
<div class="text-h5">{{ myNew.title }}</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="new-body">
|
||||
<div v-html="myNew.text"/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
||||
<q-btn
|
||||
fab
|
||||
icon="add_shopping_cart"
|
||||
color="accent"
|
||||
:to="{name: 'catalog'}"
|
||||
:title="$t('startOrder')"
|
||||
/>
|
||||
</q-page-sticky>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.new-card {
|
||||
width: 100%;
|
||||
|
||||
@media screen and (min-width: 1000px) and (max-width: 1399px) {
|
||||
width: 50%;
|
||||
}
|
||||
@media screen and (min-width: 1400px) and (max-width: 1699px) {
|
||||
width: 33.33%;
|
||||
}
|
||||
@media screen and (min-width: 1700px) {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
.new-body {
|
||||
font-family: 'Open Sans';
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #6a1;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PageIndex',
|
||||
data () {
|
||||
return {
|
||||
news: []
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
this.news = await this.$jApi.query(
|
||||
`SELECT title, text, image, id
|
||||
FROM news
|
||||
ORDER BY priority, created DESC`
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
en-US:
|
||||
startOrder: Start order
|
||||
es-ES:
|
||||
startOrder: Empezar pedido
|
||||
</i18n>
|
|
@ -129,16 +129,21 @@ a {
|
|||
</style>
|
||||
|
||||
<script>
|
||||
import { userStore } from 'stores/user'
|
||||
|
||||
export default {
|
||||
name: 'VnLogin',
|
||||
|
||||
data () {
|
||||
return {
|
||||
user: userStore(),
|
||||
email: '',
|
||||
password: '',
|
||||
remember: false,
|
||||
showPwd: true
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if (this.$route.query.emailConfirmed !== undefined) {
|
||||
this.$q.notify({
|
||||
|
@ -151,27 +156,11 @@ export default {
|
|||
this.$refs.password.focus()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async onLogin () {
|
||||
const params = {
|
||||
password: this.password
|
||||
}
|
||||
|
||||
if (this.email.indexOf('@') !== -1) {
|
||||
params.email = this.email
|
||||
} else {
|
||||
params.username = this.email
|
||||
}
|
||||
|
||||
const res = await this.$axios.post('users/login', params)
|
||||
localStorage.setItem('token', res.data.id)
|
||||
Object.assign(this.$state.user, {
|
||||
loggedIn: true,
|
||||
token: res.data.id,
|
||||
id: res.data.userId,
|
||||
name: this.email
|
||||
})
|
||||
this.$router.push('/home')
|
||||
await this.user.login(this.email, this.password)
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,15 @@ const routes = [
|
|||
path: '/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [
|
||||
{ path: '', component: () => import('pages/IndexPage.vue') }
|
||||
{
|
||||
name: '',
|
||||
path: '',
|
||||
component: () => import('pages/Home.vue')
|
||||
}, {
|
||||
name: 'home',
|
||||
path: '/cms/home',
|
||||
component: () => import('pages/Home.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { api, jApi } from 'boot/axios'
|
||||
|
||||
export const userStore = defineStore('user', {
|
||||
state: () => ({
|
||||
token: null,
|
||||
id: null,
|
||||
name: null,
|
||||
nickname: null
|
||||
}),
|
||||
|
||||
getters: {
|
||||
loggedIn: state => state.token != null
|
||||
},
|
||||
|
||||
actions: {
|
||||
async login (user, password) {
|
||||
const params = { user, password }
|
||||
const res = await api.post('Accounts/login', params)
|
||||
localStorage.setItem('vnToken', res.data.token)
|
||||
|
||||
const userData = await jApi.getObject(
|
||||
'SELECT id, nickname FROM account.myUser'
|
||||
)
|
||||
|
||||
this.$patch({
|
||||
token: res.data.token,
|
||||
name: user,
|
||||
id: userData.id,
|
||||
nickname: userData.nickname
|
||||
})
|
||||
},
|
||||
|
||||
async logout () {
|
||||
if (localStorage.getItem('vnToken') != null) {
|
||||
await api.post('Accounts/logout')
|
||||
}
|
||||
localStorage.removeItem('vnToken')
|
||||
this.$reset()
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue