1
ayanova/.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
src/utils/libs/*.js
|
||||
24
ayanova/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
/tests/e2e/videos/
|
||||
/tests/e2e/screenshots/
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
36
ayanova/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# ayanova
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Run your tests
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Run your end-to-end tests
|
||||
```
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
### Run your unit tests
|
||||
```
|
||||
npm run test:unit
|
||||
```
|
||||
10
ayanova/babel.config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
"@vue/app",
|
||||
{
|
||||
useBuiltIns: "entry"
|
||||
}
|
||||
]
|
||||
]
|
||||
};
|
||||
3
ayanova/cypress.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"pluginsFile": "tests/e2e/plugins/index.js"
|
||||
}
|
||||
16333
ayanova/package-lock.json
generated
Normal file
93
ayanova/package.json
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"name": "ayanova",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.0.0-rc.1",
|
||||
"dayjs": "^1.7.7",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"register-service-worker": "^1.0.0",
|
||||
"typeface-roboto": "0.0.54",
|
||||
"vue": "^2.5.17",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuetify": "^1.3.0",
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-persistedstate": "^2.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/webpack-preprocessor": "^3.0.0",
|
||||
"@fortawesome/fontawesome-free": "^5.5.0",
|
||||
"@vue/cli-plugin-babel": "^3.0.5",
|
||||
"@vue/cli-plugin-e2e-cypress": "^3.0.5",
|
||||
"@vue/cli-plugin-eslint": "^3.0.5",
|
||||
"@vue/cli-plugin-pwa": "^3.0.5",
|
||||
"@vue/cli-plugin-unit-jest": "^3.0.5",
|
||||
"@vue/cli-service": "^3.0.5",
|
||||
"@vue/eslint-config-prettier": "^4.0.0",
|
||||
"@vue/test-utils": "^1.0.0-beta.20",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^23.6.0",
|
||||
"eslint": "^5.8.0",
|
||||
"eslint-plugin-vue": "^5.0.0-0",
|
||||
"node-sass": "^4.9.0",
|
||||
"sass-loader": "^7.0.1",
|
||||
"vue-cli-plugin-vuetify": "^0.4.5",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"@vue/prettier"
|
||||
],
|
||||
"rules": {},
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 10"
|
||||
],
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"jsx",
|
||||
"json",
|
||||
"vue"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.vue$": "vue-jest",
|
||||
".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
|
||||
"^.+\\.jsx?$": "babel-jest"
|
||||
},
|
||||
"moduleNameMapper": {
|
||||
"^@/(.*)$": "<rootDir>/src/$1"
|
||||
},
|
||||
"snapshotSerializers": [
|
||||
"jest-serializer-vue"
|
||||
],
|
||||
"testMatch": [
|
||||
"**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
|
||||
],
|
||||
"testURL": "http://localhost/"
|
||||
}
|
||||
}
|
||||
BIN
ayanova/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
ayanova/public/img/icons/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
ayanova/public/img/icons/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
ayanova/public/img/icons/apple-touch-icon-120x120.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
ayanova/public/img/icons/apple-touch-icon-152x152.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
ayanova/public/img/icons/apple-touch-icon-180x180.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
ayanova/public/img/icons/apple-touch-icon-60x60.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
ayanova/public/img/icons/apple-touch-icon-76x76.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
ayanova/public/img/icons/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
ayanova/public/img/icons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 555 B |
BIN
ayanova/public/img/icons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ayanova/public/img/icons/msapplication-icon-144x144.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
ayanova/public/img/icons/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
1
ayanova/public/img/icons/safari-pinned-tab.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
28
ayanova/public/index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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>ayanova</title>
|
||||
<!-- <link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"
|
||||
/> -->
|
||||
|
||||
<!--
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.2/css/all.css" integrity="sha384-/rXc/GQVaYpyDdyxK+ecHPVYJSN9bmVFBvjA/9eOB+pb3F2w2N6fc5qB9Ew5yIns" crossorigin="anonymous">
|
||||
-->
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong
|
||||
>AyaNova doesn't work without JavaScript enabled. Please enable it to
|
||||
continue.</strong
|
||||
>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
20
ayanova/public/manifest.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "ayanova",
|
||||
"short_name": "ayanova",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./img/icons/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"background_color": "#000000",
|
||||
"theme_color": "#4DBA87"
|
||||
}
|
||||
2
ayanova/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
96
ayanova/src/App.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<v-app id="inspire">
|
||||
<v-navigation-drawer v-if="isAuthenticated" fixed v-model="drawer" app>
|
||||
<v-list dense>
|
||||
<v-list-tile v-for="item in navItems" :key="item.route" :to="item.route">
|
||||
<v-list-tile-action>
|
||||
<v-icon>{{ "fa-" + item.icon }}</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
<v-toolbar v-if="isAuthenticated" color="primary" dark fixed app>
|
||||
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
|
||||
<v-toolbar-title style="width: 300px" class="ml-0 pl-3">
|
||||
<v-avatar size="32px" tile>
|
||||
<img :src="require('./assets/logo.svg')" alt="AyaNova">
|
||||
</v-avatar>
|
||||
<span class="hidden-sm-and-down">AyaNova</span>
|
||||
</v-toolbar-title>
|
||||
<v-text-field flat solo-inverted hide-details prepend-inner-icon="fa-search" label="Search"></v-text-field>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon v-bind:href="helpUrl" target="blank;">
|
||||
<v-icon>fa-question-circle</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<v-content>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout justify-center align-center>
|
||||
<router-view></router-view>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-content>
|
||||
<v-footer app color="primary" dark height="auto">
|
||||
<v-layout row wrap="" align-center>
|
||||
<v-flex xs12>
|
||||
<div class="ml-3">
|
||||
<a href="https://ayanova.com" target="_blank">AyaNova</a>
|
||||
({{version}}) {{copyright}}
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-footer>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import aboutInfo from "./utils/aboutinfo";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
data() {
|
||||
return {
|
||||
drawer: null
|
||||
};
|
||||
},
|
||||
// beforeCreate() {
|
||||
|
||||
// },
|
||||
mounted() {
|
||||
if (!this.$store.state.authenticated) {
|
||||
this.$router.replace({ name: "login" });
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setAuthenticated(status) {
|
||||
this.$store.state.authenticated = status;
|
||||
},
|
||||
logout() {
|
||||
this.$store.state.authenticated = false;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isAuthenticated() {
|
||||
return this.$store.state.authenticated === true;
|
||||
},
|
||||
navItems() {
|
||||
return this.$store.state.navItems;
|
||||
},
|
||||
copyright() {
|
||||
return aboutInfo.copyright;
|
||||
},
|
||||
version() {
|
||||
return aboutInfo.version;
|
||||
},
|
||||
helpUrl() {
|
||||
return this.$store.state.helpUrl;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
source: String
|
||||
}
|
||||
};
|
||||
</script>
|
||||
19
ayanova/src/api/apimeta.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/* xeslint-disable */
|
||||
import apiUtil from "./apiutil";
|
||||
|
||||
export default {
|
||||
fetchAPIInfo() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
//step 2: get it
|
||||
fetch(apiUtil.APIUrl("ServerInfo"), apiUtil.fetchGetOptions())
|
||||
.then(apiUtil.status)
|
||||
.then(apiUtil.json)
|
||||
.then(response => {
|
||||
resolve(response);
|
||||
})
|
||||
.catch(function(error) {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
141
ayanova/src/api/apiutil.js
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Xeslint-disable */
|
||||
import store from "../store";
|
||||
|
||||
var stringifyPrimitive = function(v) {
|
||||
switch (typeof v) {
|
||||
case "string":
|
||||
return v;
|
||||
|
||||
case "boolean":
|
||||
return v ? "true" : "false";
|
||||
|
||||
case "number":
|
||||
return isFinite(v) ? v : "";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
status(response) {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return Promise.resolve(response);
|
||||
} else {
|
||||
store.commit("logItem", "API error: " + response.statusText);
|
||||
return Promise.reject(new Error(response.statusText));
|
||||
}
|
||||
},
|
||||
json(response) {
|
||||
return response.json();
|
||||
},
|
||||
patchAuthorizedHeaders() {
|
||||
return {
|
||||
//Accept: "application/json, text/plain, */*",
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json-patch+json",
|
||||
Authorization: "Bearer " + store.state.apiToken
|
||||
};
|
||||
},
|
||||
postAuthorizedHeaders() {
|
||||
return {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + store.state.apiToken
|
||||
};
|
||||
},
|
||||
postUnAuthorizedHeaders() {
|
||||
return {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
},
|
||||
fetchPostNoAuthOptions(data) {
|
||||
return {
|
||||
method: "post",
|
||||
mode: "cors",
|
||||
headers: this.postUnAuthorizedHeaders(),
|
||||
body: JSON.stringify(data)
|
||||
};
|
||||
},
|
||||
fetchPostOptions(data) {
|
||||
return {
|
||||
method: "post",
|
||||
mode: "cors",
|
||||
headers: this.postAuthorizedHeaders(),
|
||||
body: JSON.stringify(data)
|
||||
};
|
||||
},
|
||||
fetchGetOptions() {
|
||||
/* GET WITH AUTH */
|
||||
return {
|
||||
method: "get",
|
||||
mode: "cors",
|
||||
headers: this.postAuthorizedHeaders()
|
||||
};
|
||||
},
|
||||
APIUrl(apiPath) {
|
||||
if ("" == store.state.apiUrl) {
|
||||
//construct the api url and store it
|
||||
//development location?
|
||||
if (
|
||||
window.location.hostname == "localhost" &&
|
||||
window.location.port == "8080"
|
||||
) {
|
||||
store.commit("setAPIURL", "http://localhost:7575/api/v8.0/");
|
||||
store.commit("setHelpURL", "http://localhost:7575/docs/");
|
||||
store.commit(
|
||||
"logItem",
|
||||
"apiutil::APIUrl -> setting to dev. mode: " + store.state.apiUrl
|
||||
);
|
||||
} else {
|
||||
//production location <protocol>//<hostname>:<port>/
|
||||
store.commit(
|
||||
"setHelpURL",
|
||||
window.location.protocol + "//" + window.location.host + "/docs/"
|
||||
);
|
||||
store.commit(
|
||||
"setAPIURL",
|
||||
window.location.protocol + "//" + window.location.host + "/api/v8.0/"
|
||||
);
|
||||
store.commit(
|
||||
"logItem",
|
||||
"apiutil::APIUrl -> setting to: " + store.state.apiUrl
|
||||
);
|
||||
}
|
||||
}
|
||||
return store.state.apiUrl + apiPath;
|
||||
},
|
||||
buildQuery(obj, sep, eq, name) {
|
||||
sep = sep || "&";
|
||||
eq = eq || "=";
|
||||
if (obj === null) {
|
||||
obj = undefined;
|
||||
}
|
||||
|
||||
if (typeof obj === "object") {
|
||||
return Object.keys(obj)
|
||||
.map(function(k) {
|
||||
var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
|
||||
if (Array.isArray(obj[k])) {
|
||||
return obj[k]
|
||||
.map(function(v) {
|
||||
return ks + encodeURIComponent(stringifyPrimitive(v));
|
||||
})
|
||||
.join(sep);
|
||||
} else {
|
||||
return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(sep);
|
||||
}
|
||||
|
||||
if (!name) return "";
|
||||
return (
|
||||
encodeURIComponent(stringifyPrimitive(name)) +
|
||||
eq +
|
||||
encodeURIComponent(stringifyPrimitive(obj))
|
||||
);
|
||||
}
|
||||
};
|
||||
28
ayanova/src/api/auth.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/* Xeslint-disable */
|
||||
import apiUtil from "./apiutil";
|
||||
import { processLogin, processLogout } from "../utils/authutil";
|
||||
|
||||
export default {
|
||||
async authenticate(login, password) {
|
||||
return fetch(
|
||||
apiUtil.APIUrl("auth"),
|
||||
apiUtil.fetchPostNoAuthOptions({
|
||||
login: login,
|
||||
password: password
|
||||
})
|
||||
)
|
||||
.then(apiUtil.status)
|
||||
.then(apiUtil.json)
|
||||
.then(processLogin)
|
||||
.then(() => {
|
||||
return Promise.resolve(true);
|
||||
}) //succeeded, nothing to return
|
||||
.catch(function(error) {
|
||||
processLogout();
|
||||
return Promise.reject(error);
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
processLogout();
|
||||
}
|
||||
};
|
||||
43
ayanova/src/api/locale.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/* xeslint-disable */
|
||||
import store from "../store";
|
||||
import apiUtil from "./apiutil";
|
||||
import _ from "../utils/libs/lodash.js";
|
||||
|
||||
export default {
|
||||
get(key) {
|
||||
// debugger;
|
||||
if (!_.has(store.state.localeText, key)) {
|
||||
return "?" + key + "?";
|
||||
}
|
||||
return store.state.localeText[key];
|
||||
},
|
||||
fetch(keys) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
//step 1: build an array of keys that we don't have already
|
||||
//Note: this will ensure only unique keys go into the store so it's safe to call this with dupes as can happen
|
||||
var needIt = [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (!_.has(store.state.localeText, keys[i])) {
|
||||
needIt.push(keys[i]);
|
||||
}
|
||||
}
|
||||
if (needIt.length == 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
//step 2: get it
|
||||
fetch(apiUtil.APIUrl("locale/subset"), apiUtil.fetchPostOptions(needIt))
|
||||
.then(apiUtil.status)
|
||||
.then(apiUtil.json)
|
||||
.then(response => {
|
||||
_.forEach(response.data, function(item) {
|
||||
store.commit("addLocaleText", item);
|
||||
});
|
||||
resolve();
|
||||
})
|
||||
.catch(function(error) {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
29
ayanova/src/api/pagedlist.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/* xeslint-disable */
|
||||
import apiUtil from "./apiutil";
|
||||
export default {
|
||||
fetch(route, listOptions) {
|
||||
// listOptions;
|
||||
|
||||
// var futureWithSortExampleListOptions = {
|
||||
// offset: 5,
|
||||
// limit: 5,
|
||||
// sortBy: "name",
|
||||
// descending: false
|
||||
// };
|
||||
// exampleListOptions;
|
||||
|
||||
var listUrl = route + "?" + apiUtil.buildQuery(listOptions);
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
fetch(apiUtil.APIUrl(listUrl), apiUtil.fetchGetOptions())
|
||||
.then(apiUtil.status)
|
||||
.then(apiUtil.json)
|
||||
.then(response => {
|
||||
resolve(response);
|
||||
})
|
||||
.catch(function(error) {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
1
ayanova/src/assets/bw-logo.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
ayanova/src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
1
ayanova/src/assets/logo.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
ayanova/src/assets/stock_vue_logo.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
1
ayanova/src/assets/stock_vue_logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>
|
||||
|
After Width: | Height: | Size: 539 B |
21
ayanova/src/components/HelloWorld.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-layout text-xs-center wrap="">
|
||||
<v-flex xs12>
|
||||
<v-img :src="require('../assets/logo.svg')" class="my-3" contain height="200"></v-img>
|
||||
</v-flex>
|
||||
<v-flex mb-4>
|
||||
<h1 class="display-2 font-weight-bold mb-3">Welcome to AyaNova</h1>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
204
ayanova/src/components/desertlist.vue
Normal file
@@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="desserts"
|
||||
:pagination.sync="pagination"
|
||||
:total-items="totalDesserts"
|
||||
:loading="loading"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template slot="items" slot-scope="props">
|
||||
<td>{{ props.item.name }}</td>
|
||||
<td class="text-xs-right">{{ props.item.calories }}</td>
|
||||
<td class="text-xs-right">{{ props.item.fat }}</td>
|
||||
<td class="text-xs-right">{{ props.item.carbs }}</td>
|
||||
<td class="text-xs-right">{{ props.item.protein }}</td>
|
||||
<td class="text-xs-right">{{ props.item.iron }}</td>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
//https://vuetifyjs.com/en/components/data-tables#example-server
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
totalDesserts: 0,
|
||||
desserts: [],
|
||||
loading: true,
|
||||
pagination: {},
|
||||
headers: [
|
||||
{
|
||||
text: "Dessert (100g serving)",
|
||||
align: "left",
|
||||
sortable: false,
|
||||
value: "name"
|
||||
},
|
||||
{ text: "Calories", value: "calories" },
|
||||
{ text: "Fat (g)", value: "fat" },
|
||||
{ text: "Carbs (g)", value: "carbs" },
|
||||
{ text: "Protein (g)", value: "protein" },
|
||||
{ text: "Iron (%)", value: "iron" }
|
||||
]
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
pagination: {
|
||||
handler() {
|
||||
this.getDataFromApi().then(data => {
|
||||
this.desserts = data.items;
|
||||
this.totalDesserts = data.total;
|
||||
});
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getDataFromApi().then(data => {
|
||||
this.desserts = data.items;
|
||||
this.totalDesserts = data.total;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getDataFromApi() {
|
||||
this.loading = true;
|
||||
return new Promise((resolve, reject) => {
|
||||
const { sortBy, descending, page, rowsPerPage } = this.pagination;
|
||||
|
||||
let items = this.getDesserts();
|
||||
const total = items.length;
|
||||
|
||||
if (this.pagination.sortBy) {
|
||||
items = items.sort((a, b) => {
|
||||
const sortA = a[sortBy];
|
||||
const sortB = b[sortBy];
|
||||
|
||||
if (descending) {
|
||||
if (sortA < sortB) return 1;
|
||||
if (sortA > sortB) return -1;
|
||||
return 0;
|
||||
} else {
|
||||
if (sortA < sortB) return -1;
|
||||
if (sortA > sortB) return 1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (rowsPerPage > 0) {
|
||||
items = items.slice((page - 1) * rowsPerPage, page * rowsPerPage);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
resolve({
|
||||
items,
|
||||
total
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
getDesserts() {
|
||||
return [
|
||||
{
|
||||
value: false,
|
||||
name: "Frozen Yogurt",
|
||||
calories: 159,
|
||||
fat: 6.0,
|
||||
carbs: 24,
|
||||
protein: 4.0,
|
||||
iron: "1%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Ice cream sandwich",
|
||||
calories: 237,
|
||||
fat: 9.0,
|
||||
carbs: 37,
|
||||
protein: 4.3,
|
||||
iron: "1%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Eclair",
|
||||
calories: 262,
|
||||
fat: 16.0,
|
||||
carbs: 23,
|
||||
protein: 6.0,
|
||||
iron: "7%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Cupcake",
|
||||
calories: 305,
|
||||
fat: 3.7,
|
||||
carbs: 67,
|
||||
protein: 4.3,
|
||||
iron: "8%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Gingerbread",
|
||||
calories: 356,
|
||||
fat: 16.0,
|
||||
carbs: 49,
|
||||
protein: 3.9,
|
||||
iron: "16%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Jelly bean",
|
||||
calories: 375,
|
||||
fat: 0.0,
|
||||
carbs: 94,
|
||||
protein: 0.0,
|
||||
iron: "0%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Lollipop",
|
||||
calories: 392,
|
||||
fat: 0.2,
|
||||
carbs: 98,
|
||||
protein: 0,
|
||||
iron: "2%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Honeycomb",
|
||||
calories: 408,
|
||||
fat: 3.2,
|
||||
carbs: 87,
|
||||
protein: 6.5,
|
||||
iron: "45%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "Donut",
|
||||
calories: 452,
|
||||
fat: 25.0,
|
||||
carbs: 51,
|
||||
protein: 4.9,
|
||||
iron: "22%"
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
name: "KitKat",
|
||||
calories: 518,
|
||||
fat: 26.0,
|
||||
carbs: 65,
|
||||
protein: 7,
|
||||
iron: "6%"
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
</style>
|
||||
26
ayanova/src/components/inventorypartassemblytop.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-5 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large color="secondary">fa-heart</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline">Part assembly</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Cras facilisis mi vitae nunc lobortis pharetra. Nulla volutpat tincidunt ornare.
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
|
||||
Nullam in aliquet odio. Aliquam eu est vitae tellus bibendum tincidunt. Suspendisse potenti.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
26
ayanova/src/components/inventoryparttop.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-5 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large color="secondary">fa-cannabis</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline">Parts</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Cras facilisis mi vitae nunc lobortis pharetra. Nulla volutpat tincidunt ornare.
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
|
||||
Nullam in aliquet odio. Aliquam eu est vitae tellus bibendum tincidunt. Suspendisse potenti.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
26
ayanova/src/components/inventorypotop.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-5 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large color="secondary">fa-crow</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline">Purchase orders</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Cras facilisis mi vitae nunc lobortis pharetra. Nulla volutpat tincidunt ornare.
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
|
||||
Nullam in aliquet odio. Aliquam eu est vitae tellus bibendum tincidunt. Suspendisse potenti.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
26
ayanova/src/components/inventorywarehousetop.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-5 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large color="secondary">fa-heart </v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline">Warehouses</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Cras facilisis mi vitae nunc lobortis pharetra. Nulla volutpat tincidunt ornare.
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
|
||||
Nullam in aliquet odio. Aliquam eu est vitae tellus bibendum tincidunt. Suspendisse potenti.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
69
ayanova/src/components/inventorywidgetedit.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<v-layout row justify-center>
|
||||
<v-dialog v-model="dialogdata.showeditdialog" persistent max-width="600px">
|
||||
<!-- <v-btn slot="activator" color="primary" dark>Open Dialog</v-btn> -->
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="headline">User Profile ID: {{dialogdata.recordId}}</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-container grid-list-md>
|
||||
<v-layout wrap>
|
||||
<v-flex xs12 sm6 md4>
|
||||
<v-text-field label="Legal first name*" required></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md4>
|
||||
<v-text-field label="Legal middle name" hint="example of helper text only on focus"></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md4>
|
||||
<v-text-field
|
||||
label="Legal last name*"
|
||||
hint="example of persistent helper text"
|
||||
persistent-hint
|
||||
required
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-text-field label="Email*" required></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-text-field label="Password*" type="password" required></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-select :items="['0-17', '18-29', '30-54', '54+']" label="Age*" required></v-select>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-autocomplete
|
||||
:items="['Skiing', 'Ice hockey', 'Soccer', 'Basketball', 'Hockey', 'Reading', 'Writing', 'Coding', 'Basejump']"
|
||||
label="Interests"
|
||||
multiple
|
||||
></v-autocomplete>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<small>*indicates required field</small>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="blue darken-1" flat @click="$emit('dialogclose')">Close</v-btn>
|
||||
<v-btn color="blue darken-1" flat @click="$emit('dialogclose')">Save</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
dialogdata: {
|
||||
showeditdialog: false,
|
||||
recordId: 0
|
||||
}
|
||||
},
|
||||
data: () => ({})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
222
ayanova/src/components/inventorywidgetlist.vue
Normal file
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<v-flex xs12 md12>
|
||||
<div>
|
||||
<v-toolbar flat>
|
||||
<v-toolbar-title>
|
||||
<v-icon large color="primary">fa-splotch</v-icon>
|
||||
<span class="hidden-sm-and-down">{{ lt("WidgetList")}}</span>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon @click="newItem()">
|
||||
<v-icon>fa-plus-circle</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon>
|
||||
<v-icon>fa-filter</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon @click="getDataFromApi()">
|
||||
<v-icon>fa-sync</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon>
|
||||
<v-icon>fa-ellipsis-v</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<WidgetEdit :dialogdata="dialogdata" v-on:dialogclose="dialogdata.showeditdialog=false"/>
|
||||
<v-data-table
|
||||
v-model="selected"
|
||||
:headers="headers"
|
||||
:items="Items"
|
||||
item-key="id"
|
||||
:pagination.sync="pagination"
|
||||
:total-items="totalItems"
|
||||
:loading="loading"
|
||||
:rows-per-page-items="rowsPerPageItems"
|
||||
:rows-per-page-text="lt('RowsPerPage')"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template slot="items" slot-scope="props">
|
||||
<td class="text-xs-left">{{ props.item.name | capitalize }}</td>
|
||||
<td class="text-xs-left">{{ props.item.serial }}</td>
|
||||
<td class="text-xs-left">{{ props.item.dollarAmount | currency }}</td>
|
||||
<td class="text-xs-left">{{ props.item.active | boolastext }}</td>
|
||||
<td class="text-xs-left">{{ props.item.roles }}</td>
|
||||
<td class="text-xs-left">{{ props.item.startDate | shortdate}}</td>
|
||||
<td class="text-xs-left">{{ props.item.endDate | shortdate }}</td>
|
||||
<td class="justify-center layout px-0">
|
||||
<v-icon small class="mr-3" @click="editItem(props.item)">fa-pencil-alt</v-icon>
|
||||
</td>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
/* eslint-disable */
|
||||
import localeText from "../api/locale";
|
||||
import pagedList from "../api/pagedlist";
|
||||
import WidgetEdit from "../components/inventorywidgetedit";
|
||||
export default {
|
||||
ltKeysRequired: [
|
||||
"Widget",
|
||||
"WidgetList",
|
||||
"CommonName",
|
||||
"WidgetSerial",
|
||||
"WidgetDollarAmount",
|
||||
"CommonActive",
|
||||
"WidgetRoles",
|
||||
"WidgetStartDate",
|
||||
"WidgetEndDate",
|
||||
"WidgetNotes",
|
||||
"RowsPerPage"
|
||||
],
|
||||
components: {
|
||||
WidgetEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogdata: {
|
||||
showeditdialog: false,
|
||||
recordId: 0
|
||||
},
|
||||
totalItems: 0,
|
||||
Items: [],
|
||||
loading: true,
|
||||
pagination: {},
|
||||
selected: [],
|
||||
rowsPerPageItems: [5, 10, 25, 99],
|
||||
rowsPerPageText: "blah per blah",
|
||||
headers: [
|
||||
{
|
||||
text: this.lt("CommonName"),
|
||||
value: "name"
|
||||
},
|
||||
{ text: this.lt("WidgetSerial"), value: "serial" },
|
||||
{ text: this.lt("WidgetDollarAmount"), value: "dollarAmount" },
|
||||
{ text: this.lt("CommonActive"), value: "active" },
|
||||
{ text: this.lt("WidgetRoles"), value: "roles" },
|
||||
{ text: this.lt("WidgetStartDate"), value: "startDate" },
|
||||
{ text: this.lt("WidgetEndDate"), value: "endDate" }
|
||||
]
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
pagination: {
|
||||
handler() {
|
||||
this.getDataFromApi();
|
||||
/*
|
||||
{
|
||||
descending: false,
|
||||
page: 1,
|
||||
rowsPerPage: 5,
|
||||
sortBy: "name",
|
||||
totalItems: 0
|
||||
}
|
||||
*/
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.rowsPerPageText = lt("RowsPerPage");
|
||||
this.getDataFromApi();
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
lt: function(key) {
|
||||
return localeText.get(key);
|
||||
},
|
||||
newItem() {
|
||||
this.dialogdata.recordId = -1;
|
||||
this.dialogdata.showeditdialog = true;
|
||||
},
|
||||
getDataFromApi() {
|
||||
// debugger;
|
||||
var listOptions = {
|
||||
offset: 0,
|
||||
limit: 5,
|
||||
sort: "name",
|
||||
asc:true
|
||||
};
|
||||
|
||||
if (this.pagination.rowsPerPage && this.pagination.rowsPerPage > 0) {
|
||||
listOptions.offset =
|
||||
(this.pagination.page - 1) * this.pagination.rowsPerPage;
|
||||
listOptions.limit = this.pagination.rowsPerPage;
|
||||
}
|
||||
listOptions.sort = this.pagination.sortBy;
|
||||
listOptions.asc=!this.pagination.descending;
|
||||
|
||||
this.loading = true;
|
||||
pagedList.fetch("Widget/ListWidgets", listOptions).then(res => {
|
||||
// debugger;
|
||||
this.loading = false;
|
||||
this.Items = res.data;
|
||||
this.totalItems = res.paging.count;
|
||||
});
|
||||
},
|
||||
editItem(item) {
|
||||
this.dialogdata.recordId = item.id;
|
||||
this.dialogdata.showeditdialog = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
//Example api response
|
||||
// {
|
||||
// "data": [
|
||||
// {
|
||||
// "id": 1,
|
||||
// "concurrencyToken": 2262471,
|
||||
// "ownerId": 1,
|
||||
// "name": "Handcrafted Wooden Bacon 23",
|
||||
// "serial": 1,
|
||||
// "dollarAmount": 25.42,
|
||||
// "active": true,
|
||||
// "roles": 8212,
|
||||
// "startDate": "2018-11-19T12:20:42.920058",
|
||||
// "endDate": "2018-11-19T15:37:47.053849",
|
||||
// "notes": "Voluptas assumenda laudantium nemo cupiditate. Quia voluptatem reiciendis et. Sit non error est. Tenetur provident nostrum. Voluptatem voluptatem et."
|
||||
// },
|
||||
// {
|
||||
// "id": 2,
|
||||
// "concurrencyToken": 2262494,
|
||||
// "ownerId": 1,
|
||||
// "name": "Ergonomic Soft Gloves 24",
|
||||
// "serial": 2,
|
||||
// "dollarAmount": 530.39,
|
||||
// "active": true,
|
||||
// "roles": 8212,
|
||||
// "startDate": "2018-11-19T12:17:32.488013",
|
||||
// "endDate": "2018-11-19T17:01:18.425666",
|
||||
// "notes": "Sed rerum minima blanditiis est. Praesentium consequatur numquam nostrum voluptatem libero dolores voluptatem et. Aut et nobis consectetur voluptatem minus. Ipsa nemo non in iste adipisci voluptatem. Minus consequatur in accusantium."
|
||||
// },
|
||||
// {
|
||||
// "id": 3,
|
||||
// "concurrencyToken": 2262518,
|
||||
// "ownerId": 1,
|
||||
// "name": "Fantastic Metal Computer 25",
|
||||
// "serial": 3,
|
||||
// "dollarAmount": 494.3,
|
||||
// "active": true,
|
||||
// "roles": 8212,
|
||||
// "startDate": "2018-11-19T13:06:47.437006",
|
||||
// "endDate": "2018-11-19T14:41:44.665721",
|
||||
// "notes": "Facere et ex. Ipsa aspernatur itaque maiores sint nulla esse incidunt. Architecto labore voluptatem dolore iusto ut."
|
||||
// }
|
||||
// ],
|
||||
// "paging": {
|
||||
// "count": 100,
|
||||
// "offset": 0,
|
||||
// "limit": 3,
|
||||
// "first": "http://localhost:7575/api/v8.0/Widget/ListWidgets?pageNo=1&pageSize=3",
|
||||
// "previous": null,
|
||||
// "next": "http://localhost:7575/api/v8.0/Widget/ListWidgets?pageNo=1&pageSize=3",
|
||||
// "last": "http://localhost:7575/api/v8.0/Widget/ListWidgets?pageNo=34&pageSize=3"
|
||||
// }
|
||||
// }
|
||||
145
ayanova/src/components/stock-HelloWorld.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-layout
|
||||
text-xs-center
|
||||
wrap
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-img
|
||||
:src="require('../assets/logo.svg')"
|
||||
class="my-3"
|
||||
contain
|
||||
height="200"
|
||||
></v-img>
|
||||
</v-flex>
|
||||
|
||||
<v-flex mb-4>
|
||||
<h1 class="display-2 font-weight-bold mb-3">
|
||||
Welcome to Vuetify
|
||||
</h1>
|
||||
<p class="subheading font-weight-regular">
|
||||
For help and collaboration with other Vuetify developers,
|
||||
<br>please join our online
|
||||
<a href="https://community.vuetifyjs.com" target="_blank">Discord Community</a>
|
||||
</p>
|
||||
</v-flex>
|
||||
|
||||
<v-flex
|
||||
mb-5
|
||||
xs12
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-3">What's next?</h2>
|
||||
|
||||
<v-layout justify-center>
|
||||
<a
|
||||
v-for="(next, i) in whatsNext"
|
||||
:key="i"
|
||||
:href="next.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ next.text }}
|
||||
</a>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
|
||||
<v-flex
|
||||
xs12
|
||||
mb-5
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-3">Important Links</h2>
|
||||
|
||||
<v-layout justify-center>
|
||||
<a
|
||||
v-for="(link, i) in importantLinks"
|
||||
:key="i"
|
||||
:href="link.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ link.text }}
|
||||
</a>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
|
||||
<v-flex
|
||||
xs12
|
||||
mb-5
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-3">Ecosystem</h2>
|
||||
|
||||
<v-layout justify-center>
|
||||
<a
|
||||
v-for="(eco, i) in ecosystem"
|
||||
:key="i"
|
||||
:href="eco.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ eco.text }}
|
||||
</a>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
ecosystem: [
|
||||
{
|
||||
text: "vuetify-loader",
|
||||
href: "https://github.com/vuetifyjs/vuetify-loader"
|
||||
},
|
||||
{
|
||||
text: "github",
|
||||
href: "https://github.com/vuetifyjs/vuetify"
|
||||
},
|
||||
{
|
||||
text: "awesome-vuetify",
|
||||
href: "https://github.com/vuetifyjs/awesome-vuetify"
|
||||
}
|
||||
],
|
||||
importantLinks: [
|
||||
{
|
||||
text: "Documentation",
|
||||
href: "https://vuetifyjs.com"
|
||||
},
|
||||
{
|
||||
text: "Chat",
|
||||
href: "https://community.vuetifyjs.com"
|
||||
},
|
||||
{
|
||||
text: "Made with Vuetify",
|
||||
href: "https://madewithvuetifyjs.com"
|
||||
},
|
||||
{
|
||||
text: "Twitter",
|
||||
href: "https://twitter.com/vuetifyjs"
|
||||
},
|
||||
{
|
||||
text: "Articles",
|
||||
href: "https://medium.com/vuetify"
|
||||
}
|
||||
],
|
||||
whatsNext: [
|
||||
{
|
||||
text: "Explore components",
|
||||
href: "https://vuetifyjs.com/components/api-explorer"
|
||||
},
|
||||
{
|
||||
text: "Select a layout",
|
||||
href: "https://vuetifyjs.com/layout/pre-defined"
|
||||
},
|
||||
{
|
||||
text: "Frequently Asked Questions",
|
||||
href: "https://vuetifyjs.com/getting-started/frequently-asked-questions"
|
||||
}
|
||||
]
|
||||
})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
106
ayanova/src/main.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import "@babel/polyfill";
|
||||
import "@fortawesome/fontawesome-free/css/all.css";
|
||||
import "typeface-roboto/index.css";
|
||||
import Vue from "vue";
|
||||
import "./plugins/vuetify";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import "./registerServiceWorker";
|
||||
import errorHandler from "./utils/errorhandler";
|
||||
import NProgress from "nprogress";
|
||||
import "nprogress/nprogress.css";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// ERROR HANDLING
|
||||
//
|
||||
Vue.config.errorHandler = errorHandler.handleVueError;
|
||||
window.onerror = errorHandler.handleGeneralError;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// AJAX LOADER INDICATOR
|
||||
//
|
||||
// Store a copy of the fetch function
|
||||
var _oldFetch = fetch;
|
||||
|
||||
// Create our new version of the fetch function
|
||||
window.fetch = function() {
|
||||
// Create hooks
|
||||
var fetchStart = new Event("fetchStart", {
|
||||
view: document,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
});
|
||||
var fetchEnd = new Event("fetchEnd", {
|
||||
view: document,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
});
|
||||
|
||||
// Pass the supplied arguments to the real fetch function
|
||||
var fetchCall = _oldFetch.apply(this, arguments);
|
||||
|
||||
// Trigger the fetchStart event
|
||||
document.dispatchEvent(fetchStart);
|
||||
|
||||
fetchCall
|
||||
.then(function() {
|
||||
// Trigger the fetchEnd event
|
||||
document.dispatchEvent(fetchEnd);
|
||||
})
|
||||
.catch(function() {
|
||||
// Trigger the fetchEnd event
|
||||
document.dispatchEvent(fetchEnd);
|
||||
});
|
||||
|
||||
return fetchCall;
|
||||
};
|
||||
|
||||
document.addEventListener("fetchStart", function() {
|
||||
// eslint-disable-next-line
|
||||
//console.log("Show spinner");
|
||||
NProgress.start();
|
||||
});
|
||||
|
||||
document.addEventListener("fetchEnd", function() {
|
||||
// eslint-disable-next-line
|
||||
//console.log("Hide spinner");
|
||||
NProgress.done();
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// FILTERS
|
||||
//
|
||||
Vue.filter("capitalize", function(value) {
|
||||
if (!value) return "";
|
||||
value = value.toString();
|
||||
return value.charAt(0).toUpperCase() + value.slice(1);
|
||||
});
|
||||
|
||||
Vue.filter("shortdate", function(value) {
|
||||
if (!value) return "";
|
||||
var dj = dayjs(value);
|
||||
return dj.format("YYYY-MM-DD hh:mm:ss A");
|
||||
});
|
||||
|
||||
Vue.filter("currency", function(value) {
|
||||
if (!value) return "";
|
||||
return "$" + value;
|
||||
});
|
||||
|
||||
Vue.filter("boolastext", function(value) {
|
||||
if (!value) return "";
|
||||
return value ? "Yes" : "Nope";
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// INSTANTIATE
|
||||
//
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount("#app");
|
||||
13
ayanova/src/plugins/vuetify.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import Vue from "vue";
|
||||
import Vuetify from "vuetify";
|
||||
import "vuetify/dist/vuetify.min.css";
|
||||
|
||||
Vue.use(Vuetify, {
|
||||
iconfont: "fa",
|
||||
theme: {
|
||||
primary: "#00205B",
|
||||
secondary: "#00843D",
|
||||
accent: "#ffff00",
|
||||
error: "#b71c1c"
|
||||
}
|
||||
});
|
||||
28
ayanova/src/registerServiceWorker.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from "register-service-worker";
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
"App is being served from cache by a service worker.\n" +
|
||||
"For more details, visit https://goo.gl/AFskqB"
|
||||
);
|
||||
},
|
||||
cached() {
|
||||
console.log("Content has been cached for offline use.");
|
||||
},
|
||||
updated() {
|
||||
console.log("New content is available; please refresh.");
|
||||
},
|
||||
offline() {
|
||||
console.log(
|
||||
"No internet connection found. App is running in offline mode."
|
||||
);
|
||||
},
|
||||
error(error) {
|
||||
console.error("Error during service worker registration:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
57
ayanova/src/router.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import Vue from "vue";
|
||||
import Router from "vue-router";
|
||||
import Home from "./views/Home.vue";
|
||||
//import { isLoggedIn, login, logout } from "./utils/auth";
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
export default new Router({
|
||||
mode: "history",
|
||||
base: process.env.BASE_URL,
|
||||
routes: [
|
||||
// {
|
||||
// path: "/",
|
||||
// redirect: {
|
||||
// name: "login"
|
||||
// }
|
||||
// },
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "login" */ "./views/login.vue")
|
||||
},
|
||||
// {
|
||||
// path: "/secure",
|
||||
// name: "secure",
|
||||
// component: () =>
|
||||
// import(/* webpackChunkName: "secure" */ "./views/secure.vue")
|
||||
// },
|
||||
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
name: "about",
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "about" */ "./views/About.vue")
|
||||
},
|
||||
{
|
||||
path: "/log",
|
||||
name: "log",
|
||||
component: () => import(/* webpackChunkName: "log" */ "./views/log.vue")
|
||||
},
|
||||
{
|
||||
path: "/inventory",
|
||||
name: "inventory",
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "inventory" */ "./views/inventory.vue")
|
||||
}
|
||||
]
|
||||
});
|
||||
64
ayanova/src/store.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import createPersistedState from "vuex-persistedstate";
|
||||
import _ from "./utils/libs/lodash.js";
|
||||
|
||||
const MaxLogLength = 100;
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
plugins: [createPersistedState()],
|
||||
state: {
|
||||
authenticated: false,
|
||||
apiUrl: "",
|
||||
helpUrl: "",
|
||||
apiToken: "-",
|
||||
userId: 0,
|
||||
roles: 0,
|
||||
localeText: {},
|
||||
navItems: [],
|
||||
logArray: []
|
||||
},
|
||||
mutations: {
|
||||
login(state, data) {
|
||||
// mutate state
|
||||
state.authenticated = data.authenticated;
|
||||
state.userId = data.userId;
|
||||
state.roles = data.roles;
|
||||
state.apiToken = data.apiToken;
|
||||
},
|
||||
logout(state) {
|
||||
state.apiToken = "-";
|
||||
state.authenticated = false;
|
||||
state.userId = 0;
|
||||
state.roles = 0;
|
||||
state.navItems = [];
|
||||
state.localeText = {};
|
||||
state.apiUrl = "";
|
||||
},
|
||||
addNavItem(state, data) {
|
||||
state.navItems.push(data);
|
||||
},
|
||||
addLocaleText(state, data) {
|
||||
state.localeText[data.key] = data.value;
|
||||
},
|
||||
setAPIURL(state, data) {
|
||||
state.apiUrl = data;
|
||||
},
|
||||
setHelpURL(state, data) {
|
||||
state.helpUrl = data;
|
||||
},
|
||||
logItem(state, msg) {
|
||||
msg = Date.now() + "|" + msg;
|
||||
state.logArray.push(msg);
|
||||
if (state.logArray.length > MaxLogLength) {
|
||||
state.logArray = _.drop(
|
||||
state.logArray,
|
||||
state.logArray.length - MaxLogLength
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {}
|
||||
});
|
||||
5
ayanova/src/utils/aboutinfo.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
version: "8.0.0-alpha.1",
|
||||
copyright:
|
||||
"Copyright © 1999-2018, Ground Zero Tech-Works Inc. All Rights Reserved"
|
||||
};
|
||||
71
ayanova/src/utils/authutil.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/* xeslint-disable */
|
||||
import decode from "jwt-decode";
|
||||
import store from "../store";
|
||||
import initialize from "./initialize";
|
||||
|
||||
export function processLogin(response) {
|
||||
//is token present?
|
||||
if (!response || !response.data || !response.data.token) {
|
||||
store.commit("logItem", "auth::processLogin -> response empty");
|
||||
return Promise.reject();
|
||||
}
|
||||
const token = decode(response.data.token);
|
||||
|
||||
if (!token || !token.iss) {
|
||||
store.commit("logItem", "auth::processLogin -> response token empty");
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
if (token.iss != "ayanova.com") {
|
||||
store.commit(
|
||||
"logItem",
|
||||
"auth::processLogin -> token invalid (iss): " + token.iss
|
||||
);
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
//Put app relevant items into vuex store so app can use them
|
||||
store.commit("login", {
|
||||
apiToken: response.data.token,
|
||||
authenticated: true,
|
||||
userId: Number(token.id),
|
||||
roles: token["ayanova/roles"]
|
||||
});
|
||||
|
||||
//Initialize the application
|
||||
initialize();
|
||||
store.commit(
|
||||
"logItem",
|
||||
"auth::processLogin -> User " + token.id + " logged in"
|
||||
);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
export function processLogout() {
|
||||
if (store.state.authenticated) {
|
||||
store.commit("logItem", "auth::processLogout -> User logged out");
|
||||
}
|
||||
store.commit("logout");
|
||||
}
|
||||
|
||||
export function isLoggedIn() {
|
||||
//const token = getToken();
|
||||
return !!store.state.apiToken && !isTokenExpired(store.state.apiToken);
|
||||
}
|
||||
|
||||
function getTokenExpirationDate(encodedToken) {
|
||||
const token = decode(encodedToken);
|
||||
if (!token.exp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const date = new Date(0);
|
||||
date.setUTCSeconds(token.exp);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
function isTokenExpired(token) {
|
||||
const expirationDate = getTokenExpirationDate(token);
|
||||
return expirationDate < new Date();
|
||||
}
|
||||
34
ayanova/src/utils/errorhandler.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/* xeslint-disable */
|
||||
import store from "../store";
|
||||
|
||||
function dealWithError(msg) {
|
||||
store.commit("logItem", msg);
|
||||
}
|
||||
export default {
|
||||
handleGeneralError(message, source, lineno, colno, error) {
|
||||
var msg = "GeneralError: \n" + message;
|
||||
if (source) {
|
||||
msg += "\nsource: " + source;
|
||||
}
|
||||
if (lineno) {
|
||||
msg += "\nlineno: " + lineno;
|
||||
}
|
||||
if (colno) {
|
||||
msg += "\ncolno: " + colno;
|
||||
}
|
||||
if (error) {
|
||||
msg += "\nerror: " + error;
|
||||
}
|
||||
dealWithError(msg);
|
||||
},
|
||||
handleVueError(err, vm, info) {
|
||||
var msg = "VueError: \n" + err;
|
||||
if (vm) {
|
||||
msg += "\nvm present ";
|
||||
}
|
||||
if (info) {
|
||||
msg += "\ninfo: " + info;
|
||||
}
|
||||
dealWithError(msg);
|
||||
}
|
||||
};
|
||||
90
ayanova/src/utils/initialize.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/* xeslint-disable */
|
||||
import store from "../store";
|
||||
import roles from "./roles";
|
||||
import lt from "../api/locale";
|
||||
|
||||
function addNavItem(title, icon, route) {
|
||||
store.commit("addNavItem", {
|
||||
title,
|
||||
icon,
|
||||
route
|
||||
});
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
// Initialize the app
|
||||
// on change of authentication status
|
||||
export default function initialize() {
|
||||
if (store.state.authenticated) {
|
||||
//fetch the required localized text keys into the cache
|
||||
lt.fetch([
|
||||
"Home",
|
||||
"Service",
|
||||
"Dispatch",
|
||||
"Inventory",
|
||||
"Accounting",
|
||||
"Administration",
|
||||
"Operations",
|
||||
"HelpAboutAyaNova",
|
||||
"Logout"
|
||||
])
|
||||
.then(function() {
|
||||
//put nav items into store
|
||||
//Everyone has a home
|
||||
addNavItem(lt.get("Home"), "home", "/");
|
||||
|
||||
if (
|
||||
roles.hasRole(roles.AuthorizationRoles.TechLimited) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.TechFull) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.SubContractorLimited) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.SubContractorFull)
|
||||
) {
|
||||
addNavItem(lt.get("Service"), "toolbox", "/service");
|
||||
}
|
||||
|
||||
if (
|
||||
roles.hasRole(roles.AuthorizationRoles.DispatchLimited) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.DispatchFull)
|
||||
) {
|
||||
addNavItem(lt.get("Dispatch"), "shipping-fast", "/dispatch");
|
||||
}
|
||||
|
||||
if (
|
||||
roles.hasRole(roles.AuthorizationRoles.InventoryLimited) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.InventoryFull)
|
||||
) {
|
||||
addNavItem(lt.get("Inventory"), "dolly", "/inventory");
|
||||
}
|
||||
|
||||
if (roles.hasRole(roles.AuthorizationRoles.AccountingFull)) {
|
||||
addNavItem(
|
||||
lt.get("Accounting"),
|
||||
"file-invoice-dollar",
|
||||
"/accounting"
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
roles.hasRole(roles.AuthorizationRoles.BizAdminLimited) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.BizAdminFull)
|
||||
) {
|
||||
addNavItem(lt.get("Administration"), "user-tie", "/admin");
|
||||
}
|
||||
|
||||
if (
|
||||
roles.hasRole(roles.AuthorizationRoles.OpsAdminFull) ||
|
||||
roles.hasRole(roles.AuthorizationRoles.OpsAdminLimited)
|
||||
) {
|
||||
addNavItem(lt.get("Operations"), "cogs", "ops");
|
||||
}
|
||||
|
||||
//Everyone can see about and logout
|
||||
addNavItem(lt.get("HelpAboutAyaNova"), "info-circle", "/about");
|
||||
addNavItem(lt.get("Logout"), "sign-out-alt", "/login");
|
||||
})
|
||||
.catch(function(error) {
|
||||
store.commit("logItem", "Initialize::() -> error" + error);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
17107
ayanova/src/utils/libs/lodash.js
Normal file
43
ayanova/src/utils/roles.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import store from "../store";
|
||||
export default {
|
||||
AuthorizationRoles: {
|
||||
///<summary>No role set</summary>
|
||||
NoRole: 0,
|
||||
///<summary>BizAdminLimited</summary>
|
||||
BizAdminLimited: 1,
|
||||
///<summary>BizAdminFull</summary>
|
||||
BizAdminFull: 2,
|
||||
///<summary>DispatchLimited</summary>
|
||||
DispatchLimited: 4,
|
||||
///<summary>DispatchFull</summary>
|
||||
DispatchFull: 8,
|
||||
///<summary>InventoryLimited</summary>
|
||||
InventoryLimited: 16,
|
||||
///<summary>InventoryFull</summary>
|
||||
InventoryFull: 32,
|
||||
///<summary>AccountingFull</summary>
|
||||
AccountingFull: 64, //No limited role, not sure if there is a need
|
||||
///<summary>TechLimited</summary>
|
||||
TechLimited: 128,
|
||||
///<summary>TechFull</summary>
|
||||
TechFull: 256,
|
||||
///<summary>SubContractorLimited</summary>
|
||||
SubContractorLimited: 512,
|
||||
///<summary>SubContractorFull</summary>
|
||||
SubContractorFull: 1024,
|
||||
///<summary>ClientLimited</summary>
|
||||
ClientLimited: 2048,
|
||||
///<summary>ClientFull</summary>
|
||||
ClientFull: 4096,
|
||||
///<summary>OpsAdminLimited</summary>
|
||||
OpsAdminLimited: 8192,
|
||||
///<summary>OpsAdminFull</summary>
|
||||
OpsAdminFull: 16384
|
||||
},
|
||||
hasRole(role) {
|
||||
if (!store.state.roles || store.state.roles === 0) {
|
||||
return false;
|
||||
}
|
||||
return role === (store.state.roles & role);
|
||||
}
|
||||
};
|
||||
160
ayanova/src/views/About.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<!-- <div class="about">
|
||||
|
||||
<h1>About AyaNova</h1>-->
|
||||
<v-layout row>
|
||||
<v-flex xs12 sm6 offset-sm3>
|
||||
<v-card>
|
||||
<v-toolbar>
|
||||
<v-avatar size="64px" tile>
|
||||
<img :src="require('../assets/bw-logo.svg')" alt="AyaNova">
|
||||
</v-avatar>
|
||||
<v-toolbar-title>{{ lt("HelpAboutAyaNova")}}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn large icon to="/log">
|
||||
<v-icon>fa-glasses</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<v-list two-line subheader>
|
||||
<v-subheader>{{ lt("ClientApp")}}</v-subheader>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("Version")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ clientInfo.version }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
<v-divider></v-divider>
|
||||
<v-list two-line subheader>
|
||||
<v-subheader>{{ lt("Server")}}</v-subheader>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("Version")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.serverVersion }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("SchemaVersion")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.dbSchemaVersion }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("ServerTime")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.serverLocalTime }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("TimeZone")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.serverTimeZone }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
<v-divider></v-divider>
|
||||
<v-list two-line subheader>
|
||||
<v-subheader>{{ lt("HelpLicense")}}</v-subheader>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("RegisteredUser")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.license.license.licensedTo }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("DatabaseID")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.license.license.dbId }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("LicenseSerial")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.license.license.keySerial }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("LicenseExpiration")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.license.license.licenseExpiration }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("SupportedUntil")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ serverInfo.license.license.maintenanceExpiration }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ lt("LicensedOptions")}}</v-list-tile-title>
|
||||
<v-list-tile-sub-title
|
||||
v-for="item in serverInfo.license.license.features"
|
||||
:key="item.Feature"
|
||||
>{{item.Feature}} {{item.Count ? item.Count : ""}}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* xeslint-disable */
|
||||
import apiMeta from "../api/apimeta";
|
||||
import aboutInfo from "../utils/aboutinfo";
|
||||
import lt from "../api/locale";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
serverInfo: { license: { license: {} } },
|
||||
clientInfo: {}
|
||||
};
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
lt.fetch([
|
||||
"HelpAboutAyaNova",
|
||||
"ClientApp",
|
||||
"Server",
|
||||
"Version",
|
||||
"SchemaVersion",
|
||||
"ServerTime",
|
||||
"TimeZone",
|
||||
"HelpLicense",
|
||||
"RegisteredUser",
|
||||
"DatabaseID",
|
||||
"LicenseSerial",
|
||||
"LicenseExpiration",
|
||||
"SupportedUntil",
|
||||
"LicensedOptions"
|
||||
]).then(() => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.clientInfo.version = aboutInfo.version;
|
||||
apiMeta
|
||||
.fetchAPIInfo()
|
||||
.then(response => {
|
||||
this.serverInfo = response.data;
|
||||
})
|
||||
.catch(function(error) {
|
||||
/* xeslint-disable-next-line */
|
||||
//console.log(error);
|
||||
//TODO: turn this into a general error handling method for every form
|
||||
//probablyo an error component with error message slot to fill in
|
||||
alert(error);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
lt: function(key) {
|
||||
return lt.get(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
13
ayanova/src/views/Home.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<HelloWorld/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from "../components/HelloWorld";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HelloWorld
|
||||
}
|
||||
};
|
||||
</script>
|
||||
89
ayanova/src/views/inventory.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<v-layout column wrap class="my-5" align-center>
|
||||
<v-flex xs12>
|
||||
<v-container grid-list-xl>
|
||||
<v-layout row wrap align-top>
|
||||
<WidgetList/>
|
||||
<WarehouseTop/>
|
||||
<POTop/>
|
||||
<PartTop/>
|
||||
<PartAssemblyTop/>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-0 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large color="accent">fa-lightbulb</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline text-xs-center">Material Design</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Cras facilisis mi vitae nunc lobortis pharetra. Nulla volutpat tincidunt ornare.
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
|
||||
Nullam in aliquet odio. Aliquam eu est vitae tellus bibendum tincidunt. Suspendisse potenti.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<!-- <v-layout align-center justify-center row fill-height>
|
||||
<WidgetTop/>
|
||||
<PartTop/>
|
||||
<PartAssemblyTop/>
|
||||
<WarehouseTop/>
|
||||
<POTop/>
|
||||
</v-layout>-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* Xeslint-disable */
|
||||
import WidgetList from "../components/inventorywidgetlist";
|
||||
import WarehouseTop from "../components/inventorywarehousetop";
|
||||
import POTop from "../components/inventorypotop";
|
||||
import PartTop from "../components/inventoryparttop";
|
||||
import PartAssemblyTop from "../components/inventorypartassemblytop";
|
||||
/*
|
||||
HMMM?? - Maybe top level category is "part" and inventory is a sub item like the rest since they all revolve around parts but are not all inventory
|
||||
*/
|
||||
|
||||
// - PART REQUESTS OVERVIEW ETC....
|
||||
// - PART ASSEMBLIES
|
||||
// - PART CATEGORIES
|
||||
// - PART WAREHOUSES
|
||||
// - PARTS
|
||||
// - Part inventory
|
||||
// - Part inventory adjustments
|
||||
|
||||
//import store from "../store";
|
||||
import lt from "../api/locale";
|
||||
//import _ from "../utils/libs/lodash.js";
|
||||
export default {
|
||||
components: {
|
||||
WidgetList,
|
||||
WarehouseTop,
|
||||
POTop,
|
||||
PartTop,
|
||||
PartAssemblyTop
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
//Cache all required lt keys
|
||||
var ltKeysRequired = ["Inventory"].concat(WidgetList.ltKeysRequired);
|
||||
lt.fetch(ltKeysRequired).then(() => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
lt: function(key) {
|
||||
return lt.get(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
42
ayanova/src/views/log.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<v-layout row>
|
||||
<v-flex>
|
||||
<h1>{{ lt("Log")}}</h1>
|
||||
<v-textarea v-model="logText" full-width readonly></v-textarea>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* xeslint-disable */
|
||||
|
||||
//import lt from "../api/locale";
|
||||
import store from "../store";
|
||||
import lt from "../api/locale";
|
||||
import _ from "../utils/libs/lodash.js";
|
||||
export default {
|
||||
data() {
|
||||
return { logText: "" };
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
lt.fetch(["Log"]).then(() => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
var outText = "";
|
||||
_.forEach(store.state.logArray, function(value) {
|
||||
outText += value + "\n";
|
||||
});
|
||||
this.logText = outText;
|
||||
},
|
||||
methods: {
|
||||
lt: function(key) {
|
||||
return lt.get(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
88
ayanova/src/views/login.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<v-container fluid>
|
||||
<v-layout row wrap="">
|
||||
<v-flex xs12 class="text-xs-center" mt-5 ml-5 pl-5>
|
||||
<v-img :src="require('../assets/logo.svg')" class="my-3" contain height="200"></v-img>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 offset-sm3 mt-3>
|
||||
<form>
|
||||
<v-layout column>
|
||||
<v-flex>
|
||||
<v-text-field
|
||||
name="username"
|
||||
v-model="input.username"
|
||||
prepend-icon="fa-user"
|
||||
label="User"
|
||||
required
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<v-text-field
|
||||
name="password"
|
||||
v-model="input.password"
|
||||
prepend-icon="fa-key"
|
||||
label="Password"
|
||||
type="password"
|
||||
required
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex class="text-xs-center" mt-1>
|
||||
<v-btn color="primary" v-on:click="login()">
|
||||
<v-icon>fa-sign-in-alt</v-icon>
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</form>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* xeslint-disable */
|
||||
import auth from "../api/auth";
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
input: {
|
||||
username: "manager",
|
||||
password: "l3tm3in"
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
login() {
|
||||
if (this.input.username != "" && this.input.password != "") {
|
||||
auth
|
||||
.authenticate(this.input.username, this.input.password)
|
||||
.then(() => {
|
||||
this.$router.replace({ name: "home" });
|
||||
})
|
||||
.catch(function(error) {
|
||||
/* xeslint-disable-next-line */
|
||||
//console.log(error);
|
||||
alert("login failed: " + error);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
next(() => {
|
||||
auth.logout();
|
||||
next();
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#login {
|
||||
width: 500px;
|
||||
border: 1px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
margin: auto;
|
||||
margin-top: 200px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
26
ayanova/src/views/secure.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div id="secure">
|
||||
<h1>Secure Area</h1>
|
||||
<p>
|
||||
This is a secure area
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Secure',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#secure {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #CCCCCC;
|
||||
padding: 20px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
10
ayanova/tests/e2e/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
plugins: ["cypress"],
|
||||
env: {
|
||||
mocha: true,
|
||||
"cypress/globals": true
|
||||
},
|
||||
rules: {
|
||||
strict: "off"
|
||||
}
|
||||
};
|
||||
21
ayanova/tests/e2e/plugins/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// https://docs.cypress.io/guides/guides/plugins-guide.html
|
||||
/* 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"
|
||||
});
|
||||
};
|
||||
8
ayanova/tests/e2e/specs/test.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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 App");
|
||||
});
|
||||
});
|
||||
25
ayanova/tests/e2e/support/commands.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// ***********************************************
|
||||
// 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) => { ... })
|
||||
20
ayanova/tests/e2e/support/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// 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')
|
||||
5
ayanova/tests/unit/.eslintrc.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
jest: true
|
||||
}
|
||||
};
|
||||
12
ayanova/tests/unit/example.spec.js
Normal file
@@ -0,0 +1,12 @@
|
||||
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, {
|
||||
propsData: { msg }
|
||||
});
|
||||
expect(wrapper.text()).toMatch(msg);
|
||||
});
|
||||
});
|
||||