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 @@ - - - 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 @@ + + + + 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 @@ + + + + + + + + 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 {