diff --git a/forms/cms/home/style.scss b/forms/cms/home/style.scss
index 15ecc290..b6d83b5f 100644
--- a/forms/cms/home/style.scss
+++ b/forms/cms/home/style.scss
@@ -51,4 +51,4 @@
}
.new-text li {
margin: 4px 0;
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index 7fa9184d..0ed1988c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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
}
}
},
diff --git a/package.json b/package.json
index e04ed1f6..9ebf5068 100644
--- a/package.json
+++ b/package.json
@@ -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 ./"
diff --git a/quasar.config.js b/quasar.config.js
index ffa78481..d0fd8d6b 100644
--- a/quasar.config.js
+++ b/quasar.config.js
@@ -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
diff --git a/src/boot/axios.js b/src/boot/axios.js
index 9dbc9420..079f1bed 100644
--- a/src/boot/axios.js
+++ b/src/boot/axios.js
@@ -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 }
diff --git a/src/components/EssentialLink.vue b/src/components/EssentialLink.vue
deleted file mode 100644
index 585f98ce..00000000
--- a/src/components/EssentialLink.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
- {{ title }}
- {{ caption }}
-
-
-
-
-
diff --git a/src/css/app.scss b/src/css/app.scss
index 7d42ef23..e0d7afb3 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -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);
}
diff --git a/src/css/opensans.ttf b/src/css/opensans.ttf
new file mode 100644
index 00000000..e21ff5f1
Binary files /dev/null and b/src/css/opensans.ttf differ
diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss
index 6df04006..aa576173 100644
--- a/src/css/quasar.variables.scss
+++ b/src/css/quasar.variables.scss
@@ -14,7 +14,7 @@
$primary : #1A1A1A;
$secondary : #26A69A;
-$accent : #8ed300;
+$accent : #8cc63f;
$dark : #1D1D1D;
$dark-page : #121212;
diff --git a/src/js/db/connection.js b/src/js/db/connection.js
new file mode 100644
index 00000000..f8c87bf3
--- /dev/null
+++ b/src/js/db/connection.js
@@ -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
+}
diff --git a/src/js/db/result-set.js b/src/js/db/result-set.js
new file mode 100644
index 00000000..ad9d4a42
--- /dev/null
+++ b/src/js/db/result-set.js
@@ -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
+ }
+}
diff --git a/src/js/db/result.js b/src/js/db/result.js
new file mode 100644
index 00000000..47f47d23
--- /dev/null
+++ b/src/js/db/result.js
@@ -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
+ }
+}
diff --git a/src/js/vn/json-connection.js b/src/js/vn/json-connection.js
new file mode 100644
index 00000000..de9cd0f6
--- /dev/null
+++ b/src/js/vn/json-connection.js
@@ -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) }
+ }
+}
diff --git a/src/js/vn/json-exception.js b/src/js/vn/json-exception.js
new file mode 100644
index 00000000..823c4f1c
--- /dev/null
+++ b/src/js/vn/json-exception.js
@@ -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
+ }
+}
diff --git a/src/js/vn/object.js b/src/js/vn/object.js
new file mode 100644
index 00000000..7180e889
--- /dev/null
+++ b/src/js/vn/object.js
@@ -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: {}
+ }
+ }
+ }
+}
diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue
index 102b79f4..d8fa8510 100644
--- a/src/layouts/MainLayout.vue
+++ b/src/layouts/MainLayout.vue
@@ -1,6 +1,6 @@
-
+
- Quasar App
+ Home
-
- Quasar v{{ $q.version }}
-
-
- Essential Links
-
-
-
+
+
+
+
+
+ {{user.nickname}}
+
+
+
+ {{supplantedUser}}
+
+
+
+
+
+
+ {{item.description}}
+
+
+
+
+
+
+ {{subitem.description}}
+
+
+
+
@@ -45,72 +70,125 @@
+
+
+
+
diff --git a/src/pages/Home.vue b/src/pages/Home.vue
new file mode 100644
index 00000000..92f12284
--- /dev/null
+++ b/src/pages/Home.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+ {{ myNew.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ en-US:
+ startOrder: Start order
+ es-ES:
+ startOrder: Empezar pedido
+
diff --git a/src/pages/Login/Login.vue b/src/pages/Login/Login.vue
index eeb1e226..5024550c 100644
--- a/src/pages/Login/Login.vue
+++ b/src/pages/Login/Login.vue
@@ -129,16 +129,21 @@ a {