fileupload and sync with backend

This commit is contained in:
Thomas Mack 2024-05-15 19:35:03 +02:00
parent 1e01ba7439
commit 01ae5558cc
20 changed files with 309 additions and 124 deletions

View File

@ -1,5 +1,17 @@
# billibox-vue # billibox-vue
Datenbank zur Verwaltung alter Kameras und Zubehör.
Authentifizierung erfolgt über Keycloak open-id-connect
Backend ist eine in node-js geschriebene Komponente, die JSON-Collections entgegen nimmt.
Die Daten werden zunächst lokal in einer IndexedDB vorgehalten und mit dem Backend asynchron gesichert.
Das Backend ist im Projekt billibox-fpg zu finden.
## Project setup ## Project setup
``` ```
npm install npm install

58
package-lock.json generated
View File

@ -18,7 +18,7 @@
"@fortawesome/vue-fontawesome": "^3.0.0-4", "@fortawesome/vue-fontawesome": "^3.0.0-4",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^0.26.1", "axios": "^0.26.1",
"bootstrap": "^5.1.3", "bootstrap": "^5.3.3",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"keycloak-js": "^17.0.1", "keycloak-js": "^17.0.1",
@ -1991,9 +1991,9 @@
"dev": true "dev": true
}, },
"node_modules/@popperjs/core": { "node_modules/@popperjs/core": {
"version": "2.11.4", "version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.4.tgz", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"peer": true, "peer": true,
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -4015,15 +4015,21 @@
"dev": true "dev": true
}, },
"node_modules/bootstrap": { "node_modules/bootstrap": {
"version": "5.1.3", "version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
"integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
"funding": { "funding": [
"type": "opencollective", {
"url": "https://opencollective.com/bootstrap" "type": "github",
}, "url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"peerDependencies": { "peerDependencies": {
"@popperjs/core": "^2.10.2" "@popperjs/core": "^2.11.8"
} }
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
@ -4179,9 +4185,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001322", "version": "1.0.30001524",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz",
"integrity": "sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew==", "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -4191,6 +4197,10 @@
{ {
"type": "tidelift", "type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite" "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
} }
] ]
}, },
@ -13785,9 +13795,9 @@
"dev": true "dev": true
}, },
"@popperjs/core": { "@popperjs/core": {
"version": "2.11.4", "version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.4.tgz", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"peer": true "peer": true
}, },
"@sideway/address": { "@sideway/address": {
@ -15377,9 +15387,9 @@
"dev": true "dev": true
}, },
"bootstrap": { "bootstrap": {
"version": "5.1.3", "version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
"integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
"requires": {} "requires": {}
}, },
"brace-expansion": { "brace-expansion": {
@ -15487,9 +15497,9 @@
} }
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001322", "version": "1.0.30001524",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz",
"integrity": "sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew==", "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==",
"dev": true "dev": true
}, },
"case-sensitive-paths-webpack-plugin": { "case-sensitive-paths-webpack-plugin": {

View File

@ -18,7 +18,7 @@
"@fortawesome/vue-fontawesome": "^3.0.0-4", "@fortawesome/vue-fontawesome": "^3.0.0-4",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^0.26.1", "axios": "^0.26.1",
"bootstrap": "^5.1.3", "bootstrap": "^5.3.3",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"keycloak-js": "^17.0.1", "keycloak-js": "^17.0.1",

View File

@ -1,6 +1,4 @@
<template> <template>
<router-view></router-view> <router-view></router-view>
</template> </template>

View File

@ -7,7 +7,7 @@
<router-link to="/list" class="nav-link">Startseite</router-link> <router-link to="/list" class="nav-link">Startseite</router-link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<router-link to="/shop/item/create" class="nav-link">Neue Kamera</router-link> <router-link to="/admin/camera/create" class="nav-link">Neue Kamera</router-link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<router-link to="/auth" class="nav-link">Auth</router-link> <router-link to="/auth" class="nav-link">Auth</router-link>

View File

@ -1,14 +1,31 @@
<template> <template>
<form @submit="submitFile">
<div> <div class="form-row">
<div class="form-group col-md-8 offset-2">
<label for="fileUpload">Datei</label> <label for="fileDescription">Beschreibung</label>
<input id="fileUpload" type="file" <input id="fileDescription" name="description" type="text"
@change="handleFileUpload( $event) " /><br>
/><br> </div>
<button v-on:click="submitFile()">Upload</button> </div>
</div> <div class="form-row">
<div class="form-group col-md-8 offset-2">
<label class="form-label" for="fileUpload">Datei</label>
<input class="form-control" id="fileUpload" name="file" type="file"
@change="handleFileUpload( $event) "
/><br>
</div>
</div>
<div class="form-row mt-3">
<div class="form-group col-md-8 offset-2">
<div class="d-grid">
<button class="btn bg-vue">
<span v-if="!isLoading">Hochladen</span>
<span v-else class="spinner-border spinner-border-sm"></span>
</button>
</div>
</div>
</div>
</form>
</template> </template>
<script> <script>
@ -17,7 +34,16 @@ import axios from 'axios';
export default { export default {
name: "FileUpload", name: "FileUpload",
props: {
store: {
type: Object,
required: true
},
activeStore: {
type: String,
required: true
}
},
data() { data() {
return { return {
@ -28,9 +54,10 @@ export default {
handleFileUpload(event) { handleFileUpload(event) {
this.file = event.target.files[0]; this.file = event.target.files[0];
}, },
submitFile() { submitFile(event) {
let formData = new FormData(); event.preventDefault();
formData.append('file',this.file); const form = event.target;
let formData = new FormData(form);
localStorage.debug = "axios"; localStorage.debug = "axios";
const api = axios.create({baseURL: 'http://127.0.0.1:4000'}) const api = axios.create({baseURL: 'http://127.0.0.1:4000'})
const apiLogger = require('debug')('api'); const apiLogger = require('debug')('api');
@ -48,6 +75,13 @@ export default {
).then((res) => { ).then((res) => {
console.log("FileUpload Success", res.data); console.log("FileUpload Success", res.data);
console.log("StoreID Success", this.store.id)
const uploadItem = {key: res.data.rows[0].key, value: res.data.rows[0].value};
this.$store.dispatch("insertNameKeyObject", {
storeType: this.store.id,
item: uploadItem
})
}).catch((err) => { }).catch((err) => {
console.log(err); console.log(err);
}) })

View File

@ -11,14 +11,13 @@
@click="toggleNew" @click="toggleNew"
class="billi-store-add billi-close billi-secondary" icon="xmark"/> class="billi-store-add billi-close billi-secondary" icon="xmark"/>
<transition <transition
enter-active-class="animate__animated animate__fadeInDown" enter-active-class="animate__animated animate__fadeInDown"
leave-active-class="animate__animated animate__fadeOutUp" leave-active-class="animate__animated animate__fadeOutUp"
mode="out-in" mode="out-in"
appear appear
> >
<section class="billi-store-edit" v-if="add && isActive"> <section class="billi-store-edit" v-if="add && isActive && this.store.type !== 'filestore'">
<Form @submit="submitData" :validation-schema="schema" v-slot="{ errors }"> <Form @submit="submitData" :validation-schema="schema" v-slot="{ errors }">
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-8 offset-2"> <div class="form-group col-md-8 offset-2">
@ -84,7 +83,7 @@
</transition> </transition>
<section class="billi-store-edit" v-if="add && isActive && this.store.type === 'filestore'"> <section class="billi-store-edit" v-if="add && isActive && this.store.type === 'filestore'">
<FileUpload></FileUpload> <FileUpload :active-store="activeStore" :store="store" ></FileUpload>
</section> </section>
</section> </section>

15
src/config/index.ts Normal file
View File

@ -0,0 +1,15 @@
import {urlComponents} from "@/types";
export const backendAPI:urlComponents = {
host : 'localhost',
port : 4000,
protocol : 'http'
}
export const port = process.env.PORT || 3000;
export const indexDB = {
id: 'billibox',
version: 3
}

View File

@ -1,11 +1,16 @@
import axios from "axios";
import {collectionExists, createCollection, putItem} from "@/store/backend";
import {DatabaseItem, NameKeyStore} from "@/store/interfaces/NameKeyStore";
export default class BilliDB { export default class BilliDB {
DB_VERSION: number; DB_VERSION: number;
DB_NAME: string; DB_NAME: string;
constructor(dbName:string, dbVersion:number) { BACKEND_URL: string;
constructor(dbName:string, dbVersion:number, backendUrl:string) {
this.DB_NAME = dbName; this.DB_NAME = dbName;
this.DB_VERSION = dbVersion; this.DB_VERSION = dbVersion;
this.BACKEND_URL = backendUrl;
} }
@ -57,8 +62,33 @@ export default class BilliDB {
async saveItem(item, storeId:string) { async saveItem(item, storeId:string) {
const db = await this.getDb(); console.log("-->saveItem", storeId, item);
const itemClean = {...item}
console.log("-->saveItem clean", storeId, itemClean);
const request = window.indexedDB.open(this.DB_NAME, this.DB_VERSION);
request.onsuccess = (event) => {
console.log("DB Request done");
const transaction = request.result
.transaction([storeId], 'readwrite');
const objectStore = transaction.objectStore(storeId);
const requestUpdate = objectStore.put(itemClean);
requestUpdate.onsuccess = (event) => {
console.log("Data update complete")
}
transaction.oncomplete = (event) => {
console.log("Transaction complete")
}
}
request.onerror = (err) => {
console.log("DB Error" , err)
}
/**
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
console.log("Starting Add Transaction"); console.log("Starting Add Transaction");
@ -87,6 +117,7 @@ export default class BilliDB {
console.log("onsuccess on Store", e) console.log("onsuccess on Store", e)
} }
}) })
*/
} }
async saveItems(items, storeId:string) { async saveItems(items, storeId:string) {
const db = await this.getDb(); const db = await this.getDb();
@ -159,6 +190,70 @@ export default class BilliDB {
} }
}) })
} }
async syncDatabase(storeId:string) {
console.log("-->syncDatabase");
let db;
const request = window.indexedDB.open(this.DB_NAME, this.DB_VERSION);
request.onsuccess = (event) => {
if (navigator.onLine) {
db = request.result;
console.log("..onsuccess", db)
for(const collection of db.objectStoreNames) {
console.log("working on: ", collection);
createCollection(collection).then( exist => {
console.log(exist);
const transaction = db.transaction(collection,'readwrite');
const objectStore = transaction.objectStore(collection);
console.log("working on objectstore: ", objectStore);
const cursorRequest = objectStore.openCursor();
cursorRequest.onsuccess = (e) => {
const cursor = e.target.result;
if(cursor) {
const value = cursor.value;
console.log(cursor.key, cursor.value, value);
putItem(collection, value);
cursor.continue();
} else {
console.log("no cursor");
}
}
cursorRequest.onerror = (err) => {
console.log("cursor error", err);
}
}).catch(err => {
console.log(err);
});
}
/**
const objectStore = transaction.objectStore('brand111s');
const cursorRequest = objectStore.openCursor();
cursorRequest.onsuccess = (e) => {
const cursor = e.target.result;
if (cursor) {
console.log("Cursor: ", cursor.value());
// axios.put('', cursor.value())
// Perform synchronization logic here
cursor.continue();
}
}
*/
}
}
// Test if we have connection to the Internet
}
} }

View File

@ -3,6 +3,7 @@ import App from './App.vue'
import store from './store'; import store from './store';
import router from './router' import router from './router'
import VueKeyCloak from '@dsb-norge/vue-keycloak-js' import VueKeyCloak from '@dsb-norge/vue-keycloak-js'
import 'bootstrap/dist/css/bootstrap.css'
import { KeycloakInstance } from "keycloak-js"; import { KeycloakInstance } from "keycloak-js";
import { VueKeycloakInstance } from "@dsb-norge/vue-keycloak-js/dist/types"; import { VueKeycloakInstance } from "@dsb-norge/vue-keycloak-js/dist/types";
@ -23,6 +24,8 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
library.add(faUserSecret); library.add(faUserSecret);
const SKIP_KEYCLOAK = false;
// //
// //
@ -46,12 +49,12 @@ createApp(App);
app.use(store) app.use(store)
app.use(router) app.use(router)
app.component("font-awesome-icon", FontAwesomeIcon); app.component("font-awesome-icon", FontAwesomeIcon);
app.use(VueKeyCloak, { if (!SKIP_KEYCLOAK) app.use(VueKeyCloak, {
config: { config: {
url: 'https://auth.toking.de/', url: 'https://auth.toking.de/',
realm: 'toking', realm: 'toking',
clientId: 'billibox', clientId: 'billibox',
redirectUri: 'http://127.0.0.1:8080/', redirectUri: 'http://127.0.0.1:8081/',
onLoad: 'login-required', onLoad: 'login-required',
enableLogging: true, enableLogging: true,
scope: 'open-id' scope: 'open-id'
@ -82,52 +85,3 @@ declare module '@vue/runtime-core' {
$keycloak: VueKeycloakInstance $keycloak: VueKeycloakInstance
} }
} }
// import Vue from 'vue';
// import App from './App.vue';
// import Keycloak from "keycloak-js";
// const initOptions = {
// url: 'https://auth.toking.de/', realm: 'toking', clientId: 'billibox', onLoad: 'login-required',
// redirectUri: 'http://127.0.0.1:8080/'
// };
// //const app = createApp(App);
// const keycloak = Keycloak(initOptions);
// keycloak.init({ onLoad: 'login-required', redirectUri: 'http://127.0.0.1:8080/' }).then((auth) => {
// if (!auth) {
// window.location.reload();
// }
// else {
// // @ts-ignore
// console.info("Authenticated", auth);
// // @ts-ignore
//
// new Vue({
// el: '#app',
// render: h => h(App, { props: { keycloak: keycloak } })
// });
// }
// //Token Refresh
// // setInterval(() => {
// // keycloak.updateToken(70).then((refreshed) => {
// // if (refreshed) {
// // // @ts-ignore
// //
// // console.info('Token refreshed' + refreshed);
// // }
// // else {
// // // @ts-ignore
// //
// // console.warn('Token not refreshed, valid for '
// // + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');
// // }
// // }).catch(() => {
// // // @ts-ignore
// //
// // console.error('Failed to refresh token');
// // });
// // }, 6000);
// }).catch(() => {
// // @ts-ignore
//
// console.error("Authenticated Failed");
// });

View File

@ -62,6 +62,7 @@ export default {
else return ['alert-secondary']; else return ['alert-secondary'];
}, },
setActiveStore(key) { setActiveStore(key) {
console.log("setting Active store to: ", key);
this.activeStore = key this.activeStore = key
} }
} }

View File

@ -1,22 +1,22 @@
import CreateCameraPage from "@/pages/CreateCameraPage.vue"; import CreateCameraPage from "@/pages/CreateCameraPage.vue";
import ReadNameKeyPage from "@/pages/ReadNameKeyPage.vue"; import ReadNameKeyPage from "@/pages/ReadNameKeyPage.vue";
const shopRoutes = [ const shopRoutes = [
{ // {
path: "/admin/camera/create", // path: "/admin/camera/create",
component: CreateCameraPage, // component: CreateCameraPage,
meta: { // meta: {
requiresAuth: true // requiresAuth: true
}, // },
}, // },
{ // {
path: "/admin/namekey", // path: "/admin/namekey",
component: ReadNameKeyPage, // component: ReadNameKeyPage,
props: true, // props: true,
meta: { // meta: {
requiresAuth: false, // requiresAuth: false,
// enterTransition: "rubberBand" // // enterTransition: "rubberBand"
} // }
}, // },
]; ];
export default shopRoutes; export default shopRoutes;
//# sourceMappingURL=admin-routes.js.map //# sourceMappingURL=admin-routes.js.map

View File

@ -142,7 +142,7 @@ export const brands = [
description: 'APS-Kameras, Digitalkameras, Kleinbildkameras, Mittelformatkameras.' description: 'APS-Kameras, Digitalkameras, Kleinbildkameras, Mittelformatkameras.'
}, },
{key: 'fandolfi', name: 'Gandolfi', description: 'Großformatkameras.'}, {key: 'fandolfi', name: 'Gandolfi', description: 'Großformatkameras.'},
{key: 'fottschalt', name: 'Gottschalt', description: 'Fachkameras.'}, {key: 'gottschalt', name: 'Gottschalt', description: 'Fachkameras.'},
{key: 'hasselblad', name: 'Hasselblad', description: 'Kleinbildkameras, Mittelformatkameras.'}, {key: 'hasselblad', name: 'Hasselblad', description: 'Kleinbildkameras, Mittelformatkameras.'},
{key: 'hitachi', name: 'Hitachi', description: 'Digitalkameras.'}, {key: 'hitachi', name: 'Hitachi', description: 'Digitalkameras.'},
{key: 'hewlett-Packard (HP)', name: 'Hewlett-Packard (HP)', description: 'Digitalkameras.'}, {key: 'hewlett-Packard (HP)', name: 'Hewlett-Packard (HP)', description: 'Digitalkameras.'},
@ -300,7 +300,7 @@ export const manufacturers = [
description: 'APS-Kameras, Digitalkameras, Kleinbildkameras, Mittelformatkameras.' description: 'APS-Kameras, Digitalkameras, Kleinbildkameras, Mittelformatkameras.'
}, },
{key: 'fandolfi', name: 'Gandolfi', description: 'Großformatkameras.'}, {key: 'fandolfi', name: 'Gandolfi', description: 'Großformatkameras.'},
{key: 'fottschalt', name: 'Gottschalt', description: 'Fachkameras.'}, {key: 'gottschalt', name: 'Gottschalt', description: 'Fachkameras.'},
{key: 'hasselblad', name: 'Hasselblad', description: 'Kleinbildkameras, Mittelformatkameras.'}, {key: 'hasselblad', name: 'Hasselblad', description: 'Kleinbildkameras, Mittelformatkameras.'},
{key: 'hitachi', name: 'Hitachi', description: 'Digitalkameras.'}, {key: 'hitachi', name: 'Hitachi', description: 'Digitalkameras.'},
{key: 'hewlett-Packard (HP)', name: 'Hewlett-Packard (HP)', description: 'Digitalkameras.'}, {key: 'hewlett-Packard (HP)', name: 'Hewlett-Packard (HP)', description: 'Digitalkameras.'},

View File

@ -0,0 +1,39 @@
import axios from "axios";
import {backendAPI, indexDB} from "@/config";
import Util from "@/util";
import {DatabaseItem} from "@/store/interfaces/NameKeyStore";
export async function collectionExists(collectionName: string) {
const apiBase = Util.getURL(backendAPI);
const endpoint = `${apiBase}/pgadmin/${indexDB.id}/${collectionName}`;
try {
const rawResult = await axios.get(endpoint);
return true;
} catch (e) {
return false;
}
}
export async function createCollection(collectionName: string) {
const apiBase = Util.getURL(backendAPI);
const endpoint = `${apiBase}/pgadmin/${indexDB.id}/${collectionName}`;
try {
const rawResult = await axios.post(endpoint);
return true;
} catch (e) {
return false;
}
}
export async function putItem(collectionName: string, item:DatabaseItem) {
console.log("-->putItem", item);
const apiBase = Util.getURL(backendAPI);
const endpoint = `${apiBase}/pg/${indexDB.id}/${collectionName}/${item.key}`;
try {
const rawResult = await axios.put(endpoint,item);
return rawResult.data;
} catch (e) {
return false;
}
}

View File

@ -1,6 +1,11 @@
interface NameKeyStore { export interface NameKeyStore {
name:string; name:string;
id:string; id:string;
identifier:string; identifier:string;
type:( "nameKey" | "filestore" | "object") type:( "nameKey" | "filestore" | "object")
} }
export interface DatabaseItem {
key:string,
value:object,
lastchanged?:Date
}

View File

@ -203,10 +203,11 @@ const mutations = {
const actions = { const actions = {
storeNameKeyObject(context, payload) { storeNameKeyObject(context, payload) {
console.log("actions.storeNameKeyObject", payload); console.log("actions.storeNameKeyObject", payload);
db.saveItem(payload.item, payload.storeType).then((res) => {
db.saveItem(payload, payload.storeType).then((res) => {
console.log("Item stored in Database"); console.log("Item stored in Database");
}); });
context.commit("storeNameKey", payload.item); context.commit("storeNameKey", {...payload});
}, },
insertNameKeyObject(context, payload) { insertNameKeyObject(context, payload) {
console.log("actions.insertNameKeyObject", payload); console.log("actions.insertNameKeyObject", payload);
@ -289,6 +290,7 @@ const actions = {
} }
else { else {
console.log("SEEDING skipped"); console.log("SEEDING skipped");
db.syncDatabase();
context.dispatch("loadDataFromLocalDB") context.dispatch("loadDataFromLocalDB")
.then(() => console.log("Store Data loaded")) .then(() => console.log("Store Data loaded"))
.catch((e) => console.log("Error loading StoreData", e)); .catch((e) => console.log("Error loading StoreData", e));

View File

@ -8,9 +8,12 @@ import InventoryItem from "@/store/classes/InventoryItem";
import Camera from "@/store/classes/Camera"; import Camera from "@/store/classes/Camera";
import Lens from "@/store/classes/Lens"; import Lens from "@/store/classes/Lens";
import InventorySet from "@/store/classes/InventorySet"; import InventorySet from "@/store/classes/InventorySet";
import {backendAPI, indexDB} from "@/config";
import Util from "@/util";
import {NameKeyStore} from "@/store/interfaces/NameKeyStore";
const db = new BilliDB("billibox", 3); const db = new BilliDB(indexDB.id, 3, Util.getURL(backendAPI));
const stores:NameKeyStore[] = [ const stores:NameKeyStore[] = [
@ -147,7 +150,8 @@ const mutations = {
}, },
storeNameKey(state:any, payload:any) { storeNameKey(state:any, payload:any) {
const objNK:NameKey = state[payload.storeType].find( (item) => item.key === payload.itemOld.key); console.log("mutation.storeNameKey", state, payload.storeType);
const objNK:NameKey = state[payload.storeType].find( (item) => item.key === payload.item.key);
if(objNK.key) objNK.key = payload.item.key; if(objNK.key) objNK.key = payload.item.key;
objNK.name = payload.item.name; objNK.name = payload.item.name;
objNK.description = payload.item.description; objNK.description = payload.item.description;
@ -160,7 +164,7 @@ const mutations = {
}, },
setItemActiveState(state:any, payload:any) { setItemActiveState(state:any, payload:any) {
console.log("mutation.setItemActiveState"); console.log("mutation.setItemActiveState");
state.inventory.map((item:InventoryItem) => item.active= false); state.inventory.map((item:InventoryItem) => item.active= false);
const objItem = state.inventory.find((itemId:InventoryItem) => itemId.key === payload.key); const objItem = state.inventory.find((itemId:InventoryItem) => itemId.key === payload.key);
@ -257,7 +261,7 @@ const actions = {
console.log("Item stored in Database") console.log("Item stored in Database")
}) })
context.commit("storeNameKey", payload.item); context.commit("storeNameKey", {...payload});
}, },
@ -367,6 +371,7 @@ const actions = {
localStorage.setItem("SEED_VERSION", seed.SEED_VERSION.toString()) localStorage.setItem("SEED_VERSION", seed.SEED_VERSION.toString())
} else { } else {
console.log("SEEDING skipped"); console.log("SEEDING skipped");
db.syncDatabase("test");
context.dispatch("loadDataFromLocalDB") context.dispatch("loadDataFromLocalDB")
.then(() => console.log("Store Data loaded")) .then(() => console.log("Store Data loaded"))
.catch((e) => console.log("Error loading StoreData", e)); .catch((e) => console.log("Error loading StoreData", e));

5
src/types/index.ts Normal file
View File

@ -0,0 +1,5 @@
export interface urlComponents {
host: string,
port: number,
protocol: 'http'|'https'
}

11
src/util/index.ts Normal file
View File

@ -0,0 +1,11 @@
import {urlComponents} from "@/types";
export default class Util {
public static getURL(components:urlComponents) {
return `${components.protocol}://${components.host}${(components.port)?':'+components.port:''}`;
}
}