forked from verdnatura/salix-front
Quasar project
This commit is contained in:
parent
28dcf69c42
commit
efb857c08e
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"plugins": ["@babel/plugin-syntax-dynamic-import"],
|
||||||
|
"env": {
|
||||||
|
"test": {
|
||||||
|
"plugins": ["dynamic-import-node"],
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"modules": "commonjs",
|
||||||
|
"targets": {
|
||||||
|
"node": "current"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
> 1%
|
|
||||||
last 2 versions
|
|
||||||
not dead
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
|
@ -0,0 +1,9 @@
|
||||||
|
/dist
|
||||||
|
/src-bex/www
|
||||||
|
/src-capacitor
|
||||||
|
/src-cordova
|
||||||
|
/.quasar
|
||||||
|
/node_modules
|
||||||
|
.eslintrc.js
|
||||||
|
babel.config.js
|
||||||
|
/src-ssr
|
111
.eslintrc.js
111
.eslintrc.js
|
@ -1,28 +1,87 @@
|
||||||
|
const { resolve } = require('path');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
|
||||||
env: {
|
// This option interrupts the configuration hierarchy at this file
|
||||||
node: true,
|
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
|
||||||
},
|
root: true,
|
||||||
extends: [
|
|
||||||
'plugin:vue/vue3-essential',
|
// https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
|
||||||
'eslint:recommended',
|
// Must use parserOptions instead of "parser" to allow vue-eslint-parser to keep working
|
||||||
'@vue/typescript/recommended',
|
// `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted
|
||||||
'@vue/prettier',
|
parserOptions: {
|
||||||
'@vue/prettier/@typescript-eslint',
|
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#configuration
|
||||||
],
|
// https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#eslint
|
||||||
parserOptions: {
|
// Needed to make the parser take into account 'vue' files
|
||||||
ecmaVersion: 2020,
|
extraFileExtensions: ['.vue'],
|
||||||
},
|
parser: '@typescript-eslint/parser',
|
||||||
rules: {
|
project: resolve(__dirname, './tsconfig.json'),
|
||||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
tsconfigRootDir: __dirname,
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
|
||||||
},
|
sourceType: 'module', // Allows for the use of imports
|
||||||
overrides: [
|
},
|
||||||
{
|
|
||||||
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'],
|
env: {
|
||||||
env: {
|
browser: true,
|
||||||
jest: true,
|
},
|
||||||
},
|
|
||||||
},
|
// Rules order is important, please avoid shuffling them
|
||||||
],
|
extends: [
|
||||||
|
// Base ESLint recommended rules
|
||||||
|
// 'eslint:recommended',
|
||||||
|
|
||||||
|
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
|
||||||
|
// ESLint typescript rules
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
// consider disabling this class of rules if linting takes too long
|
||||||
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
|
|
||||||
|
// Uncomment any of the lines below to choose desired strictness,
|
||||||
|
// but leave only one uncommented!
|
||||||
|
// See https://eslint.vuejs.org/rules/#available-rules
|
||||||
|
'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
|
||||||
|
// 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
|
||||||
|
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
|
||||||
|
|
||||||
|
// https://github.com/prettier/eslint-config-prettier#installation
|
||||||
|
// usage with Prettier, provided by 'eslint-config-prettier'.
|
||||||
|
'prettier',
|
||||||
|
],
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
// required to apply rules which need type information
|
||||||
|
'@typescript-eslint',
|
||||||
|
|
||||||
|
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files
|
||||||
|
// required to lint *.vue files
|
||||||
|
'vue',
|
||||||
|
|
||||||
|
// https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
|
||||||
|
// Prettier has not been included as plugin to avoid performance impact
|
||||||
|
// add it as an extension for your IDE
|
||||||
|
],
|
||||||
|
|
||||||
|
globals: {
|
||||||
|
ga: 'readonly', // Google Analytics
|
||||||
|
cordova: 'readonly',
|
||||||
|
__statics: 'readonly',
|
||||||
|
__QUASAR_SSR__: 'readonly',
|
||||||
|
__QUASAR_SSR_SERVER__: 'readonly',
|
||||||
|
__QUASAR_SSR_CLIENT__: 'readonly',
|
||||||
|
__QUASAR_SSR_PWA__: 'readonly',
|
||||||
|
process: 'readonly',
|
||||||
|
Capacitor: 'readonly',
|
||||||
|
chrome: 'readonly',
|
||||||
|
},
|
||||||
|
|
||||||
|
// add your custom rules here
|
||||||
|
rules: {
|
||||||
|
'prefer-promise-reject-errors': 'off',
|
||||||
|
|
||||||
|
// TypeScript
|
||||||
|
quotes: ['warn', 'single', { avoidEscape: true }],
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
|
||||||
|
// allow debugger during development only
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.thumbs.db
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
# Quasar core related directories
|
||||||
|
.quasar
|
||||||
/dist
|
/dist
|
||||||
|
|
||||||
/tests/e2e/videos/
|
# Cordova related directories and files
|
||||||
/tests/e2e/screenshots/
|
/src-cordova/node_modules
|
||||||
|
/src-cordova/platforms
|
||||||
|
/src-cordova/plugins
|
||||||
|
/src-cordova/www
|
||||||
|
|
||||||
|
# Capacitor related directories and files
|
||||||
|
/src-capacitor/www
|
||||||
|
/src-capacitor/node_modules
|
||||||
|
|
||||||
# local env files
|
# BEX related directories and files
|
||||||
.env.local
|
/src-bex/www
|
||||||
.env.*.local
|
/src-bex/js/core
|
||||||
|
|
||||||
# Log files
|
# Log files
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
|
@ -22,4 +31,3 @@ pnpm-debug.log*
|
||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
// to edit target browsers: use "browserslist" field in package.json
|
||||||
|
require('autoprefixer'),
|
||||||
|
],
|
||||||
|
};
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 120,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"semi": true,
|
||||||
|
"endOfLine": 'auto',
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
singleQuote: true,
|
|
||||||
printWidth: 120,
|
|
||||||
tabWidth: 4,
|
|
||||||
endOfLine: 'auto',
|
|
||||||
};
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"johnsoncodehk.volar",
|
||||||
|
"wayou.vscode-todo-highlight"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"octref.vetur",
|
||||||
|
"hookyqr.beautify",
|
||||||
|
"dbaeumer.jshint",
|
||||||
|
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
{
|
{
|
||||||
"editor.codeActionsOnSave": {
|
"editor.bracketPairColorization.enabled": true,
|
||||||
"source.fixAll.eslint": true,
|
"editor.guides.bracketPairs": true,
|
||||||
},
|
"editor.formatOnSave": true,
|
||||||
"editor.bracketPairColorization.enabled": true,
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.guides.bracketPairs": true,
|
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||||
"files.eol": "\n",
|
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
|
||||||
"editor.tabSize": 4,
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
}
|
||||||
}
|
}
|
51
README.md
51
README.md
|
@ -1,34 +1,37 @@
|
||||||
# salix-front
|
# Salix (salix-front)
|
||||||
|
|
||||||
## Project setup
|
Salix front-end
|
||||||
```
|
|
||||||
|
## Install the dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and hot-reloads for development
|
### Start the app in development mode (hot-code reloading, error reporting, etc.)
|
||||||
```
|
|
||||||
npm run serve
|
```bash
|
||||||
|
quasar dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and minifies for production
|
### Lint the files
|
||||||
```
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run your unit tests
|
```bash
|
||||||
```
|
|
||||||
npm run test:unit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run your end-to-end tests
|
|
||||||
```
|
|
||||||
npm run test:e2e
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lints and fixes files
|
|
||||||
```
|
|
||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
### Customize configuration
|
### Format the files
|
||||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
|
||||||
|
```bash
|
||||||
|
npm run format
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build the app for production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
quasar build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize the configuration
|
||||||
|
|
||||||
|
See [Configuring quasar.conf.js](https://quasar.dev/quasar-cli/quasar-conf-js).
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/* eslint-env node */
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
let extend = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The .babelrc file has been created to assist Jest for transpiling.
|
||||||
|
* You should keep your application's babel rules in this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (fs.existsSync('./.babelrc')) {
|
||||||
|
extend = './.babelrc';
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: ['@vue/cli-plugin-babel/preset'],
|
presets: ['@quasar/babel-preset-app'],
|
||||||
|
extends: extend,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"pluginsFile": "tests/e2e/plugins/index.js"
|
|
||||||
}
|
|
|
@ -1,6 +1,81 @@
|
||||||
|
const esModules = ['quasar', 'quasar/lang', 'lodash-es'].join('|');
|
||||||
|
|
||||||
|
/* eslint-env node */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
|
globals: {
|
||||||
transform: {
|
__DEV__: true,
|
||||||
'^.+\\.vue$': 'vue-jest',
|
// TODO: Remove if resolved natively
|
||||||
|
// See https://github.com/vuejs/vue-jest/issues/175
|
||||||
|
'vue-jest': {
|
||||||
|
pug: { doctype: 'html' },
|
||||||
},
|
},
|
||||||
|
// Remove if using `const enums`
|
||||||
|
// See https://huafu.github.io/ts-jest/user/config/isolatedModules#example
|
||||||
|
'ts-jest': {
|
||||||
|
isolatedModules: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// noStackTrace: true,
|
||||||
|
// bail: true,
|
||||||
|
// cache: false,
|
||||||
|
// verbose: true,
|
||||||
|
// watch: true,
|
||||||
|
collectCoverage: false,
|
||||||
|
coverageDirectory: '<rootDir>/test/jest/coverage',
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'<rootDir>/src/**/*.vue',
|
||||||
|
'<rootDir>/src/**/*.js',
|
||||||
|
'<rootDir>/src/**/*.ts',
|
||||||
|
'<rootDir>/src/**/*.jsx',
|
||||||
|
'<rootDir>/src/**/*.tsx',
|
||||||
|
],
|
||||||
|
coveragePathIgnorePatterns: ['/node_modules/', '.d.ts$'],
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
// branches: 50,
|
||||||
|
// functions: 50,
|
||||||
|
// lines: 50,
|
||||||
|
// statements: 50
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testMatch: [
|
||||||
|
// Matches tests in any subfolder of 'src' or into 'test/jest/__tests__'
|
||||||
|
// Matches all files with extension 'js', 'jsx', 'ts' and 'tsx'
|
||||||
|
'<rootDir>/test/jest/__tests__/**/*.(spec|test).+(ts|js)?(x)',
|
||||||
|
'<rootDir>/src/**/*.jest.(spec|test).+(ts|js)?(x)',
|
||||||
|
],
|
||||||
|
// Extension-less imports of components are resolved to .ts files by TS,
|
||||||
|
// grating correct type-checking in test files.
|
||||||
|
// Being 'vue' the first moduleFileExtension option, the very same imports
|
||||||
|
// will be resolved to .vue files by Jest, if both .vue and .ts files are
|
||||||
|
// in the same folder.
|
||||||
|
// This guarantee a great dev experience both for testing and type-checking.
|
||||||
|
// See https://github.com/vuejs/vue-jest/issues/188#issuecomment-620750728
|
||||||
|
moduleFileExtensions: ['vue', 'js', 'jsx', 'json', 'ts', 'tsx'],
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^quasar$': 'quasar/dist/quasar.esm.prod.js',
|
||||||
|
'^~/(.*)$': '<rootDir>/$1',
|
||||||
|
'^src/(.*)$': '<rootDir>/src/$1',
|
||||||
|
'^app/(.*)$': '<rootDir>/$1',
|
||||||
|
'^components/(.*)$': '<rootDir>/src/components/$1',
|
||||||
|
'^layouts/(.*)$': '<rootDir>/src/layouts/$1',
|
||||||
|
'^pages/(.*)$': '<rootDir>/src/pages/$1',
|
||||||
|
'^assets/(.*)$': '<rootDir>/src/assets/$1',
|
||||||
|
'^boot/(.*)$': '<rootDir>/src/boot/$1',
|
||||||
|
'.*css$': '@quasar/quasar-app-extension-testing-unit-jest/stub.css',
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
// See https://jestjs.io/docs/en/configuration.html#transformignorepatterns-array-string
|
||||||
|
[`^(${esModules}).+\\.js$`]: 'babel-jest',
|
||||||
|
'^.+\\.(ts|js|html)$': 'ts-jest',
|
||||||
|
// vue-jest uses find-babel-file, which searches by this order:
|
||||||
|
// (async) .babelrc, .babelrc.js, package.json, babel.config.js
|
||||||
|
// (sync) .babelrc, .babelrc.js, babel.config.js, package.json
|
||||||
|
// https://github.com/tleunen/find-babel-config/issues/33
|
||||||
|
'.*\\.vue$': 'vue-jest',
|
||||||
|
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
|
||||||
|
'jest-transform-stub',
|
||||||
|
},
|
||||||
|
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
|
||||||
|
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
104
package.json
104
package.json
|
@ -1,49 +1,59 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "0.1.0",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"description": "Salix front-end",
|
||||||
"scripts": {
|
"productName": "Salix",
|
||||||
"serve": "vue-cli-service serve",
|
"author": "Salix",
|
||||||
"build": "vue-cli-service build",
|
"private": true,
|
||||||
"test:unit": "vue-cli-service test:unit",
|
"scripts": {
|
||||||
"test:e2e": "vue-cli-service test:e2e",
|
"lint": "eslint --ext .js,.ts,.vue ./",
|
||||||
"lint": "vue-cli-service lint",
|
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||||
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\""
|
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
||||||
},
|
"test:unit": "jest --updateSnapshot",
|
||||||
"dependencies": {
|
"test:unit:ci": "jest --ci",
|
||||||
"@quasar/extras": "^1.0.0",
|
"test:unit:coverage": "jest --coverage",
|
||||||
"axios": "^0.26.0",
|
"test:unit:watch": "jest --watch",
|
||||||
"core-js": "^3.6.5",
|
"test:unit:watchAll": "jest --watchAll",
|
||||||
"quasar": "^2.0.0",
|
"serve:test:coverage": "quasar serve test/jest/coverage/lcov-report/ --port 8788",
|
||||||
"vue": "^3.0.0",
|
"concurrently:dev:jest": "concurrently \"quasar dev\" \"jest --watch\""
|
||||||
"vue-i18n": "^9.1.0",
|
},
|
||||||
"vue-router": "^4.0.0-0"
|
"dependencies": {
|
||||||
},
|
"@quasar/extras": "^1.0.0",
|
||||||
"devDependencies": {
|
"axios": "^0.21.1",
|
||||||
"@intlify/vue-i18n-loader": "^3.0.0",
|
"core-js": "^3.6.5",
|
||||||
"@types/jest": "^24.0.19",
|
"quasar": "^2.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
"vue": "^3.0.0",
|
||||||
"@typescript-eslint/parser": "^4.18.0",
|
"vue-i18n": "^9.0.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.15",
|
"vue-router": "^4.0.0"
|
||||||
"@vue/cli-plugin-e2e-cypress": "~4.5.15",
|
},
|
||||||
"@vue/cli-plugin-eslint": "~4.5.15",
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-router": "~4.5.15",
|
"@babel/eslint-parser": "^7.13.14",
|
||||||
"@vue/cli-plugin-typescript": "~4.5.15",
|
"@intlify/vue-i18n-loader": "^4.1.0",
|
||||||
"@vue/cli-plugin-unit-jest": "~4.5.15",
|
"@quasar/app": "^3.0.0",
|
||||||
"@vue/cli-service": "~4.5.15",
|
"@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-alpha.8",
|
||||||
"@vue/compiler-sfc": "^3.0.0",
|
"@types/node": "^12.20.21",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||||
"@vue/eslint-config-typescript": "^7.0.0",
|
"@typescript-eslint/parser": "^5.10.0",
|
||||||
"@vue/test-utils": "^2.0.0-0",
|
"eslint": "^7.14.0",
|
||||||
"eslint": "^6.7.2",
|
"eslint-config-prettier": "^8.1.0",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-jest": "^25.2.2",
|
||||||
"eslint-plugin-vue": "^7.0.0",
|
"eslint-plugin-vue": "^7.0.0",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.5.1"
|
||||||
"sass": "1.32.12",
|
},
|
||||||
"sass-loader": "^10.1.0",
|
"browserslist": [
|
||||||
"typescript": "~4.1.5",
|
"last 10 Chrome versions",
|
||||||
"vue-cli-plugin-i18n": "~2.3.1",
|
"last 10 Firefox versions",
|
||||||
"vue-cli-plugin-quasar": "~4.0.4",
|
"last 4 Edge versions",
|
||||||
"vue-jest": "^5.0.0-0"
|
"last 7 Safari versions",
|
||||||
}
|
"last 8 Android versions",
|
||||||
|
"last 8 ChromeAndroid versions",
|
||||||
|
"last 8 FirefoxAndroid versions",
|
||||||
|
"last 10 iOS versions",
|
||||||
|
"last 5 Opera versions"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.22.1",
|
||||||
|
"npm": ">= 6.13.4",
|
||||||
|
"yarn": ">= 1.21.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 859 B |
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
|
@ -1,23 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
|
||||||
<title>
|
|
||||||
<%= htmlWebpackPlugin.options.title %>
|
|
||||||
</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<noscript>
|
|
||||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
|
||||||
Please enable it to continue.</strong>
|
|
||||||
</noscript>
|
|
||||||
<div id="app"></div>
|
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* This file runs in a Node context (it's NOT transpiled by Babel), so use only
|
||||||
|
* the ES6 features that are supported by your Node version. https://node.green/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Configuration for your app
|
||||||
|
// https://quasar.dev/quasar-cli/quasar-conf-js
|
||||||
|
|
||||||
|
/* eslint-env node */
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const { configure } = require('quasar/wrappers');
|
||||||
|
|
||||||
|
module.exports = configure(function (ctx) {
|
||||||
|
return {
|
||||||
|
// https://quasar.dev/quasar-cli/supporting-ts
|
||||||
|
supportTS: {
|
||||||
|
tsCheckerConfig: {
|
||||||
|
eslint: {
|
||||||
|
enabled: true,
|
||||||
|
files: './src/**/*.{ts,tsx,js,jsx,vue}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://quasar.dev/quasar-cli/prefetch-feature
|
||||||
|
// preFetch: true,
|
||||||
|
|
||||||
|
// app boot file (/src/boot)
|
||||||
|
// --> boot files are part of "main.js"
|
||||||
|
// https://quasar.dev/quasar-cli/boot-files
|
||||||
|
boot: ['i18n', 'axios'],
|
||||||
|
|
||||||
|
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
|
||||||
|
css: ['app.scss'],
|
||||||
|
|
||||||
|
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||||
|
extras: [
|
||||||
|
// 'ionicons-v4',
|
||||||
|
// 'mdi-v5',
|
||||||
|
// 'fontawesome-v5',
|
||||||
|
// 'eva-icons',
|
||||||
|
// 'themify',
|
||||||
|
// 'line-awesome',
|
||||||
|
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||||
|
|
||||||
|
'roboto-font', // optional, you are not bound to it
|
||||||
|
'material-icons', // optional, you are not bound to it
|
||||||
|
],
|
||||||
|
|
||||||
|
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
|
||||||
|
build: {
|
||||||
|
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
||||||
|
|
||||||
|
// transpile: false,
|
||||||
|
// publicPath: '/',
|
||||||
|
|
||||||
|
// Add dependencies for transpiling with Babel (Array of string/regex)
|
||||||
|
// (from node_modules, which are by default not transpiled).
|
||||||
|
// Applies only if "transpile" is set to true.
|
||||||
|
// transpileDependencies: [],
|
||||||
|
|
||||||
|
// rtl: true, // https://quasar.dev/options/rtl-support
|
||||||
|
// preloadChunks: true,
|
||||||
|
// showProgress: false,
|
||||||
|
// gzip: true,
|
||||||
|
// analyze: true,
|
||||||
|
|
||||||
|
// Options below are automatically set depending on the env, set them if you want to override
|
||||||
|
// extractCSS: false,
|
||||||
|
|
||||||
|
// https://quasar.dev/quasar-cli/handling-webpack
|
||||||
|
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||||
|
chainWebpack(/* chain */) {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
|
||||||
|
devServer: {
|
||||||
|
server: {
|
||||||
|
type: 'http',
|
||||||
|
},
|
||||||
|
port: 8080,
|
||||||
|
open: true, // opens browser window automatically
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:3000',
|
||||||
|
logLevel: 'debug',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
|
||||||
|
framework: {
|
||||||
|
config: {},
|
||||||
|
|
||||||
|
// iconSet: 'material-icons', // Quasar icon set
|
||||||
|
// lang: 'en-US', // Quasar language pack
|
||||||
|
|
||||||
|
// For special cases outside of where the auto-import strategy can have an impact
|
||||||
|
// (like functional components as one of the examples),
|
||||||
|
// you can manually specify Quasar components/directives to be available everywhere:
|
||||||
|
//
|
||||||
|
// components: [],
|
||||||
|
// directives: [],
|
||||||
|
|
||||||
|
// Quasar plugins
|
||||||
|
plugins: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
// animations: 'all', // --- includes all animations
|
||||||
|
// https://quasar.dev/options/animations
|
||||||
|
animations: [],
|
||||||
|
|
||||||
|
// https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
|
||||||
|
ssr: {
|
||||||
|
pwa: false,
|
||||||
|
|
||||||
|
// manualStoreHydration: true,
|
||||||
|
// manualPostHydrationTrigger: true,
|
||||||
|
|
||||||
|
prodPort: 3000, // The default port that the production server should use
|
||||||
|
// (gets superseded if process.env.PORT is specified at runtime)
|
||||||
|
|
||||||
|
maxAge: 1000 * 60 * 60 * 24 * 30,
|
||||||
|
// Tell browser when a file from the server should expire from cache (in ms)
|
||||||
|
|
||||||
|
chainWebpackWebserver(/* chain */) {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
|
||||||
|
middlewares: [
|
||||||
|
ctx.prod ? 'compression' : '',
|
||||||
|
'render', // keep this as last one
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa
|
||||||
|
pwa: {
|
||||||
|
workboxPluginMode: 'GenerateSW', // 'GenerateSW' or 'InjectManifest'
|
||||||
|
workboxOptions: {}, // only for GenerateSW
|
||||||
|
|
||||||
|
// for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts])
|
||||||
|
// if using workbox in InjectManifest mode
|
||||||
|
chainWebpackCustomSW(/* chain */) {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
|
||||||
|
manifest: {
|
||||||
|
name: 'Salix',
|
||||||
|
short_name: 'Salix',
|
||||||
|
description: 'Salix front-end',
|
||||||
|
display: 'standalone',
|
||||||
|
orientation: 'portrait',
|
||||||
|
background_color: '#ffffff',
|
||||||
|
theme_color: '#027be3',
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
src: 'icons/icon-128x128.png',
|
||||||
|
sizes: '128x128',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'icons/icon-192x192.png',
|
||||||
|
sizes: '192x192',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'icons/icon-256x256.png',
|
||||||
|
sizes: '256x256',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'icons/icon-384x384.png',
|
||||||
|
sizes: '384x384',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'icons/icon-512x512.png',
|
||||||
|
sizes: '512x512',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Full list of options: https://quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
|
||||||
|
cordova: {
|
||||||
|
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
|
||||||
|
},
|
||||||
|
|
||||||
|
// Full list of options: https://quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
|
||||||
|
capacitor: {
|
||||||
|
hideSplashscreen: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Full list of options: https://quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
|
||||||
|
electron: {
|
||||||
|
bundler: 'packager', // 'packager' or 'builder'
|
||||||
|
|
||||||
|
packager: {
|
||||||
|
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
|
||||||
|
// OS X / Mac App Store
|
||||||
|
// appBundleId: '',
|
||||||
|
// appCategoryType: '',
|
||||||
|
// osxSign: '',
|
||||||
|
// protocol: 'myapp://path',
|
||||||
|
// Windows only
|
||||||
|
// win32metadata: { ... }
|
||||||
|
},
|
||||||
|
|
||||||
|
builder: {
|
||||||
|
// https://www.electron.build/configuration/configuration
|
||||||
|
|
||||||
|
appId: 'salix-front',
|
||||||
|
},
|
||||||
|
|
||||||
|
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||||
|
chainWebpack(/* chain */) {
|
||||||
|
// do something with the Electron main process Webpack cfg
|
||||||
|
// extendWebpackMain also available besides this chainWebpackMain
|
||||||
|
},
|
||||||
|
|
||||||
|
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||||
|
chainWebpackPreload(/* chain */) {
|
||||||
|
// do something with the Electron main process Webpack cfg
|
||||||
|
// extendWebpackPreload also available besides this chainWebpackPreload
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"@quasar/testing-unit-jest": {
|
||||||
|
"babel": "babelrc",
|
||||||
|
"options": [
|
||||||
|
"scripts",
|
||||||
|
"typescript"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"unit-jest": {
|
||||||
|
"runnerCommand": "jest --ci"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,3 @@
|
||||||
<template>
|
|
||||||
<router-view></router-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
@ -17,6 +13,10 @@ quasar.iconMapFn = (iconName) => {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<router-view />
|
||||||
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.body--light {
|
.body--light {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { boot } from 'quasar/wrappers';
|
||||||
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
$axios: AxiosInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Be careful when using SSR for cross-request state pollution
|
||||||
|
// due to creating a Singleton instance here;
|
||||||
|
// If any client changes this (global) instance, it might be a
|
||||||
|
// 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' });
|
||||||
|
|
||||||
|
export default boot(({ app }) => {
|
||||||
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
|
app.config.globalProperties.$axios = axios;
|
||||||
|
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
||||||
|
// so you won't necessarily have to import axios in each vue file
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
export { api };
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { boot } from 'quasar/wrappers';
|
||||||
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import messages from 'src/i18n';
|
||||||
|
|
||||||
|
export default boot(({ app }) => {
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: 'en',
|
||||||
|
messages,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set i18n instance on app
|
||||||
|
app.use(i18n);
|
||||||
|
});
|
|
@ -1,52 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-header class="bg-dark" color="white" elevated bordered>
|
|
||||||
<q-toolbar class="q-py-sm q-px-md">
|
|
||||||
<q-btn flat @click="$emit('on-toggle-drawer')" round dense icon="menu" />
|
|
||||||
<router-link to="/">
|
|
||||||
<q-btn flat round class="q-ml-xs" v-if="$q.screen.gt.xs">
|
|
||||||
<q-avatar square size="md"><img src="@/assets/logo_icon.svg" alt="Logo" /></q-avatar>
|
|
||||||
</q-btn>
|
|
||||||
</router-link>
|
|
||||||
<q-toolbar-title shrink class="text-weight-bold"> Salix </q-toolbar-title>
|
|
||||||
<q-space></q-space>
|
|
||||||
<div class="q-pl-sm q-gutter-sm row items-center no-wrap">
|
|
||||||
<q-btn v-if="$q.screen.gt.xs" dense flat size="md" icon="add">
|
|
||||||
<q-icon name="arrow_drop_down" size="s" />
|
|
||||||
<q-menu>
|
|
||||||
<q-list style="min-width: 150px">
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>New customer</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>New ticket</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
<q-btn v-if="$q.screen.gt.xs" dense flat round size="md" icon="notifications" />
|
|
||||||
<q-btn dense flat no-wrap>
|
|
||||||
<q-avatar size="lg">
|
|
||||||
<q-img
|
|
||||||
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
|
||||||
spinner-color="white"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
|
||||||
<q-tooltip>Account</q-tooltip>
|
|
||||||
<q-icon name="arrow_drop_down" size="s" />
|
|
||||||
<UserPanel />
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</q-toolbar>
|
|
||||||
</q-header>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { useState } from '@/core/composables/useState';
|
|
||||||
import { useSession } from '@/core/composables/useSession';
|
|
||||||
import UserPanel from '@/components/UserPanel.vue';
|
|
||||||
|
|
||||||
const session = useSession();
|
|
||||||
const state = useState();
|
|
||||||
const user = state.getUser();
|
|
||||||
const token = session.getToken();
|
|
||||||
</script>
|
|
|
@ -1,91 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-menu>
|
|
||||||
<div class="row no-wrap q-pa-md">
|
|
||||||
<div class="column">
|
|
||||||
<div class="text-h6 q-mb-md">{{ t('components.userPanel.settings') }}</div>
|
|
||||||
<q-toggle
|
|
||||||
:label="t(`globals.lang['${locale}']`)"
|
|
||||||
icon="public"
|
|
||||||
color="orange"
|
|
||||||
false-value="es"
|
|
||||||
true-value="en"
|
|
||||||
v-model="locale"
|
|
||||||
/>
|
|
||||||
<q-toggle v-model="darkMode" checked-icon="dark_mode" color="orange" unchecked-icon="light_mode" />
|
|
||||||
|
|
||||||
<q-btn color="orange" outline size="sm" label="Settings" icon="settings" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-separator vertical inset class="q-mx-lg" />
|
|
||||||
|
|
||||||
<div class="column items-center" style="min-width: 150px">
|
|
||||||
<q-avatar size="80px">
|
|
||||||
<q-img
|
|
||||||
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
|
||||||
spinner-color="white"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
|
||||||
|
|
||||||
<div class="text-subtitle1 q-mt-md">
|
|
||||||
<strong>{{ user.nickname }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ user.username }}</div>
|
|
||||||
|
|
||||||
<q-btn color="orange" flat label="Log Out" size="sm" icon="logout" @click="logout()" v-close-popup />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-menu>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { onMounted, computed } from 'vue';
|
|
||||||
import { Dark, useQuasar } from 'quasar';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
import { useState } from '@/core/composables/useState';
|
|
||||||
import { useSession } from '@/core/composables/useSession';
|
|
||||||
|
|
||||||
const quasar = useQuasar();
|
|
||||||
const state = useState();
|
|
||||||
const session = useSession();
|
|
||||||
const router = useRouter();
|
|
||||||
const { t, locale } = useI18n();
|
|
||||||
|
|
||||||
const darkMode = computed({
|
|
||||||
get(): boolean {
|
|
||||||
return Dark.isActive;
|
|
||||||
},
|
|
||||||
set(value: boolean): void {
|
|
||||||
Dark.set(value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const user = state.getUser();
|
|
||||||
const token = session.getToken();
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
axios
|
|
||||||
.get('/api/accounts/acl')
|
|
||||||
.then(({ data }) => {
|
|
||||||
state.setUser({
|
|
||||||
id: data.user.id,
|
|
||||||
username: data.user.name,
|
|
||||||
nickname: data.user.nickname,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
quasar.notify({
|
|
||||||
message: t('errors.statusUnauthorized'),
|
|
||||||
type: 'negative',
|
|
||||||
});
|
|
||||||
logout();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function logout(): void {
|
|
||||||
session.destroy();
|
|
||||||
router.push('/login');
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
export interface Todo {
|
||||||
|
id: number;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Meta {
|
||||||
|
totalCount: number;
|
||||||
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
import store from '@/store';
|
|
||||||
|
|
||||||
export function useRole() {
|
|
||||||
function hasAny(roles: string[]): boolean {
|
|
||||||
const roleStore: string[] = store.state.roles;
|
|
||||||
|
|
||||||
for (const role of roles) {
|
|
||||||
if (roleStore.indexOf(role) !== -1) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasAny,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
import { useState } from './useState';
|
|
||||||
|
|
||||||
interface Session {
|
|
||||||
token: string;
|
|
||||||
keepLogin: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface useSession {
|
|
||||||
getToken: () => string;
|
|
||||||
setToken: (data: Session) => void;
|
|
||||||
destroy: () => void;
|
|
||||||
isLoggedIn: () => boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSession(): useSession {
|
|
||||||
function getToken(): string {
|
|
||||||
const localToken = localStorage.getItem('token');
|
|
||||||
const sessionToken = sessionStorage.getItem('token');
|
|
||||||
|
|
||||||
return localToken || sessionToken || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function setToken(data: Session): void {
|
|
||||||
if (data.keepLogin) {
|
|
||||||
localStorage.setItem('token', data.token);
|
|
||||||
} else {
|
|
||||||
sessionStorage.setItem('token', data.token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroy(): void {
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
sessionStorage.getItem('token');
|
|
||||||
|
|
||||||
const { setUser } = useState();
|
|
||||||
|
|
||||||
setUser({
|
|
||||||
id: 0,
|
|
||||||
username: '',
|
|
||||||
nickname: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLoggedIn() {
|
|
||||||
const localToken = localStorage.getItem('token');
|
|
||||||
const sessionToken = sessionStorage.getItem('token');
|
|
||||||
|
|
||||||
return !!(localToken || sessionToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
getToken,
|
|
||||||
setToken,
|
|
||||||
destroy,
|
|
||||||
isLoggedIn,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { ref, Ref, computed, ComputedRef } from 'vue';
|
|
||||||
|
|
||||||
interface User {
|
|
||||||
id: number;
|
|
||||||
username: string;
|
|
||||||
nickname: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface useState {
|
|
||||||
getUser: () => ComputedRef<User>;
|
|
||||||
setUser: (data: User) => void;
|
|
||||||
getRoles: () => ComputedRef<string[]>;
|
|
||||||
setRoles: (data: string[]) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user: Ref<User> = ref({
|
|
||||||
id: 0,
|
|
||||||
username: '',
|
|
||||||
nickname: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
const roles: Ref<string[]> = ref([]);
|
|
||||||
|
|
||||||
export function useState(): useState {
|
|
||||||
function getUser(): ComputedRef<User> {
|
|
||||||
return computed(() => {
|
|
||||||
return {
|
|
||||||
id: user.value.id,
|
|
||||||
username: user.value.username,
|
|
||||||
nickname: user.value.nickname,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setUser(data: User): void {
|
|
||||||
user.value = {
|
|
||||||
id: data.id,
|
|
||||||
username: data.username,
|
|
||||||
nickname: data.nickname,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRoles(): ComputedRef<string[]> {
|
|
||||||
return computed(() => {
|
|
||||||
return roles.value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setRoles(data: string[]): void {
|
|
||||||
roles.value = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
getUser,
|
|
||||||
setUser,
|
|
||||||
getRoles,
|
|
||||||
setRoles,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import toLowerCase from './toLowerCase';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
toLowerCase,
|
|
||||||
};
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default function toLowerCase(value: string): string {
|
|
||||||
return value.toLowerCase();
|
|
||||||
}
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
// app global css in SCSS form
|
||||||
|
@import './icons.scss';
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 158 KiB |
|
@ -0,0 +1,24 @@
|
||||||
|
// Quasar SCSS (& Sass) Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
// To customize the look and feel of this app, you can override
|
||||||
|
// the Sass/SCSS variables found in Quasar's source Sass/SCSS files.
|
||||||
|
|
||||||
|
// Check documentation for full list of Quasar variables
|
||||||
|
|
||||||
|
// Your own variables (that are declared here) and Quasar's own
|
||||||
|
// ones will be available out of the box in your .vue/.scss/.sass files
|
||||||
|
|
||||||
|
// It's highly recommended to change the default colors
|
||||||
|
// to match your app's branding.
|
||||||
|
// Tip: Use the "Theme Builder" on Quasar's documentation website.
|
||||||
|
|
||||||
|
$primary: #1976d2;
|
||||||
|
$secondary: #26a69a;
|
||||||
|
$accent: #9c27b0;
|
||||||
|
|
||||||
|
$dark: #1d1d1d;
|
||||||
|
|
||||||
|
$positive: #21ba45;
|
||||||
|
$negative: #c10015;
|
||||||
|
$info: #31ccec;
|
||||||
|
$warning: #f2c037;
|
|
@ -0,0 +1,7 @@
|
||||||
|
declare namespace NodeJS {
|
||||||
|
interface ProcessEnv {
|
||||||
|
NODE_ENV: string;
|
||||||
|
VUE_ROUTER_MODE: 'hash' | 'history' | 'abstract' | undefined;
|
||||||
|
VUE_ROUTER_BASE: string | undefined;
|
||||||
|
}
|
||||||
|
}
|
27
src/i18n.ts
27
src/i18n.ts
|
@ -1,27 +0,0 @@
|
||||||
import { createI18n, LocaleMessages, VueMessageType } from 'vue-i18n';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load locale messages
|
|
||||||
*
|
|
||||||
* The loaded `JSON` locale messages is pre-compiled by `@intlify/vue-i18n-loader`, which is integrated into `vue-cli-plugin-i18n`.
|
|
||||||
* See: https://github.com/intlify/vue-i18n-loader#rocket-i18n-resource-pre-compilation
|
|
||||||
*/
|
|
||||||
function loadLocaleMessages(): LocaleMessages<VueMessageType> {
|
|
||||||
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i);
|
|
||||||
const messages: LocaleMessages<VueMessageType> = {};
|
|
||||||
locales.keys().forEach((key) => {
|
|
||||||
const matched = key.match(/([A-Za-z0-9-_]+)\./i);
|
|
||||||
if (matched && matched.length > 1) {
|
|
||||||
const locale = matched[1];
|
|
||||||
messages[locale] = locales(key).default;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default createI18n({
|
|
||||||
legacy: false, // Disabled for composition API usage
|
|
||||||
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
|
|
||||||
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
|
|
||||||
messages: loadLocaleMessages(),
|
|
||||||
});
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// This is just an example,
|
||||||
|
// so you can safely delete all default props below
|
||||||
|
|
||||||
|
export default {
|
||||||
|
failed: 'Action failed',
|
||||||
|
success: 'Action was successful',
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
import en from './en';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
'en': en,
|
||||||
|
};
|
|
@ -0,0 +1,45 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title><%= productName %></title>
|
||||||
|
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="description" content="<%= productDescription %>" />
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="msapplication-tap-highlight" content="no" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="128x128"
|
||||||
|
href="icons/favicon-128x128.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="96x96"
|
||||||
|
href="icons/favicon-96x96.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="32x32"
|
||||||
|
href="icons/favicon-32x32.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="16x16"
|
||||||
|
href="icons/favicon-16x16.png"
|
||||||
|
/>
|
||||||
|
<link rel="icon" type="image/ico" href="favicon.ico" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- DO NOT touch the following DIV -->
|
||||||
|
<div id="q-app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,107 @@
|
||||||
|
<template>
|
||||||
|
<q-layout view="lHh Lpr lFf">
|
||||||
|
<q-header elevated>
|
||||||
|
<q-toolbar>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
round
|
||||||
|
icon="menu"
|
||||||
|
aria-label="Menu"
|
||||||
|
@click="toggleLeftDrawer"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-toolbar-title> Quasar App </q-toolbar-title>
|
||||||
|
|
||||||
|
<div>Quasar v{{ $q.version }}</div>
|
||||||
|
</q-toolbar>
|
||||||
|
</q-header>
|
||||||
|
|
||||||
|
<q-drawer v-model="leftDrawerOpen" 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-list>
|
||||||
|
</q-drawer>
|
||||||
|
|
||||||
|
<q-page-container>
|
||||||
|
<router-view />
|
||||||
|
</q-page-container>
|
||||||
|
</q-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
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 { defineComponent, ref } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MainLayout',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
EssentialLink,
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const leftDrawerOpen = ref(false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
essentialLinks: linksList,
|
||||||
|
leftDrawerOpen,
|
||||||
|
toggleLeftDrawer() {
|
||||||
|
leftDrawerOpen.value = !leftDrawerOpen.value;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
"globals": {
|
|
||||||
"lang": {
|
|
||||||
"es": "Spanish",
|
|
||||||
"en": "English"
|
|
||||||
},
|
|
||||||
"pages": {
|
|
||||||
"logIn": "Log In"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"statusUnauthorized": "Access denied",
|
|
||||||
"statusInternalServerError": "An internal server error has ocurred"
|
|
||||||
},
|
|
||||||
"login": {
|
|
||||||
"title": "Login",
|
|
||||||
"username": "Username",
|
|
||||||
"password": "Password",
|
|
||||||
"submit": "Log in",
|
|
||||||
"keepLogin": "Keep me logged in",
|
|
||||||
"loginSuccess": "You have successfully logged in",
|
|
||||||
"loginError": "Invalid username or password"
|
|
||||||
},
|
|
||||||
"customer": {},
|
|
||||||
"components": {
|
|
||||||
"topbar": {},
|
|
||||||
"userPanel": {
|
|
||||||
"settings": "Settings",
|
|
||||||
"logOut": "Log Out"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"globals": {
|
|
||||||
"lang": {
|
|
||||||
"es": "Español",
|
|
||||||
"en": "Inglés"
|
|
||||||
},
|
|
||||||
"pages": {
|
|
||||||
"logIn": "Iniciar sesión",
|
|
||||||
"dashboard": "Portada",
|
|
||||||
"customers": "Clientes",
|
|
||||||
"customerList": "Listado de clientes",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"statusUnauthorized": "Acceso denegado",
|
|
||||||
"statusInternalServerError": "Ha ocurrido un error interno del servidor"
|
|
||||||
},
|
|
||||||
"login": {
|
|
||||||
"title": "Iniciar sesión",
|
|
||||||
"username": "Nombre de usuario",
|
|
||||||
"password": "Contraseña",
|
|
||||||
"submit": "Iniciar sesión",
|
|
||||||
"keepLogin": "Mantener sesión iniciada",
|
|
||||||
"loginSuccess": "Inicio de sesión correcto",
|
|
||||||
"loginError": "Nombre de usuario o contraseña incorrectos"
|
|
||||||
},
|
|
||||||
"customer": {},
|
|
||||||
"components": {
|
|
||||||
"topbar": {},
|
|
||||||
"userPanel": {
|
|
||||||
"settings": "Configuración",
|
|
||||||
"logOut": "Cerrar sesión"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
30
src/main.ts
30
src/main.ts
|
@ -1,30 +0,0 @@
|
||||||
import { createApp } from 'vue';
|
|
||||||
import App from './App.vue';
|
|
||||||
import router from './router';
|
|
||||||
import { Quasar } from 'quasar';
|
|
||||||
import quasarUserOptions from './quasar-user-options';
|
|
||||||
import i18n from './i18n';
|
|
||||||
|
|
||||||
const app = createApp(App).use(i18n).use(Quasar, quasarUserOptions).use(router);
|
|
||||||
|
|
||||||
app.mount('#app');
|
|
||||||
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
import { useSession } from '@/core/composables/useSession';
|
|
||||||
const { getToken } = useSession();
|
|
||||||
|
|
||||||
axios.interceptors.request.use(
|
|
||||||
function (context) {
|
|
||||||
const token = getToken();
|
|
||||||
|
|
||||||
if (token.length && context.headers) {
|
|
||||||
context.headers.Authorization = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
|
||||||
},
|
|
||||||
function (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div style="font-size: 30vh">404</div>
|
||||||
|
|
||||||
|
<div class="text-h2" style="opacity: 0.4">Oops. Nothing here...</div>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
class="q-mt-xl"
|
||||||
|
color="white"
|
||||||
|
text-color="blue"
|
||||||
|
unelevated
|
||||||
|
to="/"
|
||||||
|
label="Go Home"
|
||||||
|
no-caps
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Error404',
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<!-- <q-page class="row items-center justify-evenly">
|
||||||
|
<example-component
|
||||||
|
title="Example component"
|
||||||
|
active
|
||||||
|
:todos="todos"
|
||||||
|
:meta="meta"
|
||||||
|
></example-component>
|
||||||
|
</q-page>-->
|
||||||
|
<div>asdasda</div>
|
||||||
|
<q-icon name="vn:ticket" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
// import { useQuasar } from 'quasar';
|
||||||
|
//const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div {
|
||||||
|
background-color: $primary;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,12 +0,0 @@
|
||||||
import './styles/quasar.scss';
|
|
||||||
import lang from 'quasar/lang/es.js';
|
|
||||||
import '@quasar/extras/roboto-font/roboto-font.css';
|
|
||||||
import '@quasar/extras/material-icons/material-icons.css';
|
|
||||||
import { Notify } from 'quasar';
|
|
||||||
|
|
||||||
// To be used on app.use(Quasar, { ... })
|
|
||||||
export default {
|
|
||||||
config: {},
|
|
||||||
plugins: [Notify],
|
|
||||||
lang: lang,
|
|
||||||
};
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Forces TS to apply `@quasar/app` augmentations of `quasar` package
|
||||||
|
// Removing this would break `quasar/wrappers` imports as those typings are declared
|
||||||
|
// into `@quasar/app`
|
||||||
|
// As a side effect, since `@quasar/app` reference `quasar` to augment it,
|
||||||
|
// this declaration also apply `quasar` own
|
||||||
|
// augmentations (eg. adds `$q` into Vue component context)
|
||||||
|
/// <reference types="@quasar/app" />
|
|
@ -1,85 +1,39 @@
|
||||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
|
import { route } from 'quasar/wrappers';
|
||||||
import { useSession } from '@/core/composables/useSession';
|
import {
|
||||||
import i18n from '@/i18n';
|
createMemoryHistory,
|
||||||
|
createRouter,
|
||||||
|
createWebHashHistory,
|
||||||
|
createWebHistory,
|
||||||
|
} from 'vue-router';
|
||||||
|
import routes from './routes';
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
/*
|
||||||
{
|
* If not building with SSR mode, you can
|
||||||
path: '/login',
|
* directly export the Router instantiation;
|
||||||
name: 'Login',
|
*
|
||||||
meta: { title: 'logIn' },
|
* The function below can be async too; either use
|
||||||
component: () => import('../views/Login/Login.vue'),
|
* async/await or return a Promise which resolves
|
||||||
},
|
* with the Router instance.
|
||||||
{
|
*/
|
||||||
path: '/',
|
|
||||||
name: 'Main',
|
|
||||||
component: () => import('../views/Layout/Main.vue'),
|
|
||||||
redirect: { name: 'Dashboard' },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/dashboard',
|
|
||||||
name: 'Dashboard',
|
|
||||||
meta: { title: 'dashboard' },
|
|
||||||
component: () => import('../views/Dashboard/Dashboard.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/customer',
|
|
||||||
name: 'Customer',
|
|
||||||
meta: { title: 'customers' },
|
|
||||||
component: () => import('../views/Customer/Customer.vue'),
|
|
||||||
redirect: { name: 'List' },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'list',
|
|
||||||
name: 'List',
|
|
||||||
meta: { title: 'customerList' },
|
|
||||||
component: () => import('../views/Customer/List.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':id',
|
|
||||||
name: 'Card',
|
|
||||||
component: () => import('../views/Customer/Card/Card.vue'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/:pathMatch(.*)*',
|
|
||||||
name: 'NotFound',
|
|
||||||
component: () => import('../views/Layout/NotFound.vue'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const router = createRouter({
|
export default route(function (/* { store, ssrContext } */) {
|
||||||
history: createWebHistory(process.env.BASE_URL),
|
const createHistory = process.env.SERVER
|
||||||
|
? createMemoryHistory
|
||||||
|
: process.env.VUE_ROUTER_MODE === 'history'
|
||||||
|
? createWebHistory
|
||||||
|
: createWebHashHistory;
|
||||||
|
|
||||||
|
const Router = createRouter({
|
||||||
|
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||||
routes,
|
routes,
|
||||||
|
|
||||||
|
// Leave this as is and make changes in quasar.conf.js instead!
|
||||||
|
// quasar.conf.js -> build -> vueRouterMode
|
||||||
|
// quasar.conf.js -> build -> publicPath
|
||||||
|
history: createHistory(
|
||||||
|
process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Router;
|
||||||
});
|
});
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
const session = useSession();
|
|
||||||
const { isLoggedIn } = session;
|
|
||||||
|
|
||||||
if (!isLoggedIn && to.name !== 'Login') {
|
|
||||||
next({ path: '/login', query: { redirect: to.fullPath } });
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.afterEach((to) => {
|
|
||||||
interface Meta {
|
|
||||||
title?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = i18n.global;
|
|
||||||
|
|
||||||
const childMeta: Meta = to.meta;
|
|
||||||
if (childMeta && childMeta.title) {
|
|
||||||
//const parent = to.matched[1];
|
|
||||||
//const childTitle: string = childMeta.title;
|
|
||||||
|
|
||||||
document.title = t(`globals.pages.${childMeta.title}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
|
const routes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: () => import('layouts/MainLayout.vue'),
|
||||||
|
children: [{ path: '', component: () => import('pages/Index.vue') }],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Always leave this as last one,
|
||||||
|
// but you can also remove it
|
||||||
|
{
|
||||||
|
path: '/:catchAll(.*)*',
|
||||||
|
component: () => import('pages/Error404.vue'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default routes;
|
|
@ -1,6 +1,7 @@
|
||||||
|
// Mocks all files ending in `.vue` showing them as plain Vue instances
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import type { DefineComponent } from 'vue'
|
import type { DefineComponent } from 'vue';
|
||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>;
|
||||||
export default component
|
export default component;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
@import './quasar.variables.scss';
|
|
||||||
@import '~quasar-styl';
|
|
||||||
@import './icons.scss';
|
|
||||||
// @import '~quasar-addon-styl';
|
|
|
@ -1,16 +0,0 @@
|
||||||
// It's highly recommended to change the default colors
|
|
||||||
// to match your app's branding.
|
|
||||||
|
|
||||||
$primary : #027BE3;
|
|
||||||
$secondary : #26A69A;
|
|
||||||
$accent : #9C27B0;
|
|
||||||
|
|
||||||
$dark : #1D1D1D;
|
|
||||||
$darker : #111111;
|
|
||||||
|
|
||||||
$positive : #21BA45;
|
|
||||||
$negative : #C10015;
|
|
||||||
$info : #31CCEC;
|
|
||||||
$warning : #F2C037;
|
|
||||||
|
|
||||||
@import '~quasar-variables-styl'
|
|
|
@ -1,15 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="row fit fixed">
|
|
||||||
<div class="col-2">
|
|
||||||
<q-card square>
|
|
||||||
<router-link :to="{ path: '/customer/list' }">
|
|
||||||
<q-icon name="arrow_back" size="md" color="primary" />
|
|
||||||
</router-link>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<q-card>asd</q-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<router-view></router-view>
|
|
||||||
</template>
|
|
|
@ -1,145 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-page class="q-pa-md">
|
|
||||||
<div class="column items-center q-gutter-y-md">
|
|
||||||
<q-card v-for="customer in customers" :key="customer.id" class="card">
|
|
||||||
<!-- v-ripple :to="{ path: '/dashboard' }" -->
|
|
||||||
<q-item v-ripple class="q-pa-none items-start cursor-pointer q-hoverable">
|
|
||||||
<q-item-section class="q-pa-md">
|
|
||||||
<div class="text-h6">{{ customer.name }}</div>
|
|
||||||
<q-item-label caption>@{{ customer.username }}</q-item-label>
|
|
||||||
<div class="q-mt-md">
|
|
||||||
<q-list>
|
|
||||||
<q-item class="q-pa-none">
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label caption>Email</q-item-label>
|
|
||||||
<q-item-label>{{ customer.email }}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item class="q-pa-none">
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label caption>Phone</q-item-label>
|
|
||||||
<q-item-label>{{ customer.phone }} </q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</div>
|
|
||||||
</q-item-section>
|
|
||||||
<q-separator vertical />
|
|
||||||
<q-card-actions vertical class="justify-between">
|
|
||||||
<q-btn color="grey-7" round flat icon="more_vert">
|
|
||||||
<q-menu cover auto-close>
|
|
||||||
<q-list>
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>Action 1</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>Action 2</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
<q-btn flat round color="orange" icon="badge" @click="navigate(customer.id)" />
|
|
||||||
<q-btn flat round color="accent" icon="preview" />
|
|
||||||
<q-card-actions>
|
|
||||||
<q-btn
|
|
||||||
color="grey"
|
|
||||||
round
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
:icon="customer.expanded.value ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
|
|
||||||
@click="customer.expanded.value = !customer.expanded.value"
|
|
||||||
/>
|
|
||||||
</q-card-actions>
|
|
||||||
</q-card-actions>
|
|
||||||
</q-item>
|
|
||||||
<q-slide-transition>
|
|
||||||
<div v-show="customer.expanded.value">
|
|
||||||
<q-separator />
|
|
||||||
<q-card-section class="text-subitle2">
|
|
||||||
<q-list>
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label>Address</q-item-label>
|
|
||||||
<q-item-label caption>Avenue 11</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-card-section>
|
|
||||||
</div>
|
|
||||||
</q-slide-transition>
|
|
||||||
<!-- <q-card-section horizontal>
|
|
||||||
<q-card-section vertical class="col">
|
|
||||||
<div class="text-h6">{{ customer.name }}</div>
|
|
||||||
<div class="text-subtitle2">@{{ customer.username }}</div>
|
|
||||||
|
|
||||||
<q-card-section vertical>text</q-card-section>
|
|
||||||
</q-card-section>
|
|
||||||
|
|
||||||
<q-separator vertical />
|
|
||||||
|
|
||||||
<q-card-actions vertical class="justify-around">
|
|
||||||
<q-btn flat round color="red" icon="favorite" />
|
|
||||||
<q-btn flat round color="accent" icon="bookmark" />
|
|
||||||
<q-btn color="grey-7" round flat icon="more_vert">
|
|
||||||
<q-menu cover auto-close>
|
|
||||||
<q-list>
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>Action 1</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section>Action 2</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
</q-card-actions>
|
|
||||||
</q-card-section> -->
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
</q-page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, Ref } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
interface Customer {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
username: string;
|
|
||||||
email: string;
|
|
||||||
phone: string;
|
|
||||||
expanded: Ref<boolean>;
|
|
||||||
}
|
|
||||||
const customers: Customer[] = [
|
|
||||||
{
|
|
||||||
id: 1101,
|
|
||||||
name: 'Bruce Wayne',
|
|
||||||
username: 'batman',
|
|
||||||
email: 'batman@gotham',
|
|
||||||
phone: '555-555-5555',
|
|
||||||
expanded: ref(false),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1102,
|
|
||||||
name: 'James Gordon',
|
|
||||||
username: 'jamesgordon',
|
|
||||||
email: 'jamesgordon@gotham',
|
|
||||||
phone: '555-555-1111',
|
|
||||||
expanded: ref(false),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function navigate(id: number) {
|
|
||||||
router.push({ path: `/customer/${id}` });
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 60em;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-page class="q-pa-md">
|
|
||||||
<q-card class="q-pa-md"> Dashboard page.. </q-card>
|
|
||||||
</q-page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
|
@ -1,83 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-layout view="hHh lpR fFf">
|
|
||||||
<Topbar @on-toggle-drawer="onToggleDrawer()" />
|
|
||||||
<q-drawer
|
|
||||||
v-model="drawer"
|
|
||||||
show-if-above
|
|
||||||
:mini="miniState"
|
|
||||||
@mouseover="miniState = false"
|
|
||||||
@mouseout="miniState = true"
|
|
||||||
mini-to-overlay
|
|
||||||
:width="200"
|
|
||||||
:breakpoint="500"
|
|
||||||
>
|
|
||||||
<q-scroll-area class="fit text-grey-8">
|
|
||||||
<q-list padding>
|
|
||||||
<q-item clickable v-ripple :to="{ path: '/dashboard' }" active-class="text-orange">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="dashboard" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> Dashboard</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable v-ripple :to="{ path: '/customer' }" active-class="text-orange">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="people" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> Customers </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable v-ripple :to="{ path: '/ticket' }" active-class="text-orange">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="vn:ticket" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> Tickets </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable v-ripple>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="receipt" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section> Invoice Out </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item clickable v-ripple>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="shopping_cart" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section> Catalog </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-separator />
|
|
||||||
|
|
||||||
<q-item clickable v-ripple>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="drafts" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section> Drafts </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-scroll-area>
|
|
||||||
</q-drawer>
|
|
||||||
<q-page-container>
|
|
||||||
<router-view></router-view>
|
|
||||||
</q-page-container>
|
|
||||||
</q-layout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import Topbar from '@/components/Topbar.vue';
|
|
||||||
const drawer = ref(false);
|
|
||||||
const miniState = ref(true);
|
|
||||||
|
|
||||||
function onToggleDrawer(): void {
|
|
||||||
drawer.value = !drawer.value;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.bg-darker {
|
|
||||||
background-color: $darker;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-page> Page not found </q-page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
|
@ -1,130 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-layout>
|
|
||||||
<q-header class="transparent">
|
|
||||||
<q-toolbar>
|
|
||||||
<q-space></q-space>
|
|
||||||
<q-toggle
|
|
||||||
:label="t(`globals.lang['${locale}']`)"
|
|
||||||
icon="public"
|
|
||||||
color="orange"
|
|
||||||
false-value="es"
|
|
||||||
true-value="en"
|
|
||||||
v-model="locale"
|
|
||||||
/>
|
|
||||||
<q-toggle v-model="darkMode" checked-icon="dark_mode" color="orange" unchecked-icon="light_mode" />
|
|
||||||
</q-toolbar>
|
|
||||||
</q-header>
|
|
||||||
<q-page-container>
|
|
||||||
<q-page>
|
|
||||||
<div id="login">
|
|
||||||
<q-card class="login q-pa-xl">
|
|
||||||
<img src="@/assets/logo.svg" alt="Logo" class="logo q-mb-xl" />
|
|
||||||
<q-form @submit="onSubmit" class="q-gutter-md">
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
color="orange"
|
|
||||||
v-model="username"
|
|
||||||
:label="t('login.username')"
|
|
||||||
lazy-rules
|
|
||||||
:rules="[
|
|
||||||
(val: string) => (val && val.length > 0) || 'Please type something',
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
color="orange"
|
|
||||||
type="password"
|
|
||||||
v-model="password"
|
|
||||||
:label="t('login.password')"
|
|
||||||
lazy-rules
|
|
||||||
:rules="[
|
|
||||||
(val: string) => (val && val.length > 0) || 'Please type something',
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
<q-toggle v-model="keepLogin" :label="t('login.keepLogin')" color="orange" />
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<q-btn :label="t('login.submit')" type="submit" color="orange" />
|
|
||||||
</div>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
</q-page>
|
|
||||||
</q-page-container>
|
|
||||||
</q-layout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { Dark, useQuasar } from 'quasar';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
import { useSession } from '@/core/composables/useSession';
|
|
||||||
|
|
||||||
const quasar = useQuasar();
|
|
||||||
const session = useSession();
|
|
||||||
const router = useRouter();
|
|
||||||
const { t, locale } = useI18n();
|
|
||||||
|
|
||||||
let username = ref('');
|
|
||||||
let password = ref('');
|
|
||||||
let keepLogin = ref(true);
|
|
||||||
|
|
||||||
const darkMode = computed({
|
|
||||||
get(): boolean {
|
|
||||||
return Dark.isActive;
|
|
||||||
},
|
|
||||||
set(value: boolean): void {
|
|
||||||
Dark.set(value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function onSubmit(): void {
|
|
||||||
axios
|
|
||||||
.post('/api/accounts/login', {
|
|
||||||
user: username.value,
|
|
||||||
password: password.value,
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
session.setToken({
|
|
||||||
token: response.data.token,
|
|
||||||
keepLogin: keepLogin.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
quasar.notify({
|
|
||||||
message: t('login.loginSuccess'),
|
|
||||||
type: 'positive',
|
|
||||||
});
|
|
||||||
router.push('/dashboard');
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
const errorCode = error.response.status;
|
|
||||||
if (errorCode === 401) {
|
|
||||||
quasar.notify({
|
|
||||||
message: t('login.loginFailed'),
|
|
||||||
type: 'negative',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
quasar.notify({
|
|
||||||
message: t('errors.statusInternalServerError'),
|
|
||||||
type: 'negative',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
#login {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
min-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login {
|
|
||||||
width: 400px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = {
|
||||||
|
extends: [
|
||||||
|
// Removes 'no-undef' lint errors for Jest global functions (`describe`, `it`, etc),
|
||||||
|
// add Jest-specific lint rules and Jest plugin
|
||||||
|
// See https://github.com/jest-community/eslint-plugin-jest#recommended
|
||||||
|
'plugin:jest/recommended',
|
||||||
|
// Uncomment following line to apply style rules
|
||||||
|
// 'plugin:jest/style',
|
||||||
|
],
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
coverage/*
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { describe, expect, it } from '@jest/globals';
|
||||||
|
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-jest';
|
||||||
|
import { mount, shallowMount } from '@vue/test-utils';
|
||||||
|
import { QBtn } from 'quasar';
|
||||||
|
import MyButton from './demo/MyButton';
|
||||||
|
|
||||||
|
// Specify here Quasar config you'll need to test your component
|
||||||
|
installQuasarPlugin();
|
||||||
|
|
||||||
|
describe('MyButton', () => {
|
||||||
|
it('has increment method', () => {
|
||||||
|
const wrapper = mount(MyButton);
|
||||||
|
const { vm } = wrapper;
|
||||||
|
|
||||||
|
expect(typeof vm.increment).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can check the inner text content', () => {
|
||||||
|
const wrapper = mount(MyButton);
|
||||||
|
const { vm } = wrapper;
|
||||||
|
|
||||||
|
expect((vm.$el as HTMLElement).textContent).toContain('rocket muffin');
|
||||||
|
expect(wrapper.find('.content').text()).toContain('rocket muffin');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the correct default data', () => {
|
||||||
|
const wrapper = mount(MyButton);
|
||||||
|
const { vm } = wrapper;
|
||||||
|
|
||||||
|
expect(typeof vm.counter).toBe('number');
|
||||||
|
expect(vm.counter).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly updates counter when button is pressed', async () => {
|
||||||
|
const wrapper = shallowMount(MyButton);
|
||||||
|
const { vm } = wrapper;
|
||||||
|
const button = wrapper.findComponent(QBtn);
|
||||||
|
await button.trigger('click');
|
||||||
|
expect(vm.counter).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-jest';
|
||||||
|
import { describe, expect, it } from '@jest/globals';
|
||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import MyDialog from './demo/MyDialog';
|
||||||
|
|
||||||
|
installQuasarPlugin();
|
||||||
|
|
||||||
|
describe('MyDialog', () => {
|
||||||
|
it('should mount MyDialog', () => {
|
||||||
|
const wrapper = mount(MyDialog, {
|
||||||
|
data: () => ({
|
||||||
|
isDialogOpen: true,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.exists()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { defineComponent, ref } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MyButton',
|
||||||
|
props: {
|
||||||
|
incrementStep: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const counter = ref(0);
|
||||||
|
const input = ref('rocket muffin');
|
||||||
|
function increment() {
|
||||||
|
counter.value += props.incrementStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { counter, input, increment };
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script lang="ts" src="./MyButton.ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p class="content">{{ input }}</p>
|
||||||
|
<span>{{ counter }}</span>
|
||||||
|
<q-btn class="button" @click="increment()"></q-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MyDialog',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isDialogOpen: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script lang="ts" src="./MyDialog.ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-dialog v-model="isDialogOpen">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>Custom dialog which should be tested</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
plugins: ['cypress'],
|
|
||||||
env: {
|
|
||||||
mocha: true,
|
|
||||||
'cypress/globals': true,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
strict: 'off',
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* eslint-disable arrow-body-style */
|
|
||||||
// https://docs.cypress.io/guides/guides/plugins-guide.html
|
|
||||||
|
|
||||||
// if you need a custom webpack configuration you can uncomment the following import
|
|
||||||
// and then use the `file:preprocessor` event
|
|
||||||
// as explained in the cypress docs
|
|
||||||
// https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples
|
|
||||||
|
|
||||||
// /* eslint-disable import/no-extraneous-dependencies, global-require */
|
|
||||||
// const webpack = require('@cypress/webpack-preprocessor')
|
|
||||||
|
|
||||||
module.exports = (on, config) => {
|
|
||||||
// on('file:preprocessor', webpack({
|
|
||||||
// webpackOptions: require('@vue/cli-service/webpack.config'),
|
|
||||||
// watchOptions: {}
|
|
||||||
// }))
|
|
||||||
|
|
||||||
return Object.assign({}, config, {
|
|
||||||
fixturesFolder: 'tests/e2e/fixtures',
|
|
||||||
integrationFolder: 'tests/e2e/specs',
|
|
||||||
screenshotsFolder: 'tests/e2e/screenshots',
|
|
||||||
videosFolder: 'tests/e2e/videos',
|
|
||||||
supportFile: 'tests/e2e/support/index.js',
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,8 +0,0 @@
|
||||||
// https://docs.cypress.io/api/introduction/api.html
|
|
||||||
|
|
||||||
describe('My First Test', () => {
|
|
||||||
it('Visits the app root url', () => {
|
|
||||||
cy.visit('/');
|
|
||||||
cy.contains('h1', 'Welcome to Your Vue.js + TypeScript App');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,25 +0,0 @@
|
||||||
// ***********************************************
|
|
||||||
// This example commands.js shows you how to
|
|
||||||
// create various custom commands and overwrite
|
|
||||||
// existing commands.
|
|
||||||
//
|
|
||||||
// For more comprehensive examples of custom
|
|
||||||
// commands please read more here:
|
|
||||||
// https://on.cypress.io/custom-commands
|
|
||||||
// ***********************************************
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a parent command --
|
|
||||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a child command --
|
|
||||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a dual command --
|
|
||||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is will overwrite an existing command --
|
|
||||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
|
|
@ -1,20 +0,0 @@
|
||||||
// ***********************************************************
|
|
||||||
// This example support/index.js is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// Import commands.js using ES2015 syntax:
|
|
||||||
import './commands';
|
|
||||||
|
|
||||||
// Alternatively you can use CommonJS syntax:
|
|
||||||
// require('./commands')
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
|
||||||
import HelloWorld from '@/components/HelloWorld.vue';
|
|
||||||
|
|
||||||
describe('HelloWorld.vue', () => {
|
|
||||||
it('renders props.msg when passed', () => {
|
|
||||||
const msg = 'new message';
|
|
||||||
const wrapper = shallowMount(HelloWorld, {
|
|
||||||
props: { msg },
|
|
||||||
});
|
|
||||||
expect(wrapper.text()).toMatch(msg);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,41 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"extends": "@quasar/app/tsconfig-preset",
|
||||||
"target": "esnext",
|
"compilerOptions": {
|
||||||
"module": "esnext",
|
"baseUrl": "."
|
||||||
"strict": true,
|
}
|
||||||
"jsx": "preserve",
|
|
||||||
"importHelpers": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"types": [
|
|
||||||
"webpack-env",
|
|
||||||
"jest"
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"@/*": [
|
|
||||||
"src/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lib": [
|
|
||||||
"esnext",
|
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"scripthost"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.tsx",
|
|
||||||
"src/**/*.vue",
|
|
||||||
"tests/**/*.ts",
|
|
||||||
"tests/**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
pluginOptions: {
|
|
||||||
quasar: {
|
|
||||||
importStrategy: 'kebab',
|
|
||||||
rtlSupport: false,
|
|
||||||
},
|
|
||||||
i18n: {
|
|
||||||
locale: 'es',
|
|
||||||
fallbackLocale: 'en',
|
|
||||||
localeDir: 'locales',
|
|
||||||
enableLegacy: false,
|
|
||||||
runtimeOnly: false,
|
|
||||||
compositionOnly: false,
|
|
||||||
fullInstall: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
css: {
|
|
||||||
loaderOptions: {
|
|
||||||
sass: {
|
|
||||||
additionalData: `@import "@/styles/quasar.variables.scss";`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
transpileDependencies: ['quasar'],
|
|
||||||
devServer: {
|
|
||||||
proxy: {
|
|
||||||
'^/api': {
|
|
||||||
target: 'http://localhost:3000',
|
|
||||||
logLevel: 'debug',
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
Loading…
Reference in New Issue