Compare commits

..

1 Commits

Author SHA1 Message Date
HerrHase 078627d9cd adding
2 years ago

10
.gitignore vendored

@ -122,4 +122,12 @@ dist
/bin
/dist
/build
/out
# Neutralinojs client (minified)
neutralino.js
# Neutralinojs related files
.storage
*.log
.tmp/*

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 Björn Hase <me@herr-hase.wtf>
Copyright (c) 2021 Neutralinojs and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

@ -1,19 +1,12 @@
# Potato launcher
There are many Launchers for Desktops and they are all fancy. But this one
is damn simple, no fancy dancy functions only add Apps from your file
system or use commands. Each entry can have a description, tags and also an
image. Easy Filtering and Sort by name or last Time you started a App.
I know there a many Launcher on the Market, and they are all damn Beautiful, this
App is not Beautiful, it's only starts App, it is really simple, no fancy dancy Functions.
This Launcher used [Electron](https://www.electronjs.org/), [Riot.js](https://riot.js.org/), [Plain UI](https://plain-ui.com) and [Pouchdb](https://pouchdb.com/).
## Why Electron?
Electron was not the first choice, but it works, and with [Electron Forge](https://www.electronforge.io/) there many possibilities
for deploying. But Electron is also known for his need of resources. But there is a Branch for [neutralino.js](https://neutralino.js.org/),
there will be another attempt to use neutralino.js, because it is more lightweight.
And it is not finish!
## Next Goals
* Keyboard- and Controller-Support for navigation
* Kiosk-Mode
* Change Format of Images
* Adding Function to Filter Results
* Keyboard- and Controller-Control

Binary file not shown.

Binary file not shown.

@ -0,0 +1,81 @@
const minimist = require('minimist')
const WS = require('websocket').w3cwebsocket
const { v4: uuidv4 } = require('uuid')
/**
* connector creating client and routing to handlers
*
* @author Björn Hase
* @license https://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
*/
class Connector {
/**
* getting
*
*
* @param {object} handlers
*
*/
constructor(handlers) {
this.handlers = handlers
// getting arguments
const argv = minimist(process.argv.slice(2))
this.NL_PORT = argv['nl-port']
this.NL_TOKEN = argv['nl-token']
this.NL_EXTID = argv['nl-extension-id']
// create socket connection for receive and send events
this.client = new WS(`ws://localhost:${this.NL_PORT}?extensionId=${this.NL_EXTID}`)
// add events for on message to
this.client.onmessage = (event) => {
this.handleMessage(event)
}
}
/**
* send to app
*
* @param {string} eventName
* @param {array} data
*
*/
send(eventName, data) {
this.client.send(JSON.stringify({
id: uuidv4(),
method: 'app.broadcast',
accessToken: this.NL_TOKEN,
data: {
event: eventName,
data: data
}
}))
}
/**
* handle messages from app
*
* @param {object} event
*
*/
handleMessage(event) {
if (typeof event.data === 'string') {
// parse message
const message = JSON.parse(event.data)
// if event is in handlers-object mapped call it
if (this.handlers.hasOwnProperty(message.event)) {
this.handlers[message.event].call(null, this, message.data)
}
}
}
}
module.exports.Connector = Connector

@ -0,0 +1,81 @@
const AppsStore = require('./../stores/apps.js').AppsStore
/**
* handler for apps
*
* @author Björn Hase
* @license https://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
*/
class AppsHandler {
/**
* use create in appStore and send event with result to app
*
* @param {object} data
* @return {object}
*
*/
create(connector, data) {
const appsStore = new AppsStore()
appsStore.create(data)
.then((data) => {
connector.send('pouchdb.apps.success', data)
})
}
/**
* use update in appStore and send event with result to app
*
* @param {object} data
* @return {object}
*
*/
update(connector, data) {
const appsStore = new AppsStore()
appsStore.update(data)
.then((data) => {
connector.send('pouchdb.apps.success', data)
})
}
/**
* use update in appStore and send event with result to app
*
* @param {object} data
* @return {object}
*
*/
findOne(connector, data) {
const appsStore = new AppsStore()
appsStore.findOneById(data.id)
.then((data) => {
if (data) {
connector.send('pouchdb.apps.readyOne', data)
}
})
}
/**
* use find in appStore and send event with result to app
*
* @param {object} connector
* @param {object} data
*
*/
find(connector, data) {
const appsStore = new AppsStore()
appsStore.find()
.then((data) => {
console.error('send result', data)
connector.send('pouchdb.apps.ready', data)
})
}
}
module.exports.AppsHandler = AppsHandler

@ -0,0 +1,28 @@
const Connector = require('./connector/connector.js').Connector
const AppsHandler = require('./handlers/apps.js').AppsHandler
// create handlers
const appsHandler = new AppsHandler()
// create connector and add handlers for events
const connector = new Connector({
'pouchdb.apps.create': appsHandler.create,
'pouchdb.apps.update': appsHandler.update,
'pouchdb.apps.findOne': appsHandler.findOne,
'pouchdb.apps.find': appsHandler.find
})
//
connector.client.onerror = function() {
}
//
connector.client.onopen = function() {
}
//
connector.client.onclose = function() {
process.exit()
}

@ -0,0 +1,701 @@
{
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"abstract-leveldown": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz",
"integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==",
"requires": {
"buffer": "^5.5.0",
"immediate": "^3.2.3",
"level-concat-iterator": "~2.0.0",
"level-supports": "~1.0.0",
"xtend": "~4.0.0"
}
},
"argsarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz",
"integrity": "sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg=="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"bufferutil": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
"requires": {
"node-gyp-build": "^4.3.0"
}
},
"clone-buffer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
"integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g=="
},
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"d": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"requires": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"deferred-leveldown": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz",
"integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==",
"requires": {
"abstract-leveldown": "~6.2.1",
"inherits": "^2.0.3"
}
},
"double-ended-queue": {
"version": "2.1.0-0",
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
"integrity": "sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ=="
},
"encoding-down": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz",
"integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==",
"requires": {
"abstract-leveldown": "^6.2.1",
"inherits": "^2.0.3",
"level-codec": "^9.0.0",
"level-errors": "^2.0.0"
}
},
"end-stream": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/end-stream/-/end-stream-0.1.0.tgz",
"integrity": "sha512-Brl10T8kYnc75IepKizW6Y9liyW8ikz1B7n/xoHrJxoVSSjoqPn30sb7XVFfQERK4QfUMYRGs9dhWwtt2eu6uA==",
"requires": {
"write-stream": "~0.4.3"
}
},
"errno": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"requires": {
"prr": "~1.0.1"
}
},
"es5-ext": {
"version": "0.10.62",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
"integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
"requires": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"next-tick": "^1.1.0"
}
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"requires": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"requires": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"ext": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
"integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
"requires": {
"type": "^2.5.0"
},
"dependencies": {
"type": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
}
}
},
"fetch-cookie": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz",
"integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==",
"requires": {
"tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"immediate": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"level": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/level/-/level-6.0.1.tgz",
"integrity": "sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw==",
"requires": {
"level-js": "^5.0.0",
"level-packager": "^5.1.0",
"leveldown": "^5.4.0"
}
},
"level-codec": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz",
"integrity": "sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==",
"requires": {
"buffer": "^5.6.0"
}
},
"level-concat-iterator": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz",
"integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw=="
},
"level-errors": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz",
"integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==",
"requires": {
"errno": "~0.1.1"
}
},
"level-iterator-stream": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz",
"integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==",
"requires": {
"inherits": "^2.0.4",
"readable-stream": "^3.4.0",
"xtend": "^4.0.2"
},
"dependencies": {
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"level-js": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/level-js/-/level-js-5.0.2.tgz",
"integrity": "sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg==",
"requires": {
"abstract-leveldown": "~6.2.3",
"buffer": "^5.5.0",
"inherits": "^2.0.3",
"ltgt": "^2.1.2"
}
},
"level-packager": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz",
"integrity": "sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==",
"requires": {
"encoding-down": "^6.3.0",
"levelup": "^4.3.2"
}
},
"level-supports": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz",
"integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==",
"requires": {
"xtend": "^4.0.2"
}
},
"level-write-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/level-write-stream/-/level-write-stream-1.0.0.tgz",
"integrity": "sha512-bBNKOEOMl8msO+uIM9YX/gUO6ckokZ/4pCwTm/lwvs46x6Xs8Zy0sn3Vh37eDqse4mhy4fOMIb/JsSM2nyQFtw==",
"requires": {
"end-stream": "~0.1.0"
}
},
"leveldown": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.6.0.tgz",
"integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==",
"requires": {
"abstract-leveldown": "~6.2.1",
"napi-macros": "~2.0.0",
"node-gyp-build": "~4.1.0"
},
"dependencies": {
"node-gyp-build": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz",
"integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ=="
}
}
},
"levelup": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz",
"integrity": "sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==",
"requires": {
"deferred-leveldown": "~5.3.0",
"level-errors": "~2.0.0",
"level-iterator-stream": "~4.0.0",
"level-supports": "~1.0.0",
"xtend": "~4.0.0"
}
},
"ltgt": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
"integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA=="
},
"minimist": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"napi-macros": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz",
"integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg=="
},
"next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"node-gyp-build": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz",
"integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg=="
},
"pouchdb": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb/-/pouchdb-7.3.0.tgz",
"integrity": "sha512-OwsIQGXsfx3TrU1pLruj6PGSwFH+h5k4hGNxFkZ76Um7/ZI8F5TzUHFrpldVVIhfXYi2vP31q0q7ot1FSLFYOw==",
"requires": {
"abort-controller": "3.0.0",
"argsarray": "0.0.1",
"buffer-from": "1.1.2",
"clone-buffer": "1.0.0",
"double-ended-queue": "2.1.0-0",
"fetch-cookie": "0.11.0",
"immediate": "3.3.0",
"inherits": "2.0.4",
"level": "6.0.1",
"level-codec": "9.0.2",
"level-write-stream": "1.0.0",
"leveldown": "5.6.0",
"levelup": "4.4.0",
"ltgt": "2.2.1",
"node-fetch": "2.6.7",
"readable-stream": "1.1.14",
"spark-md5": "3.0.2",
"through2": "3.0.2",
"uuid": "8.3.2",
"vuvuzela": "1.0.3"
}
},
"pouchdb-abstract-mapreduce": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-7.3.0.tgz",
"integrity": "sha512-+2fVt3SDh7D776lIGbYZOsKX5js1aUyUw7iJaTGitxSdQ2ObWSTrr3SUrj5Qo1CkgPXwRM3Tdoq/53JYAa2qCA==",
"requires": {
"pouchdb-binary-utils": "7.3.0",
"pouchdb-collate": "7.3.0",
"pouchdb-collections": "7.3.0",
"pouchdb-errors": "7.3.0",
"pouchdb-fetch": "7.3.0",
"pouchdb-mapreduce-utils": "7.3.0",
"pouchdb-md5": "7.3.0",
"pouchdb-utils": "7.3.0"
}
},
"pouchdb-binary-utils": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-binary-utils/-/pouchdb-binary-utils-7.3.0.tgz",
"integrity": "sha512-xvBH/XGHGcou2vkEzszJxkCc7YElfRUrkLUg51Jbdmh1mogLDUO0bU3Tj6TOIIJfRkQrU/HV+dDkMAhsil0amQ==",
"requires": {
"buffer-from": "1.1.2"
}
},
"pouchdb-collate": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-collate/-/pouchdb-collate-7.3.0.tgz",
"integrity": "sha512-ys7rXKtEr6cfghgUjknwFJiOkITebV6JmeTybJKCzMV0r2luXu0OoPQsKVpE/wbM/3F5LxfpbFKGFpPcfGMvTA=="
},
"pouchdb-collections": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-collections/-/pouchdb-collections-7.3.0.tgz",
"integrity": "sha512-Xr54m2+fErShXn+qAT4xwqJ+8NwddNPeTMJT4z4k1sZsrwfHmZsWbsKAyGPMF04eQaaU+7DDRMciu2VzaBUXyg=="
},
"pouchdb-errors": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-errors/-/pouchdb-errors-7.3.0.tgz",
"integrity": "sha512-dTBbIC1BbCy6J9W/Csg5xROgb3wJN3HpbgAJHHSEtAkb8oA45KZmU3ZwEpNhf0AfPuQm4XgW1936PvlDlGgJiw==",
"requires": {
"inherits": "2.0.4"
}
},
"pouchdb-fetch": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-fetch/-/pouchdb-fetch-7.3.0.tgz",
"integrity": "sha512-8/lcg8iMDG+GVs1dHNXA4ktJSEpH71dHU3xesMJ25tNQOqfAaaWrkfz9j71ZYDDkveLYE6UjUzl/sDacu2hSjw==",
"requires": {
"abort-controller": "3.0.0",
"fetch-cookie": "0.11.0",
"node-fetch": "2.6.7"
}
},
"pouchdb-find": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-find/-/pouchdb-find-7.3.0.tgz",
"integrity": "sha512-EwhnfyxCAkKf8PG4tfndTTygEmtuz+o1LiZkxfPrflfXA3m1jo1ithib0hwBYtEwEYWuZxH6B8pRZutbLoQCGA==",
"requires": {
"pouchdb-abstract-mapreduce": "7.3.0",
"pouchdb-collate": "7.3.0",
"pouchdb-errors": "7.3.0",
"pouchdb-fetch": "7.3.0",
"pouchdb-md5": "7.3.0",
"pouchdb-selector-core": "7.3.0",
"pouchdb-utils": "7.3.0"
}
},
"pouchdb-mapreduce-utils": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-7.3.0.tgz",
"integrity": "sha512-KDVSd+H2r+XWTrQfKWV71SknDDYRjYXoeWs0ZQl3xITHCcTl+fIgqyagg/XN+Zy/U9LeLPGMe2JdgPx9H8lJgw==",
"requires": {
"argsarray": "0.0.1",
"inherits": "2.0.4",
"pouchdb-collections": "7.3.0",
"pouchdb-utils": "7.3.0"
}
},
"pouchdb-md5": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-md5/-/pouchdb-md5-7.3.0.tgz",
"integrity": "sha512-wL04QgoKyd/L/TV5gxgcvlEyCJiZoXCOEFJklTzkdza/kBQNJGPH7i0ZhKa7Sb+AvZYoWZHddf1Zgv7rBScHkA==",
"requires": {
"pouchdb-binary-utils": "7.3.0",
"spark-md5": "3.0.2"
}
},
"pouchdb-selector-core": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-selector-core/-/pouchdb-selector-core-7.3.0.tgz",
"integrity": "sha512-sK/cCrIGeL9ImcMhKGcwa54+bzX7Wv4hhVV+oUW3T1Nasaoxh+Muem1GuA+x1+SbTCE8y37rUg8i6DIOhX51ew==",
"requires": {
"pouchdb-collate": "7.3.0",
"pouchdb-utils": "7.3.0"
}
},
"pouchdb-utils": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pouchdb-utils/-/pouchdb-utils-7.3.0.tgz",
"integrity": "sha512-HH+5IXXWn/ZgVCSnrlydBMYn6MabT7RS7SNoo9w8qVH9efpZSp3eLchw6yMQNLw8LQefWmbbskiHV9VgJmSVWQ==",
"requires": {
"argsarray": "0.0.1",
"clone-buffer": "1.0.0",
"immediate": "3.3.0",
"inherits": "2.0.4",
"pouchdb-collections": "7.3.0",
"pouchdb-errors": "7.3.0",
"pouchdb-md5": "7.3.0",
"uuid": "8.3.2"
}
},
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
},
"psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
},
"dependencies": {
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
}
}
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"spark-md5": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz",
"integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"through2": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
"integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
"requires": {
"inherits": "^2.0.4",
"readable-stream": "2 || 3"
},
"dependencies": {
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"tough-cookie": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"requires": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
}
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"requires": {
"is-typedarray": "^1.0.0"
}
},
"universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="
},
"url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"requires": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"utf-8-validate": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
"requires": {
"node-gyp-build": "^4.3.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"vuvuzela": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz",
"integrity": "sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"websocket": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
"requires": {
"bufferutil": "^4.0.1",
"debug": "^2.2.0",
"es5-ext": "^0.10.50",
"typedarray-to-buffer": "^3.1.5",
"utf-8-validate": "^5.0.2",
"yaeti": "^0.0.6"
}
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"write-stream": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz",
"integrity": "sha512-IJrvkhbAnj89W/GAVdVgbnPiVw5Ntg/B4tc/MUCIEwj/g6JIww1DWJyB/yBMT3yw2/TkT6IUZ0+IYef3flEw8A==",
"requires": {
"readable-stream": "~0.0.2"
},
"dependencies": {
"readable-stream": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-0.0.4.tgz",
"integrity": "sha512-azrivNydKRYt7zwLV5wWUK7YzKTWs3q87xSmY6DlHapPrCvaT6ZrukvM5erV+yCSSPmZT8zkSdttOHQpWWm9zw=="
}
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="
}
}
}

@ -0,0 +1,13 @@
{
"private": true,
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"minimist": "^1.2.6",
"pouchdb": "^7.3.0",
"pouchdb-find": "^7.3.0",
"uuid": "^8.3.2",
"websocket": "^1.0.34"
}
}

@ -0,0 +1,125 @@
const PouchdbHandler = require('./pouchdbHandler.js').PouchdbHandler
/**
* apps
*
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/tellme-bot.git
*
*/
class AppsStore extends PouchdbHandler {
constructor() {
super()
// add index for apps
this.createIndex([
'name',
'description',
'tags'
])
}
/**
*
* @param {object} data
* @return {object}
*
*/
create(data) {
return this.db.post(data)
.then((response) => {
return this.findOneById(response._id)
}).catch((error) => {
console.error(error)
})
}
/**
*
* @param {object} data
* @return {object}
*
*/
update(data) {
return this.db.put(data)
.then((response) => {
return this.findOneById(response._id)
}).catch((error) => {
console.error(error)
})
}
/**
* find one app by id
*
* @param {string} id
* @return {mixed}
*
*/
findOneById(id) {
const query = {
'fields': [
'_id',
'_rev',
'name',
'command',
'description',
'thumbnail',
'tags'
],
'selector': {
'_id' : id
}
}
return this.db.find(query).then((documents) => {
if (documents.docs.length === 0) {
return null
} else {
return documents.docs[0]
}
}).catch((error) => {
console.error(error)
})
}
/**
* find apps
*
* @return {mixed}
*
*/
find() {
const query = {
'fields': [
'_id',
'name',
'command',
'description',
'thumbnail',
'tags',
'started_date'
],
'selector': {
'name': {
'$exists': true
}
}
}
return this.db.find(query).then((documents) => {
if (documents.warning) {
console.warning(documents.warning)
}
return documents.docs
}).catch((error) => {
console.error(error)
})
}
}
module.exports.AppsStore = AppsStore

@ -1,5 +1,5 @@
import PouchDB from 'pouchdb'
import PouchDBfind from 'pouchdb-find'
const PouchDB = require('pouchdb')
const PouchDBfind = require('pouchdb-find')
/**
* PouchdbHandler, for create
@ -10,16 +10,16 @@ import PouchDBfind from 'pouchdb-find'
*
*/
class DatabaseHandler {
class PouchdbHandler {
/**
*
*
*/
constructor(name) {
constructor() {
PouchDB.plugin(PouchDBfind)
this.db = new PouchDB(name, {
this.db = new PouchDB('.storage/pouchdb/apps', {
revs_limit: 0
})
}
@ -30,27 +30,21 @@ class DatabaseHandler {
* @param {array} fields
*
*/
createIndex(fields, name = null) {
createIndex(fields) {
// adding index
try {
const query = {
this.db.createIndex({
index: {
fields: fields
}
}
if (name) {
query.index.ddoc = name
}
}).then(() => {
this.db.createIndex(query)
})
} catch (error) {
console.log(error)
}
}
}
export default DatabaseHandler
module.exports.PouchdbHandler = PouchdbHandler

@ -0,0 +1,126 @@
const PouchdbHandler = require('./pouchdbHandler.js').PouchdbHandler
/**
* apps
*
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/tellme-bot.git
*
*/
class TagsStore extends PouchdbHandler {
constructor() {
super()
// add index for apps
this.createIndex([
'name'
])
}
/**
*
*
* @param {object} data
*
*/
async create(tags) {
const query = {
'selector': {
'name': {
'$in': tags
}
}, 'fields': [
'name'
]
}
// check for existings tags and remove
// adding tags that are not removed
this.db.find(query).then((documents) => {
if (documents.docs && documents.docs.length > 0) {
documents.docs.forEach(data, () => {
const index = tags.indexOf(data.name)
if (index >= 0) {
tags.splice(index, 1)
}
})
}
if (tags.length > 0) {
tags.forEach((tag) => {
await this.db.post({
'name': tag
})
})
}
})
}
/**
*
*
* @param {object} data
*
*/
async remove(tags) {
const query = {
'selector': {
'name': {
'$in': tags
}
}, 'fields': [
'name'
]
}
// check for existings tags and remove
// adding tags that are not removed
this.db.find(query).then((documents) => {
if (documents.docs && documents.docs.length > 0) {
documents.docs.forEach(data, () => {
const index = tags.indexOf(data.name)
if (index >= 0) {
tags.splice(index, 1)
}
})
}
if (tags.length > 0) {
tags.forEach((tag) => {
await this.db.post({
'name': tag
})
})
}
})
}
/**
* find apps
*
* @return {mixed}
*
*/
find() {
const query = {
'fields': [
'name'
]
}
return this.db.find(query).then((documents) => {
return documents.docs
})
}
}
module.exports.TagsStore = TagsStore

@ -1,77 +0,0 @@
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
// add var for window
let appWindow = null
// add events
app.on('ready', handleReady)
app.on('activate', handleActivate)
app.on('window-all-closed', handleAllClosed)
/**
* create window for app
*
*
*/
function handleReady() {
// create window
appWindow = new BrowserWindow({
frame: false,
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: false,
contextIsolation: false,
webSecurity: true,
enableRemoteModule: true
}
})
// max size of window
appWindow.maximize()
appWindow.setMenu(null)
// loading
appWindow.loadURL('file://' + __dirname + '/dist/index.html')
// add event if window closed
appWindow.on('closed', handleClose)
if (process.env.debug) {
appWindow.webContents.openDevTools()
}
// adding events for ipcMain
ipcMain.on('getPathUserData', (event) => {
event.returnValue = app.getPath('userData')
})
}
/**
* handle close window
*
*/
function handleClose() {
appWindow = null
}
/**
*
*
*/
function handleAllClosed() {
if (process.platform !== 'darwin') {
app.quit()
}
}
/**
*
*
*/
function handleActivate() {
if (appWindow === null) {
createAppWindow()
}
}

@ -1 +1,18 @@
{}
{
"/build/js/app/spritemap.js": "/build/js/app/spritemap.js",
"/public/symbol-defs.svg": "/public/symbol-defs.svg",
"/build/js/app.js": "/build/js/app.js",
"/build/css/styles.css": "/build/css/styles.css",
"/build/js/neutralino.js": "/build/js/neutralino.js",
"/build/css/demo.html": "/build/css/demo.html",
"/build/css/IBMPlexMono-Bold.eot": "/build/css/IBMPlexMono-Bold.eot",
"/build/css/IBMPlexMono-Bold.ttf": "/build/css/IBMPlexMono-Bold.ttf",
"/build/css/IBMPlexMono-Bold.woff": "/build/css/IBMPlexMono-Bold.woff",
"/build/css/IBMPlexMono-Bold.woff2": "/build/css/IBMPlexMono-Bold.woff2",
"/build/css/IBMPlexMono.eot": "/build/css/IBMPlexMono.eot",
"/build/css/IBMPlexMono.ttf": "/build/css/IBMPlexMono.ttf",
"/build/css/IBMPlexMono.woff": "/build/css/IBMPlexMono.woff",
"/build/css/IBMPlexMono.woff2": "/build/css/IBMPlexMono.woff2",
"/build/css/OFL.txt": "/build/css/OFL.txt",
"/build/css/stylesheet.css": "/build/css/stylesheet.css"
}

@ -0,0 +1,54 @@
{
"applicationId": "js.neutralino.potato-launcher",
"version": "1.0.0",
"defaultMode": "window",
"port": 0,
"documentRoot": "/build/",
"url": "/",
"enableServer": true,
"enableNativeAPI": true,
"enableExtensions": true,
"tokenSecurity": "one-time",
"logging": {
"enabled": true,
"writeToLogFile": true
},
"nativeAllowList": [
"app.*",
"filesystem.*",
"os.*",
"extensions.*",
"computer.*",
"storage.*",
"debug.log"
],
"modes": {
"window": {
"title": "Potato Launcher",
"fullScreen": false,
"alwaysOnTop": false,
"icon": "/resources/icons/appIcon.png",
"enableInspector": false,
"borderless": true,
"maximize": true,
"hidden": false,
"resizable": true,
"exitProcessOnClose": true
}
},
"cli": {
"binaryName": "potato-launcher",
"resourcesPath": "/build/",
"extensionsPath": "/extensions/",
"clientLibrary": "/resources/js/neutralino.js",
"binaryVersion": "4.7.0",
"clientVersion": "3.6.0"
},
"extensions": [
{
"id": "js.neutralino.pouchdb",
"commandLinux": "${NL_PATH}/extensions/bin/pouchdb-linux-x64",
"commandWindows": "${NL_PATH}/extensions/bin/index.exe"
}
]
}

7556
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,54 +1,25 @@
{
"name": "potato-launcher",
"version": "0.2.0",
"author": "Björn Hase <me@herr-hase.wtf>",
"homepage": "https://herr-hase.wtf",
"main": "index.js",
"description": "Launcher for Apps on Desktop",
"build": {
"files": [
"dist/**/*",
"package.json",
"index.js"
],
"linux": {
"target": [
"AppImage",
"deb"
],
"icon": "resources/logo.png",
"category": "Utility"
},
"nodeGypRebuild": false,
"npmRebuild": false,
"asar": true
},
"private": true,
"version": "0.1.0",
"scripts": {
"development": "export debug=true && npx mix && electron .",
"production": "npx mix --production && electron .",
"build-linux": "npx mix --production && npm exec --package=electron-builder -- electron-builder build --linux"
"dev": "npx mix --production && neu run --disable-auto-reload",
"build": "npx mix --production && rm -r dist && neu build",
"build-extensions-linux": "nexe ./extensions/pouchdb/index.js --build --output=./../bin/pouchdb-linux-x64 -r ./ --cwd=./extensions/pouchdb --python=$(which python3) --target=linux-x64 --verbose --enableNodeCli",
"build-extensions-win64": "nexe ./extensions/pouchdb/index.js --build --output=./../bin/pouchdb-win-x64 -r ./ --cwd=./extensions/pouchdb --python=$(which python3) --target=windows-x64 --verbose --enableNodeCli"
},
"dependencies": {
"@riotjs/observable": "^4.1.1",
"@tiny-components/confirm": "^0.1.1",
"@tiny-components/notification": "^0.1.0",
"@tiny-components/plain-ui": "^0.6.0",
"@tiny-components/sidebar-form": "^0.1.0",
"@tiny-components/validator": "^0.2.0",
"dayjs": "^1.11.5",
"identicon": "^3.1.1",
"md5": "^2.3.0",
"mime-types": "^2.1.35",
"mkdirp": "^1.0.4",
"pouchdb": "^7.3.0",
"pouchdb-find": "^7.3.0",
"riot": "^7.0.3",
"uuid": "^9.0.0"
"riot": "^7.0.3"
},
"devDependencies": {
"@riotjs/webpack-loader": "^6.0.0",
"electron": "^21.2.0",
"electron-builder": "^23.6.0",
"laravel-mix": "^6.0.49",
"sass": "^1.54.5",
"sass-loader": "^12.6.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

@ -4,16 +4,18 @@
<meta charset="UTF-8">
<title>Potato Launcher</title>
<link rel="stylesheet" href="css/styles.css">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; img-src data: 'self';">
</head>
<body>
<div class="potato-main">
<div class="container-full p-top-4">
<potato-apps-view></potato-apps-view>
<tiny-notification></tiny-notification>
<tiny-confirm></tiny-confirm>
</div>
</div>
<script src="js/neutralino.js"></script>
<!-- -->
<script src="js/app.js"></script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

@ -1,16 +0,0 @@
<svg width="72px" height="72px" viewBox="0 0 72 72" id="emoji" xmlns="http://www.w3.org/2000/svg">
<g id="color">
<path fill="#A57939" stroke="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2" d="M59.0417,27.8733c0,18.2898-7.5955,27.2079-14.6746,31.5411c-6.1848,3.8041-11.9917,4.1064-11.9917,4.1064 c-10.8076,0-19.5746-8.767-19.5746-19.5746c0-6.6509,3.7337-11.4301,8.3765-16.0729C33.2467,15.804,31.9388,9.5079,42.8303,9.5079 c8.956,0,16.2114,7.2681,16.2114,16.224C59.0417,26.5381,59.0417,27.8733,59.0417,27.8733z"/>
<path fill="#a57939" stroke="none" d="M59.0449,25.73c0,0.81,0,2.14,0,2.14c0,18.29-7.6,27.21-14.68,31.54 c-6.1801,3.81-11.9901,4.11-11.9901,4.11c-1.67,0-3.28-0.21-4.8199-0.6c31.56-8.62,25.35-49.89,25.35-49.89 C56.6449,16,59.0449,20.59,59.0449,25.73z"/>
<circle cx="38.2737" cy="51.6496" r="3.2408" fill="#A57939" stroke="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"/>
</g>
<g id="hair"/>
<g id="skin"/>
<g id="skin-shadow"/>
<g id="line">
<path fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2" d="M59.0417,27.8733c0,18.2898-7.5955,27.2079-14.6746,31.5411c-6.1848,3.8041-11.9917,4.1064-11.9917,4.1064 c-10.8076,0-19.5746-8.767-19.5746-19.5746c0-6.6509,3.7337-11.4301,8.3765-16.0729C33.2467,15.804,31.9388,9.5079,42.8303,9.5079 c8.956,0,16.2114,7.2681,16.2114,16.224C59.0417,26.5381,59.0417,27.8733,59.0417,27.8733z"/>
<circle cx="39.534" cy="16.2145" r="1.2603" fill="#000000" stroke="none"/>
<circle cx="38.2737" cy="51.6496" r="3.2408" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"/>
<path fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2" d="M59.0417,27.8733c0,18.2898-7.5955,27.2079-14.6746,31.5411c-6.1848,3.8041-11.9917,4.1064-11.9917,4.1064 c-10.8076,0-19.5746-8.767-19.5746-19.5746c0-6.6509,3.7337-11.4301,8.3765-16.0729C33.2467,15.804,31.9388,9.5079,42.8303,9.5079 c8.956,0,16.2114,7.2681,16.2114,16.224C59.0417,26.5381,59.0417,27.8733,59.0417,27.8733z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@ -4,7 +4,6 @@ import TinyLoading from '@tiny-components/loading/src/loading.riot'
import TinySidebarFormHeader from './forms/header.riot'
import TinySidebarFormFooter from './forms/footer.riot'
import TinyNotification from '@tiny-components/notification/src/notification.riot'
import TinyConfirm from '@tiny-components/confirm/src/confirm.riot'
import FieldError from '@tiny-components/validator/src/fieldError.riot'
@ -19,12 +18,54 @@ riot.register('tiny-loading', TinyLoading)
riot.register('tiny-sidebar-form-header', TinySidebarFormHeader)
riot.register('tiny-sidebar-form-footer', TinySidebarFormFooter)
riot.register('tiny-notification', TinyNotification)
riot.register('tiny-confirm', TinyConfirm)
riot.register('potato-field-tags', potatoFieldTags)
riot.register('potato-apps-view', potatoAppsView)
riot.register('potato-close-button', potatoCloseButton)
riot.mount('potato-apps-view')
riot.mount('tiny-notification')
riot.mount('tiny-confirm')
// adding events for Neutralino
Neutralino.events.on('ready', async () => {
// @TODO thats mad, it is only a workaround, don't judge me, i will do better
// its no possible to create a hole path, solving this with array and a recursive function
try {
const result = await Neutralino.filesystem.getStats('./.storage')
if (result) {
try {
await Neutralino.filesystem.createDirectory('./.storage/pouchdb')
} catch(error) {
}
}
} catch(error) {
if (error.code === 'NE_FS_NOPATHE') {
try {
await Neutralino.filesystem.createDirectory('./.storage')
await Neutralino.filesystem.createDirectory('./.storage/pouchdb')
} catch(error) {
}
}
}
riot.mount('potato-apps-view')
riot.mount('tiny-notification')
})
// let it rain
Neutralino.init()
// workaround to prevent a stack overflow
window._arrayBufferToBase64 = function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}

@ -18,6 +18,7 @@
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
*/
export default {
/**

@ -1,6 +1,6 @@
<potato-close-button>
<button class="button button--full button--icon button--danger button--hover-icon-text m-bottom-0" onclick={ (event) => { handleClose(event) } }>
<svg class="icon icon--big fill-text-contrast" aria-hidden="true">
<button class="button button--icon button--danger button--hover-icon-contrast m-left-4 m-bottom-0" onclick={ (event) => { handleClose(event) } }>
<svg class="icon icon--big" aria-hidden="true">
<use xlink:href="symbol-defs.svg#icon-log-out"></use>
</svg>
</button>
@ -18,7 +18,7 @@
export default {
handleClose(event) {
window.close()
Neutralino.app.exit()
}
}

@ -2,7 +2,7 @@
<div class="field-tags">
<select name="{ state.options.name }[]" multiple style="display: none;">
<option each={ tag in state.tags } value={ tag } selected></option>
<option each={ tag in state.tags } value={ tag }></option>
</select>
<label class="field-label">
@ -30,7 +30,6 @@
</li>
</ul>
</div>
</div>
<script>
@ -142,7 +141,9 @@
for (let i = 0; i < this.state.tags.length; i++) {
if (value === this.state.tags[i]) {
inArray = true
this.state.errors.push('Already added')
this.update()
break
}
@ -151,13 +152,16 @@
// if value is not already in data and longer than zero chars
if (inArray === false && value.length > 0) {
this.state.tags.push(value)
this.update()
// select new option
this.$('select option[value="' + value + '"]').selected = true
this.$('input').value = ''
} else if (value.length === 0) {
this.state.errors.push('Required!')
this.update()
}
this.update()
// adding focus to input
this.$('input').focus();
}

@ -1,152 +0,0 @@
<potato-filter>
<div class="{ getFilterCssClasses('filter') }" if={ this.state.tags.length > 0 }>
<div class="display-flex">
<button class="button button--open button--icon button--hover-icon-contrast m-bottom-0" onclick={ (event) => { handleOpen(event) }}>
<svg class="icon icon--big">
<use xlink:href="symbol-defs.svg#icon-filter" />
</svg>
</button>
<button class="button button--close button--icon button--hover-icon-contrast m-bottom-0" onclick={ (event) => { handleOpen(event) }}>
<svg class="icon icon--big">
<use xlink:href="symbol-defs.svg#icon-close" />
</svg>
</button>
<div class="filter__selected m-left-3" if={ state.tags.length > 0 }>
<button if={ tag.selected === true } class="button m-bottom-0 m-right-3" each={ (tag, index) in state.tags } onclick={ (event) => { handleTagToggle(event, index) }}>
{ tag.name }
<svg class="icon">
<use xlink:href="symbol-defs.svg#icon-close" />
</svg>
</button>
</div>
</div>
<div class="filter__tags">
<button class="button" each={ (tag, index) in state.tags } onclick={ (event) => { handleTagToggle(event, index) }}>
{ tag.name }
<svg class="{ getTagCssClasses('icon', tag, true) }">
<use xlink:href="symbol-defs.svg#icon-checkbox" />
</svg>
<svg class="{ getTagCssClasses('icon', tag) }">
<use xlink:href="symbol-defs.svg#icon-checkbox-checked" />
</svg>
</button>
</div>
</div>
<script>
import tagsStore from './../stores/tags.js'
import appsStore from './../stores/apps.js'
/**
* filtering apps by tags, showing all available tags as list of buttons
* whith a checkbox icon, after select or deselect update apps
*
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
*/
export default {
state: {
tags: [],
selected: [],
isOpen: false
},
/**
*
*
*/
onMounted() {
tagsStore.on('ready', (data) => {
this.state.tags = data
this.update()
})
tagsStore.get()
},
/**
* get css for filter
*
* @param {string} defaultCssClass
* @return {string}
*/
getFilterCssClasses(defaultCssClass) {
const classes = [
defaultCssClass
]
if (this.state.isOpen === true) {
classes.push('filter--open')
}
return classes.join(' ')
},
/**
* get css for tag
*
* @param {string} defaultCssClass
* @param {object} tag
* @param {mixed} parameter
* @return {string}
*/
getTagCssClasses(defaultCssClass, tag, parameter = undefined) {
const classes = [
defaultCssClass
]
if (tag.selected === parameter) {
classes.push('hidden')
}
return classes.join(' ')
},
/**
* toggle tag, if selected or not
*
* @param {object} event
* @param {integer} index
*
*/
handleTagToggle(event, index) {
// if selected is undefined on tags with index
if (this.state.tags[index].selected === undefined) {
this.state.tags[index].selected = true
this.state.selected.push(this.state.tags[index].name)
} else {
const selectedIndex = this.state.selected.indexOf(this.state.tags[index].name)
// delete selected from tags
delete this.state.tags[index].selected
// if selctedIndex has value, remove from array
if (selectedIndex !== -1) {
this.state.selected.splice(selectedIndex, 1)
}
}
// update filter for store
appsStore.filter(this.state.selected)
this.update()
},
handleOpen(event) {
if (this.state.isOpen === true) {
this.state.isOpen = false
} else {
this.state.isOpen = true
}
this.update()
}
}
</script>
</potato-filter>

@ -1,57 +0,0 @@
<potato-sorting>
<div class="filter">
<button class="button button--icon button--hover-icon-contrast m-bottom-0" if={ state.column === 'name' } onclick={ (event) => { handleToggle(event) }}>
<svg class="icon icon--big">
<use xlink:href="symbol-defs.svg#icon-text" />
</svg>
</button>
<button class="button button--icon button--hover-icon-contrast m-bottom-0" if={ state.column === 'date_started' } onclick={ (event) => { handleToggle(event) }}>
<svg class="icon icon--big">
<use xlink:href="symbol-defs.svg#icon-clock" />
</svg>
</button>
</div>
<script>
import appsStore from './../stores/apps.js'
/**
* sorting of apps
*
* @author Björn Hase <me@herr-hase.wtf>
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
*/
export default {
state: {
column: 'name'
},
/**
* toggle sorting
*
*
* @param {[type]} event
*
*/
handleToggle(event) {
event.preventDefault()
if (this.state.column === 'name') {
this.state.column = 'date_started'
} else if (this.state.column === 'date_started') {
this.state.column = 'name'
}
appsStore.sort(this.state.column)
this.update()
}
}
</script>
</potato-sorting>

@ -1,274 +0,0 @@
import DatabaseHandler from './databaseHandler.js'
import FileHandler from './fileHandler.js'
import TagsDatabase from './tags.js'
const { ipcRenderer } = require('electron')
/**
* apps
*
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/tellme-bot.git
*
*/
class AppsDatabase extends DatabaseHandler {
constructor() {
super('apps')
// add index for apps to sort by name
this.createIndex([
'name'
], 'name-sort')
// add index for apps to sort by date_started
this.createIndex([
'date_started'
], 'date-started-sort')
}
/**
* create app
*
* @param {object} data
* @return {object}
*
*/
async create(data) {
// default for date_started
data.date_started = 0
if (data.thumbnail) {
data.thumbnail = await this.createOrUpdateFile(data.thumbnail)
}
return this.db.post(data)
.then((response) => {
// if tags are in data update tags also in database
if (data.tags) {
const tagsDatabase = new TagsDatabase()
tagsDatabase.update(data.tags)
}
return this.findOneById(response._id)
}).catch((error) => {
// @TODO handle errors from pouchdb
console.error(error)
})
}
/**
* create or update file with fileHandler
*
*
* @param {[type]} file
* @param {[type]} entry
* @param {[type]} key
* @return {mixed}
*
*/
async createOrUpdateFile(file, entry, key) {
// fileHandler
const fileHandler = new FileHandler(ipcRenderer.sendSync('getPathUserData') + '/attachments')
const reader = new FileReader()
// if file is blob use readFileFromBlob to get data
if (file instanceof Blob) {
file.data = await fileHandler.readFileFromBlob(file)
if (entry && entry[key]) {
fileHandler.remove(entry[key])
}
file = fileHandler.put(file.name, file.type, file.data)
}
return file
}
/**
* update app
*
* @param {object} data
* @return {object}
*
*/
async update(data) {
const entry = await this.findOneById(data._id)
if (data.thumbnail) {
data.thumbnail = await this.createOrUpdateFile(data.thumbnail, entry, 'thumbnail')
}
return this.db.put(data)
.then(async (response) => {
const tagsDatabase = new TagsDatabase()
// if tags are in data update tags also in database
if (data.tags && data.tags.length > 0) {
tagsDatabase.update(data.tags)
} else {
await tagsDatabase.removeNotNeeded()
}
return this.findOneById(response._id)
}).catch((error) => {
// @TODO handle errors from pouchdb
console.error(error)
})
}
/**
* remove app
*
* @param {object} document
* @return {object}
*
*/
async remove(document) {
const entry = await this.findOneById(document._id)
if (entry.thumbnail) {
const fileHandler = new FileHandler(ipcRenderer.sendSync('getPathUserData') + '/attachments')
fileHandler.remove(entry.thumbnail)
}
return this.db.remove(document)
.then(async (response) => {
// successfull remove document, check for tags that
// not longer used
if (response.ok === true) {
const tagsDatabase = new TagsDatabase()
await tagsDatabase.removeNotNeeded()
}
return response
}).catch((error) => {
// @TODO handle errors from pouchdb
console.error(error)
})
}
/**
* find one app by id
*
* @param {string} id
* @return {mixed}
*
*/
findOneById(id) {
const query = {
'fields': [
'_id',
'_rev',
'name',
'command',
'description',
'thumbnail',
'tags',
'date_started'
],
'selector': {
'_id' : id
}
}
return this.db.find(query).then((documents) => {
if (documents.docs.length === 0) {
return null
} else {
return documents.docs[0]
}
}).catch((error) => {
// @TODO handle errors from pouchdb
console.error(error)
})
}
/**
* find apps
*
* @return {mixed}
*
*/
async find(parameters) {
const query = {
'selector': {
},
'fields': [
'_id',
'_rev',
'name',
'command',
'description',
'thumbnail',
'tags',
'date_started'
]
}
// adding sort from parameters
if (parameters.sort) {
query.sort = []
query.sort.push(parameters.sort)
// if sort is date_stared change 'date-started-sort'
if (parameters.sort === 'date_started') {
query.use_index = '_design/date-started-sort'
query.selector = {
'date_started': {
'$exists': true
}
}
// @TODO refactor this, change logic in filter
query.sort = [{
'date_started': 'desc'
}]
// if sort is name change 'name-sort'
} else {
query.use_index = '_design/name-sort'
query.selector = {
'name': {
'$regex': ''
}
}
}
}
// adding tags from parameters
if (parameters.tags.length > 0) {
query.selector.tags = {
$in: parameters.tags
}
}
return this.db.find(query).then(async (documents) => {
return documents.docs
}).catch((error) => {
// @TODO handle errors from pouchdb
console.error(error)
})
}
}
export default AppsDatabase

@ -1,127 +0,0 @@
import { v4 as uuidv4 } from 'uuid'
import md5 from 'md5'
import mkdirp from 'mkdirp'
import path from 'path'
import fs from 'fs'
/**
* handling files and create files in a hash-directory system
*
* @author Björn Hase
* @license https://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
*/
class FileHandler {
/**
*
*
* @param {string} storagePath
*
*/
constructor(storagePath) {
this.storagePath = storagePath
}
/**
* add file to storage
*
* @param {string} filename
* @param {string} type
* @param {mixed} data
* @return {object}
*
*/
put(filename, type, data) {
const uuid = uuidv4()
const relativePath = this._createDirPath(uuid) + '/' + uuid
try {
fs.writeFileSync(this.storagePath + '/' + relativePath, data, { encoding: 'binary' })
} catch(error) {
throw new Error(error)
}
return {
name: filename,
type: type,
path: relativePath
}
}
/**
* remove
*
* @param {object} file
*
*/
remove(file) {
fs.unlinkSync(this.storagePath + '/' + file.path)
}
/**
* read file from Blob as binary string
*
* @param {Object} file
* @return {mixed}
*
*/
readFileFromBlob(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = (response) => {
resolve(response.target.result)
}
reader.onerror = (error) => reject(error)
reader.readAsBinaryString(file)
})
}
/**
* creating directory for file,
* using filename and uniqid to get a hash and split
* him into chunks and creating directories
*
* @param {string} filename
* @return {string}
*/
_createDirPath(uuid) {
// getting hash
const hashPath = md5(uuid)
// creating string of relative path, and create missing directories
const relativePath = this._chunks(hashPath).join('/')
const absolutePath = this.storagePath + '/' + relativePath
mkdirp.sync(absolutePath)
return relativePath
}
/**
* split string into chunks
*
* @param {string} value
* @param {integer} size
* @return {array}
*/
_chunks(value, size = 8) {
let result = [];
if (value !== null) {
value = String(value);
size = ~~size;
result = size > 0 ? value.match(new RegExp('.{1,' + size + '}', 'g')) : [value];
}
return result;
}
}
export default FileHandler

@ -1,169 +0,0 @@
import DatabaseHandler from './databaseHandler.js'
import AppsStore from './apps.js'
import tagsStore from './../stores/tags.js'
/**
* tags
*
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/tellme-bot.git
*
*/
class TagsDatabase extends DatabaseHandler {
constructor() {
super('tags')
// add index for apps
this.createIndex([
'name'
], 'tags')
}
/**
* adding new tags, if tags are already
* exists skip tag
*
* @param {object} data
*
*/
update(tags) {
const query = {
'selector': {
'name': {
'$in': tags
}
}, 'fields': [
'name'
]
}
// check for existings tags and remove
// adding tags that are not removed
this.db.find(query).then((documents) => {
return this.filterTags(documents, tags)
}).then((tags) => {
if (tags.length > 0) {
// adding tags to entries
for (let i = 0; i < tags.length; i++) {
this.db.post({
'name': tags[i]
}).then(() => {
// last tag, then check for remove
if (i === (tags.length - 1)) {
this.removeNotNeeded()
}
})
}
}
})
}
/**
* search for tags in apps and remove
* tags that not longer exists in apps
*
*
*/
removeNotNeeded() {
const query = {
'selector': {
'name': {
'$exists': true
}
}, 'fields': [
'_id',
'_rev',
'name'
]
}
this.db.find(query).then((tags) => {
if (tags.docs.length > 0) {
const appsStore = new AppsStore()
for (let i = 0; i < tags.docs.length; i++) {
// create parameters
const parameters = {
tags: [],
sort: 'name'
}
// add tag name to parameters
parameters.tags.push(tags.docs[i].name)
// find app by tag, if no app is found, remove tag and update filter
appsStore.find(parameters).then((apps) => {
if (apps.length === 0) {
this.db.remove(tags.docs[i]).then(() => {
tagsStore.get()
})
}
})
}
}
})
}
/**
* filter tags, if they are already exists
*
* @param {array} documents
* @param {array} tags
* @return {array}
*
*/
filterTags(documents, tags) {
if (documents.docs.length > 0) {
for (let i = 0; i < documents.docs.length; i++) {
// check for name in tags
const index = tags.indexOf(documents.docs[i].name)
// if found remove from tags
if (index >= 0) {
tags.splice(index, 1)
}
}
}
return tags
}
/**
* find apps
*
* @return {array}
*
*/
find() {
const query = {
'fields': [
'name'
],
'selector': {
'name': {
'$exists': true
}
},
'sort': [
'name'
]
}
return this.db.find(query).then((documents) => {
return documents.docs
})
}
}
export default TagsDatabase

@ -3,7 +3,7 @@
<div class="sidebar__inner">
<!-- header -->
<tiny-sidebar-form-header title="{ state.current._id ? 'Edit ' + state.current.name : 'New' }" close={ (event) => { handleClose(event) }}></tiny-sidebar-form-header>
<tiny-sidebar-form-header title="New" close={ (event) => { handleClose(event) }}></tiny-sidebar-form-header>
<div class="sidebar__form">
@ -18,9 +18,8 @@
<div class="field-group">
<label class="field-label">
name*
<input type="text" class="field-text" name="name" value={ state.current.name } />
<input type="text" class="field-text" name="name" value="{ state.current.name ? state.current.name : '' }" />
</label>
<field-error name="name"></field-error>
</div>
<!-- command -->
@ -28,8 +27,8 @@
<label class="field-label">
command*
<div class="field-input-group">
<input class="field-text" type="text" name="command" value="{ state.current.command }" />
<button class="button button--hover-icon-contrast m-bottom-0" type="button" onclick={ (event) => { handleOpenCommand(event) }}>
<input class="field-text" type="text" name="command" value="{ state.current.command ? state.current.command : '' }" />
<button class="button button--hover-icon-contrast m-bottom-0" type="button" onclick={ handleSelectProgram }>
<svg class="icon">
<use xlink:href="symbol-defs.svg#icon-folder" />
</svg>
@ -53,16 +52,15 @@
<div class="field-group">
<label class="field-label">
description
<textarea class="field-text" name="description" value="{ state.current.description }"></textarea>
<textarea class="field-text" name="description" value="{ state.current.description ? state.current.description : '' }"></textarea>
</label>
</div>
<!-- media -->
<div class="field-group">
<label class="field-label">
thumbnail<br />
<input id="apps-form-select-thumbnail" class="hidden-xxs hidden-xs-up" type="file" accept="image/png, image/jpeg, image/gif, image/webm, image/webp" onchange={ (event) => { handleSelectThumbnail(event) }} />
<button class="button button--hover-icon-contrast m-top-3" type="button" onclick={ (event) => { handleOpenThumbnail(event) }}>
Thumbnail<br />
<button class="button button--hover-icon-contrast m-top-3" type="button" onclick={ (event) => { handleSelectThumbnail(event) }}>
<svg class="icon">
<use xlink:href="symbol-defs.svg#icon-image" />
</svg>
@ -75,7 +73,7 @@
<use xlink:href="symbol-defs.svg#icon-delete" />
</svg>
</button>
<img class="w-100" src="{ resolveMediaPath(state.current.thumbnail) }" />
<img class="w-100" src={ toImage(state.current.thumbnail) } />
</div>
</div>
<field-error name="thumbnail"></field-error>
@ -85,11 +83,7 @@
</div>
<!-- footer -->
<tiny-sidebar-form-footer
id={ state.current._id ? state.current._id : false }
loading={ state.loading }
handle-delete={ handleDelete }>
</tiny-sidebar-form-footer>
<tiny-sidebar-form-footer id={ state.current.id ? state.current.id : false } loading={ state.loading }></tiny-sidebar-form-footer>
</form>
</div>
@ -115,11 +109,6 @@
// validator
import FormValidator from '@tiny-components/validator/src/formValidator.js'
// confirm
import confirmStore from '@tiny-components/confirm/src/store.js'
const { ipcRenderer } = require('electron')
/**
* handler for apps
*
@ -140,55 +129,57 @@
*/
onMounted() {
this.state.storagePath = ipcRenderer.sendSync('getPathUserData') + '/attachments'
// adding event for open sidebar
formStore.on('open', (id) => {
this.state.current = false
this.state.open = true
// reset tags
tagsStore.trigger('update', [])
this.reset()
// if id is not undefined, get data from pouchdb
if (id !== undefined) {
appsStore.getOne(id)
// if id is send, load apps from pouchdb
if (id) {
Neutralino.extensions.dispatch('js.neutralino.pouchdb', 'pouchdb.apps.findOne', {
'id': id
})
}
this.state.open = true
this.update()
})
this.createValidator()
// receive from extensions database
appsStore.on('success', (data) => {
appsStore.trigger('update')
// creating formValidator
this.state.validator = new FormValidator(this.$('.form'), {
'name': {
'presence': true
},
'command': {
'presence': true
},
'tags': {
this.state.current._id = data._id
this.state.current._rev = data._rev
}
})
// stop loading
this.state.loading = false
this.update()
// adding on success
this.state.validator.onSuccess((event, data) => {
this.handleSuccess(event, data)
})
// receive from extensions database
appsStore.on('close', (data) => {
Neutralino.events.on('pouchdb.apps.success', (event) => {
appsStore.trigger('update')
appsStore.trigger('updated')
this.state.open = false
this.state.current._id = event.detail._id
this.state.current._rev = event.detail._rev
// stop loading
this.state.loading = false
this.update()
})
appsStore.on('readyOne', (data) => {
// receive from extensions database
Neutralino.events.on('pouchdb.apps.readyOne', (event) => {
this.state.current = data
this.state.current = event.detail
if (!this.state.current.tags) {
this.state.current.tags = []
@ -201,31 +192,7 @@
this.update()
})
},
/**
* creating Validator for form
*
*
*/
createValidator() {
this.state.validator = new FormValidator(this.$('.form'), {
'name': {
'presence': true
},
'command': {
'presence': true
},
'tags': {
}
})
// adding on success
this.state.validator.onSuccess((event, data) => {
this.handleSuccess(event, data)
})
},
},
/**
* choose a file for command
@ -234,30 +201,18 @@
* @param {object} event
*
*/
handleOpenCommand(event) {
async handleSelectProgram(event) {
event.preventDefault()
this.$('#apps-form-select-program').click()
},
/**
*
*
*
*/
handleSelectCommand(event) {
event.preventDefault()
if (event.target.files[0]) {
if (!this.state.current) {
this.state.current = {
// open dialog to choose a file that starts a programm
const entry = await Neutralino.os.showOpenDialog('Choose a File', {
'multiSelections': false,
'defaultPath': NL_CWD
})
}
}
this.state.current.command = event.target.files[0].path
this.update()
}
// adding path to command in current
this.state.current.command = entry
this.update()
},
/**
@ -269,57 +224,55 @@
handleSuccess(event, data) {
event.preventDefault()
data = Object.assign(this.state.current, data)
this.state.current = data
this.state.loading = true
this.update()
// adding thumbnail
data.thumbnail = this.state.current.thumbnail
// send to extensions database
if (data._id && data._rev) {
appsStore.put(data)
Neutralino.extensions.dispatch('js.neutralino.pouchdb', 'pouchdb.apps.update', data)
} else {
appsStore.post(data)
Neutralino.extensions.dispatch('js.neutralino.pouchdb', 'pouchdb.apps.create', data)
}
},
/**
* open dialog for choosing thumbnail
*
*
* @param {object} event
*
*/
handleOpenThumbnail(event)
{
event.preventDefault()
this.$('#apps-form-select-thumbnail').click()
},
/**
* if select thumbnail
*
*
* @param {object} event
* @param object event
*
*/
handleSelectThumbnail(event)
async handleSelectThumbnail(event)
{
if (event.target.files[0]) {
if (!this.state.current) {
this.state.current = {
const entry = await Neutralino.os.showOpenDialog('Choose a Thumbnail for App', {
'multiSelections': false,
'defaultPath': NL_CWD,
'filters': [{
'name': 'Images',
'extensions': [
'jpg',
'png',
'jpeg',
'webp',
'gif'
]
}]
})
}
}
// getting data
const data = await Neutralino.filesystem.readBinaryFile(entry[0])
this.state.current.thumbnail = event.target.files[0]
this.update()
}
// adding as blob
this.state.current.thumbnail = _arrayBufferToBase64(data)
this.update()
},
/**
* remove thumbnail
* remove current thumbnail for App
*
*
* @param {object} event
@ -328,42 +281,30 @@
handleRemoveThumbnail(event) {
event.preventDefault()
delete this.state.current.thumbnail
// remove value, make sure that onChange trigger also on same file
this.$('#apps-form-select-thumbnail').value = ''
this.state.current.thumbnail = null
this.update()
},
/**
* delete current
*
*
* @param {object} media
*
*/
handleDelete() {
confirmStore.trigger('open', {
'content': 'Delete "' + this.state.current.name + '" ?'
})
confirmStore.confirm(() => {
appsStore.remove(this.state.current)
})
toImage(media) {
return 'data:image/png;base64,' + media
},
/**
* reset data of current form
*
* @param {[type]} file
* @return {[type]}
*/
resolveMediaPath(file) {
let result = this.state.storagePath + '/' + file.path
reset() {
this.state.current = {
if (file instanceof Blob) {
result = file.path
}
return result
tagsStore.trigger('update', [])
}
}
}

@ -1,12 +1,12 @@
<tiny-sidebar-form-footer>
<div class="sidebar__footer">
<button class="button button--danger button--hover-icon-contrast m-bottom-0" disabled={ props.loading } type="button" if={ props.id } onclick={ () => { props.handleDelete() }}>
<button class="button button--danger m-bottom-0" disabled={ props.loading } if={ props.id }>
Delete
<svg class="icon fill-danger p-left-3" aria-hidden="true">
<svg class="icon fill-success p-left-3" aria-hidden="true">
<use xlink:href="symbol-defs.svg#icon-delete"></use>
</svg>
</button>
<button class="button button--hover-icon-contrast m-bottom-0" type="submit" disabled={ props.loading }>
<button class="button m-bottom-0" type="submit" disabled={ props.loading } close>
Save
<svg class="icon fill-success p-left-3" aria-hidden="true">
<use xlink:href="symbol-defs.svg#icon-check"></use>

@ -6,7 +6,7 @@
<div class="bar__end">
<button class="button button--icon button--hover-icon-contrast m-top-3 m-bottom-3" type="button" onclick={ props.close }>
<svg class="icon fill-danger" aria-hidden="true">
<use xlink:href="symbol-defs.svg#icon-close"></use>
<use xlink:href="/symbol-defs.svg#icon-close"></use>
</svg>
</button>
</div>

@ -9,23 +9,21 @@
export default {
/**
* adding default values
*
*
*/
onBeforeMount() {
this.state.open = false
this.state.loading = false
this.state.current = false
state: {
open: false, // if sidebar is open
loading: false, // if loading is shown
current: { // current data of form
}
},
/**
* close current sidebar
*
*
*/
handleClose() {
this.reset()
this.state.open = false
this.update()
},
@ -34,8 +32,7 @@ export default {
* getting css classes for sidebar
*
*
* @return {string}
*
* @return {String}
*/
getCssClasses() {
const classes = [
@ -47,5 +44,17 @@ export default {
}
return classes.join(' ')
},
/**
*
*
*/
onBeforeMount() {
if (!this.hasOwnProperty('reset')) {
throw new Error('reset-Function in Form is missing')
}
this.reset()
}
}

@ -7,107 +7,8 @@
*
*/
import AppsDatabase from './../database/apps.js'
import tagsStore from './../stores/tags.js'
import observable from '@riotjs/observable'
import observable from '@riotjs/observable'
export default observable({
export default observable({
parameters: {
sort: 'name',
tags: []
},
/**
* getting all apps
*
*/
get() {
const appsDatabase = new AppsDatabase()
appsDatabase.find(this.parameters).then((data) => {
this.trigger('ready', data)
})
},
/**
* getting single apps
*
* @param {uuid} id
*
*/
getOne(id) {
const appsDatabase = new AppsDatabase()
appsDatabase.findOneById(id).then((data) => {
this.trigger('readyOne', data)
})
},
/**
* create new app
*
* @param {object} data
*
*/
post(data) {
const appsDatabase = new AppsDatabase()
appsDatabase.create(data).then((data) => {
this.trigger('success', data)
tagsStore.get()
})
},
/**
* update app
*
* @param {object} data
*
*/
put(data) {
const appsDatabase = new AppsDatabase()
appsDatabase.update(data).then((data) => {
this.trigger('success', data)
tagsStore.get()
})
},
/**
* update app
*
* @param {object} data
*
*/
remove(data) {
const appsDatabase = new AppsDatabase()
appsDatabase.remove(data).then(() => {
this.trigger('close')
})
},
/**
* orderBy and run get
*
* @param {string} orderBy
*
*/
sort(column) {
this.parameters.sort = column
this.get()
},
/**
* filter and run get
*
* @param {array} tags
*
*/
filter(tags) {
this.parameters.tags = tags
this.get()
}
})
})

@ -1,5 +1,5 @@
/**
* Store for tags
* Store for apps
*
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
@ -7,20 +7,8 @@
*
*/
import TagsDatabase from './../database/tags.js'
import observable from '@riotjs/observable'
import observable from '@riotjs/observable'
export default observable({
export default observable({
/**
* get all tags
*
*/
get() {
const tagsDatabase = new TagsDatabase()
tagsDatabase.find().then((data) => {
this.trigger('ready', data)
})
}
})
})

@ -3,12 +3,15 @@
<header class="header m-bottom-3">
<div class="display-flex justify-content-space-between m-top-3">
<div class="display-flex">
<potato-sorting class="m-right-3"></potato-sorting>
<potato-filter></potata-filter>
<div>
<button class="button button--icon button--hover-icon-contrast m-bottom-0">
<svg class="icon icon--big">
<use xlink:href="symbol-defs.svg#icon-filter" />
</svg>
</button>
</div>
<div>
<potato-apps-form-button class="m-right-3"></potato-apps-form-button>
<potato-apps-form-button></potato-apps-form-button>
<potato-close-button></potato-close-button>
</div>
</div>
@ -17,26 +20,23 @@
<div class="apps">
<div class="grid">
<div class="col-12 col-md-3 col-lg-2" each={ app in state.apps }>
<div class="apps__item" onclick={ (event) => { handleClick(event, app) }}>
<img class="apps__item-background" if={ app.thumbnail } src="{ state.storagePath + '/' + app.thumbnail.path }" />
<div class="apps__item-inner">
<div class="apps__header p-4 right">
<button class="button button--icon button--hover-icon-contrast" onclick={ (event) => { handleEdit(event, app) }}>
<svg class="icon">
<use xlink:href="symbol-defs.svg#icon-settings" />
</svg>
</button>
<div class="apps__item" onclick={ (event) => { handleClick(event, app) }} style="{ addBackgroundStyles(app) }">
<div class="apps__header p-4 right">
<button class="button button--icon button--hover-icon-contrast" onclick={ (event) => { handleEdit(event, app) }}>
<svg class="icon">
<use xlink:href="symbol-defs.svg#icon-settings" />
</svg>
</button>
</div>
<div class="apps__item-panel p-4">
<h3 class="m-bottom-0">
{ app.name }
</h3>
<div if={ app.description } class="content m-top-3 m-bottom-last-child-0">
{ app.description }
</div>
<div class="apps__item-panel p-4">
<h3 class="m-bottom-0">
{ app.name }
</h3>
<div if={ app.description } class="content m-top-3 m-bottom-last-child-0">
{ app.description }
</div>
<div if={ app.tags && app.tags.length > 0 } class="m-top-3">
<span class="badge m-right-3" each={ tag in app.tags }>{ tag }</span>
</div>
<div if={ app.tags && app.tags.length > 0 } class="m-top-3">
<span class="badge m-right-3" each={ tag in app.tags }>{ tag }</span>
</div>
</div>
</div>
@ -47,23 +47,16 @@
<potato-apps-form></potato-apps-form>
</div>
<script>
import * as riot from 'riot'
import dayjs from 'dayjs'
import { spawn } from 'child_process'
import * as riot from 'riot'
import potatoAppsForm from './../forms/apps.riot'
import potatoAppsFormButton from './../components/appsFormButton.riot'
import potatoFilter from './../components/filter.riot'
import potatoSorting from './../components/sorting.riot'
import appsStore from './../stores/apps.js'
import formStore from './../stores/form.js'
import notificationStore from '@tiny-components/notification/src/notificationStore.js'
const { ipcRenderer } = require('electron')
// let it rain
riot.register('potato-apps-form', potatoAppsForm)
riot.mount('potato-apps-form')
@ -71,16 +64,10 @@
riot.register('potato-apps-form-button', potatoAppsFormButton)
riot.mount('potato-apps-form-buttons')
riot.register('potato-filter', potatoFilter)
riot.mount('potato-filter')
riot.register('potato-sorting', potatoSorting)
riot.mount('potato-sorting')
/**
*
*
* @author Björn Hase <me@herr-hase.wtf>
* @author Björn Hase
* @license hhttps://www.gnu.org/licenses/gpl-3.0.en.html GPL-3
* @link https://gitea.node001.net/HerrHase/potato-launcher.git
*
@ -93,8 +80,7 @@
*
*/
state: {
apps: [],
storagePath: undefined
apps: []
},
/**
@ -103,21 +89,19 @@
*/
onMounted() {
this.state.storagePath = ipcRenderer.sendSync('getPathUserData') + '/attachments'
// add event to receive data from pouchdb
appsStore.on('ready', (data) => {
this.state.apps = data
Neutralino.events.on('pouchdb.apps.ready', (event) => {
this.state.apps = event.detail
this.update()
})
// send event to get all after
appsStore.on('update', () => {
appsStore.get()
appsStore.on('updated', () => {
Neutralino.extensions.dispatch('js.neutralino.pouchdb', 'pouchdb.apps.find')
})
// trigger event to get all apps
appsStore.trigger('update')
appsStore.trigger('updated')
},
@ -129,33 +113,20 @@
*
*/
async handleClick(event, app) {
try {
const state = await Neutralino.os.execCommand(app.command)
const running = spawn(app.command)
// send notification for starting
running.on('spawn', (data) => {
notificationStore.success(app.name + ' is starting')
// adding current datetime for started app
app.date_started = dayjs()
appsStore.put(app)
})
// if app has a error
running.on('error', (error) => {
notificationStore.danger(app.name + ' could be not started, check if command is correct')
})
// if app is closing
running.on('close', (code) => {
if (code === 0) {
notificationStore.success(app.name + ' is closed')
// if there is a error message display send a notification
if (state.stdErr) {
notificationStore.danger(state.stdErr)
}
})
} catch(error) {
console.log(error)
}
},
/**
* edit app
* start app
*
* @param {object} event
* @param {object} app
@ -164,7 +135,24 @@
handleEdit(event, app) {
event.stopPropagation()
formStore.open(app._id)
},
/**
*
*
*/
addBackgroundStyles(app) {
let styles = false
if (app.thumbnail) {
styles = "background-image: url('data:image/jpg;base64," + app.thumbnail + "')"
}
return styles
}
}
</script>
</potato-apps-view>

@ -1,7 +1,3 @@
.justify-content-space-between {
justify-content: space-between;
}
.hidden {
display: none;
}

@ -7,26 +7,20 @@
.apps {
&__item {
position: relative;
&-background {
position: absolute;
object-fit: cover;
width: 100%;
height: 100%;
z-index: -1;
}
display: flex;
flex-flow: column;
justify-content: space-between;
&-inner {
display: flex;
flex-flow: column;
justify-content: space-between;
border: 1px solid var(--border);
border: 1px solid var(--border);
height: 450px;
// background image default
background-repeat: no-repeat;
background-size: cover;
background-position: 50%;
transition: transform 0.25s, box-shadow 0.5s;
}
height: 450px;
transition: transform 0.25s, box-shadow 0.5s;
&:hover {
cursor: pointer;

@ -15,12 +15,4 @@
}
}
}
&--hover-icon-text {
&:hover {
.icon {
fill: var(--text);
}
}
}
}

@ -1,6 +0,0 @@
.tiny-modal {
.modal__footer {
display: flex;
justify-content: space-between;
}
}

@ -1,67 +0,0 @@
.filter {
&__tags {
visibility: hidden;
position: absolute;
z-index: 100;
margin: 1em 0 0;
.button {
display: block;
margin-right: 1em;
.icon {
vertical-align: sub;
margin: 0 -0.25em 0 0.25em;
}
}
}
&:after {
content: '';
position: fixed;
left: 0;
top:0;
z-index: 99;
visibility: hidden;
width: 100%;
height: 100%;
background-color: #04040480;
}
.button--close {
display: none;
}
&__selected {
.button {
color: white;
padding: 0.8em 1.2em;
background: #878787;
.icon {
fill: white;
margin: 0 -0.25em 0 0.25em
}
}
}
&--open {
&:after {
visibility: visible;
}
.filter__tags {
visibility: visible;
}
.button--close {
display: inline-flex;
z-index: 101;
}
.button--open {
display: none;
}
}
}

@ -10,7 +10,5 @@
'components/field-tags',
'components/loading',
'components/buttons',
'components/filter',
'components/confirm',
'components/icons';

@ -16,8 +16,8 @@ const SvgSpritemapPlugin = require('svg-spritemap-webpack-plugin')
mix.webpackConfig({
plugins: [
new SvgSpritemapPlugin([
'node_modules/@tiny-components/plain-ui/src/icons/mono-icons/svg/*.svg'
], {
'node_modules/@tiny-components/plain-ui/src/icons/mono-icons/svg/*.svg'
], {
output: {
filename: 'symbol-defs.svg',
chunk: {
@ -27,7 +27,7 @@ mix.webpackConfig({
plugins: [{
name: 'convertStyleToAttrs',
active: true
}, {
},{
name: 'removeStyleElement',
active: true
}, {
@ -44,32 +44,25 @@ mix.webpackConfig({
})
],
module: {
rules: [{
test: /\.riot$/,
exclude: '/node_modules/',
use: [{
loader: '@riotjs/webpack-loader',
options: {
hot: false
}
}]
}]
},
externals: {
child_process: 'require("child_process")',
fs: 'require("fs")',
path: 'require("path")',
mkdirp: 'require("mkdirp")',
electron: 'require("electron")'
}
rules: [{
test: /\.riot$/,
exclude: '/node_modules/',
use: [{
loader: '@riotjs/webpack-loader',
options: {
hot: false
}
}]
}]
}
}).options({
processCssUrls: false,
target: 'node'
})
mix
.setPublicPath('./dist')
.setPublicPath('./build')
.js('src/js/app.js', 'js')
.copy('resources/js/neutralino.js', 'build/js')
.sass('src/scss/styles.scss', 'css')
.copyDirectory('node_modules/@tiny-components/plain-ui/src/fonts/**', 'dist/css')
.copyDirectory('resources/index.html', 'dist')
.copyDirectory('node_modules/@tiny-components/plain-ui/src/fonts/**', 'build/css')
.copyDirectory('resources/index.html', 'build')

Loading…
Cancel
Save