Compare commits
6 Commits
master
...
feature_db
| Author | SHA1 | Date | |
|---|---|---|---|
| ad6f3411c0 | |||
| 75316cf15d | |||
| 66fe009fa7 | |||
| a35f026f44 | |||
| 4d57642db4 | |||
| a76c3491d2 |
44
main.js
44
main.js
@ -1,28 +1,38 @@
|
|||||||
const { app, BrowserWindow } = require('electron')
|
const { app, BrowserWindow } = require('electron')
|
||||||
require('./src/data/sqlite-electron-ipc');
|
const path = require('path')
|
||||||
|
|
||||||
|
const here = app.getAppPath()
|
||||||
|
console.log('here', here)
|
||||||
|
|
||||||
let mainWin;
|
require('./src/data/sqlite-electron-ipc')
|
||||||
|
|
||||||
|
// Preload
|
||||||
|
const Sentry = require('@sentry/browser')
|
||||||
|
Sentry.init({
|
||||||
|
dsn: 'http://a12d5c5f800b406f8d1c0c5d2ed63a78@216.128.138.128:8000/1'
|
||||||
|
})
|
||||||
|
|
||||||
|
let mainWin
|
||||||
|
|
||||||
function createWindow () {
|
function createWindow () {
|
||||||
mainWin = new BrowserWindow({
|
mainWin = new BrowserWindow({
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
icon: __dirname + '/src/img/chains.png',
|
icon: __dirname + '/src/img/chains.png',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: false,
|
contextIsolation: false,
|
||||||
},
|
preload: path.join(here, 'preload.js')
|
||||||
nodeIntegration: true
|
},
|
||||||
})
|
nodeIntegration: true
|
||||||
|
})
|
||||||
|
|
||||||
//win.autoHideMenuBar = true;
|
// win.autoHideMenuBar = true;
|
||||||
|
|
||||||
mainWin.loadFile('index.html')
|
mainWin.loadFile('index.html')
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
createWindow()
|
createWindow()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
3431
package-lock.json
generated
3431
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "time-chain",
|
"name": "time-chain",
|
||||||
"version": "1.0.0",
|
"version": "1.1.4",
|
||||||
"description": "timechain",
|
"description": "timechain",
|
||||||
"author": "Jaosn Tudisco",
|
"author": "Jaosn Tudisco",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
@ -17,7 +17,7 @@
|
|||||||
"watch": "parcel --dist-dir ./src/dist --target \"jason\" start.js",
|
"watch": "parcel --dist-dir ./src/dist --target \"jason\" start.js",
|
||||||
"build-main": "parcel build --dist-dir ./src/dist --target \"jason\" main.js",
|
"build-main": "parcel build --dist-dir ./src/dist --target \"jason\" main.js",
|
||||||
"rebuild": "electron-rebuild -f -w better-sqlite3",
|
"rebuild": "electron-rebuild -f -w better-sqlite3",
|
||||||
"postinstall": "electron-builder install-app-deps"
|
"xxxpostinstall": "electron-builder install-app-deps"
|
||||||
},
|
},
|
||||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||||
"targets": {
|
"targets": {
|
||||||
@ -29,12 +29,13 @@
|
|||||||
"@parcel/transformer-less": "^2.3.0",
|
"@parcel/transformer-less": "^2.3.0",
|
||||||
"@parcel/transformer-sass": "^2.3.0",
|
"@parcel/transformer-sass": "^2.3.0",
|
||||||
"@riotjs/compiler": "^6.1.3",
|
"@riotjs/compiler": "^6.1.3",
|
||||||
"@riotjs/parcel-transformer-riot": "^7.0.3",
|
"@riotjs/parcel-transformer-riot": "https://git.ptud.biz/tudisco/parcel-transformer-riot/archive/v8.tar.gz",
|
||||||
"electron": "^16.0.7",
|
"electron": "^16.0.7",
|
||||||
"electron-rebuild": "^3.2.7",
|
"electron-rebuild": "^3.2.7",
|
||||||
"jest": "^27.4.7",
|
"jest": "^27.4.7",
|
||||||
"less": "^4.1.2",
|
"less": "^4.1.2",
|
||||||
"parcel": "^2"
|
"parcel": "^2",
|
||||||
|
"standard": "^16.0.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/browser": "^6.17.6",
|
"@sentry/browser": "^6.17.6",
|
||||||
@ -43,6 +44,8 @@
|
|||||||
"better-sqlite3": "^7.5.0",
|
"better-sqlite3": "^7.5.0",
|
||||||
"conf": "^10.1.1",
|
"conf": "^10.1.1",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
|
"debounce": "^1.2.1",
|
||||||
|
"electron-config": "^2.0.0",
|
||||||
"empty-lite": "^1.2.0",
|
"empty-lite": "^1.2.0",
|
||||||
"es6-interface": "^3.2.1",
|
"es6-interface": "^3.2.1",
|
||||||
"hash.js": "^1.1.7",
|
"hash.js": "^1.1.7",
|
||||||
@ -50,6 +53,7 @@
|
|||||||
"nanoid": "^3.2.0",
|
"nanoid": "^3.2.0",
|
||||||
"pubsub-js": "^1.9.4",
|
"pubsub-js": "^1.9.4",
|
||||||
"riot": "^6.1.2",
|
"riot": "^6.1.2",
|
||||||
"sanitize-html": "^2.6.1"
|
"sanitize-html": "^2.6.1",
|
||||||
|
"sweetalert2": "^11.4.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
preload.js
Normal file
22
preload.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Preload
|
||||||
|
const Sentry = require('@sentry/browser')
|
||||||
|
// const { BrowserTracing } require( '@sentry/tracing' )
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: 'http://a12d5c5f800b406f8d1c0c5d2ed63a78@216.128.138.128:8000/1',
|
||||||
|
|
||||||
|
// Alternatively, use `process.env.npm_package_version` for a dynamic release version
|
||||||
|
// if your build tool supports it.
|
||||||
|
release: 'timechain@1.0.0'
|
||||||
|
// integrations: [new BrowserTracing()],
|
||||||
|
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100%
|
||||||
|
// of transactions for performance monitoring.
|
||||||
|
// We recommend adjusting this value in production
|
||||||
|
// tracesSampleRate: 1.0
|
||||||
|
})
|
||||||
|
|
||||||
|
window.Sentry = Sentry
|
||||||
|
window.Timechain_isElectron = true
|
||||||
|
window.Timechain_dbModule = 'sqlite-client'
|
||||||
|
window.Timechain_canChooseDbLocation = true
|
||||||
@ -32,6 +32,14 @@ class TimeChainDataSqliteTag //extends Interface(InterfaceTag)
|
|||||||
return this.send('has',{tag:tag})
|
return this.send('has',{tag:tag})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
all(){
|
||||||
|
return this.send('all',{})
|
||||||
|
}
|
||||||
|
|
||||||
|
like(str){
|
||||||
|
return this.send('like',{str:str})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeChainDataSqliteTagLink //extends Interface(InterfaceTagLink)
|
class TimeChainDataSqliteTagLink //extends Interface(InterfaceTagLink)
|
||||||
|
|||||||
@ -1,146 +1,198 @@
|
|||||||
const { ipcMain } = require('electron');
|
const { ipcMain } = require('electron')
|
||||||
|
const { app } = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
const fs = require('fs')
|
||||||
|
// const config = app.getPath('userData');
|
||||||
|
|
||||||
const {app} = require('electron');
|
const Config = require('electron-config')
|
||||||
//const config = app.getPath('userData');
|
const config = new Config()
|
||||||
|
|
||||||
const {TimeChainDataSqliteRecord,ConnectToDatabase, TimeChainDataSqliteFile, TimeChainDataSqliteTag, TimeChainDataSqliteTagLink} = require('./sqlite');
|
let DBPath = config.get('database.path')
|
||||||
|
if (!DBPath) {
|
||||||
|
DBPathDir = app.getPath('userData')
|
||||||
|
DBPath = path.join(DBPathDir, '/timechain.db')
|
||||||
|
config.set('database.path', DBPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { TimeChainDataSqliteRecord, ConnectToDatabase, TimeChainDataSqliteFile, TimeChainDataSqliteTag, TimeChainDataSqliteTagLink } = require('./sqlite')
|
||||||
|
|
||||||
const appPath = app.getPath('userData');
|
console.log(DBPath)
|
||||||
|
|
||||||
const DBPath = appPath+"/timechain.db";
|
const DB = ConnectToDatabase(DBPath)
|
||||||
console.log(DBPath);
|
|
||||||
|
|
||||||
const DB = ConnectToDatabase(DBPath);
|
const DbRecord = new TimeChainDataSqliteRecord()
|
||||||
|
const DbFile = new TimeChainDataSqliteFile()
|
||||||
|
const DbTag = new TimeChainDataSqliteTag()
|
||||||
|
const DbTagLink = new TimeChainDataSqliteTagLink()
|
||||||
|
|
||||||
const DbRecord = new TimeChainDataSqliteRecord();
|
// ** Extra IPC Functions
|
||||||
const DbFile = new TimeChainDataSqliteFile();
|
|
||||||
const DbTag = new TimeChainDataSqliteTag();
|
|
||||||
const DbTagLink = new TimeChainDataSqliteTagLink();
|
|
||||||
//const configDir = app.getPath('userData');
|
|
||||||
//const appPath = app.getPath('exe');
|
|
||||||
|
|
||||||
|
ipcMain.handle('select-sqlite-file', (event, arg) => {
|
||||||
|
const { dialog } = require('electron')
|
||||||
|
const files = dialog.showOpenDialog({
|
||||||
|
filters: [{
|
||||||
|
name: 'Sqlite File',
|
||||||
|
extensions: ['db', 'db3']
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!files) return false
|
||||||
|
return files
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('create-sqlite-file', (event, arg) => {
|
||||||
|
const { dialog } = require('electron')
|
||||||
|
const files = dialog.showSaveDialogSync({
|
||||||
|
filters: [{
|
||||||
|
name: 'Sqlite File',
|
||||||
|
extensions: ['db', 'db3']
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
// ** Extra Data
|
if (!files) return false
|
||||||
ipcMain.handle('timechain-config-dir', (event,arg) => {
|
return files
|
||||||
return false;
|
})
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* Allows the UI to select another database file
|
||||||
|
*/
|
||||||
|
ipcMain.handle('timechain-database-open', (event, arg) => {
|
||||||
|
if (!arg.filename) return false
|
||||||
|
if (!fs.existsSync(arg.filename)) return false
|
||||||
|
config.set('database.path', arg.filename)
|
||||||
|
app.relaunch()
|
||||||
|
app.quit()
|
||||||
|
// DB = ConnectToDatabase(arg.filename)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the UI to create a new database instance
|
||||||
|
*/
|
||||||
|
ipcMain.handle('timechain-database-create', (event, arg) => {
|
||||||
|
if (!arg.filename) return false
|
||||||
|
console.log('database.path', arg.filename)
|
||||||
|
config.set('database.path', arg.filename)
|
||||||
|
app.relaunch()
|
||||||
|
app.quit()
|
||||||
|
// DB = ConnectToDatabase(arg.filename)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
// ** RECORD **
|
// ** RECORD **
|
||||||
console.log("Register timechain-record");
|
console.log('Register timechain-record')
|
||||||
ipcMain.handle('timechain-record', async (event,arg) => {
|
ipcMain.handle('timechain-record', async (event, arg) => {
|
||||||
|
let res = null
|
||||||
|
|
||||||
let res = null;
|
switch (arg.func) {
|
||||||
|
case 'add':
|
||||||
switch(arg.func){
|
res = await DbRecord.add(arg.uuid, arg.timestamp, arg.content, arg.mime, arg.hash)
|
||||||
case 'add':
|
break
|
||||||
res = await DbRecord.add(arg.uuid, arg.timestamp, arg.content, arg.mime, arg.hash);
|
case 'delete':
|
||||||
break;
|
res = await DbRecord.delete(arg.uuid)
|
||||||
case 'delete':
|
break
|
||||||
res = await DbRecord.delete(arg.uuid);
|
case 'update':
|
||||||
break;
|
res = await DbRecord.update(arg.uuid, arg.content, arg.mime, arg.hash)
|
||||||
case 'update':
|
break
|
||||||
res = await DbRecord.update(arg.uuid,arg.content,arg.mime,arg.hash);
|
case 'find':
|
||||||
break;
|
res = await DbRecord.find(arg.search, arg.sort, arg.limit, arg.offset)
|
||||||
case 'find':
|
break
|
||||||
res = await DbRecord.find(arg.search,arg.sort,arg.limit,arg.offset);
|
case 'get':
|
||||||
break;
|
res = await DbRecord.get(arg.uuid)
|
||||||
case 'get':
|
break
|
||||||
res = await DbRecord.get(arg.uuid);
|
default:
|
||||||
break;
|
res = new Error('unknown command')
|
||||||
default:
|
}
|
||||||
res = new Error('unknown command');
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
|
|
||||||
|
return res
|
||||||
})
|
})
|
||||||
|
|
||||||
// ** FILE **
|
// ** FILE **
|
||||||
|
|
||||||
ipcMain.handle('timechain-file', async (event, arg) => {
|
ipcMain.handle('timechain-file', async (event, arg) => {
|
||||||
let res = null;
|
let res = null
|
||||||
|
|
||||||
switch(arg.func){
|
switch (arg.func) {
|
||||||
case 'add':
|
case 'add':
|
||||||
res = await DbFile.add(arg.uuid_record,arg.uuid,arg.timestamp,arg.content,arg.mime,arg.hash);
|
res = await DbFile.add(arg.uuid_record, arg.uuid, arg.timestamp, arg.content, arg.mime, arg.hash)
|
||||||
break;
|
break
|
||||||
case 'update':
|
case 'update':
|
||||||
res = await DbFile.update(arg.uuid,arg.timestamp,arg.content,arg.mime,arg.hash);
|
res = await DbFile.update(arg.uuid, arg.timestamp, arg.content, arg.mime, arg.hash)
|
||||||
break;
|
break
|
||||||
case 'get-record':
|
case 'get-record':
|
||||||
res = await DbFile.getByRecord(arg.uuid_record);
|
res = await DbFile.getByRecord(arg.uuid_record)
|
||||||
break;
|
break
|
||||||
case 'delete-record':
|
case 'delete-record':
|
||||||
res = await DbFile.deleteRecord(arg.uuid_record);
|
res = await DbFile.deleteRecord(arg.uuid_record)
|
||||||
break;
|
break
|
||||||
case 'get':
|
case 'get':
|
||||||
res = await DbFile.get(arg.uuid);
|
res = await DbFile.get(arg.uuid)
|
||||||
break;
|
break
|
||||||
case 'delete':
|
case 'delete':
|
||||||
res = await DbFile.delete(arg.uuid);
|
res = await DbFile.delete(arg.uuid)
|
||||||
break;
|
break
|
||||||
default:
|
default:
|
||||||
res = new Error('Unknow a command');
|
res = new Error('Unknow a command')
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res
|
||||||
});
|
})
|
||||||
|
|
||||||
// ** TAG **
|
// ** TAG **
|
||||||
|
|
||||||
ipcMain.handle('timechain-tag', async (event, arg) => {
|
ipcMain.handle('timechain-tag', async (event, arg) => {
|
||||||
|
let res = null
|
||||||
|
|
||||||
let res = null;
|
switch (arg.func) {
|
||||||
|
case 'add':
|
||||||
|
res = await DbTag.add(arg.tag)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
res = await DbTag.delete(arg.tag)
|
||||||
|
break
|
||||||
|
case 'has':
|
||||||
|
res = await DbTag.delete(arg.tag)
|
||||||
|
break
|
||||||
|
case 'all':
|
||||||
|
res = await DbTag.all()
|
||||||
|
break;
|
||||||
|
case 'like':
|
||||||
|
res = await DbTag.like(arg.str)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = new Error('Command Unknown')
|
||||||
|
}
|
||||||
|
|
||||||
switch(arg.func){
|
return res
|
||||||
case 'add':
|
})
|
||||||
res = await DbTag.add(arg.tag);
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
res = await DbTag.delete(arg.tag);
|
|
||||||
break;
|
|
||||||
case 'has':
|
|
||||||
res = await DbTag.delete(arg.tag);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = new Error('Command Unknown');
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// TAG LINK
|
// TAG LINK
|
||||||
|
|
||||||
ipcMain.handle('timechain-taglink', async (event, arg) => {
|
ipcMain.handle('timechain-taglink', async (event, arg) => {
|
||||||
|
let res = null
|
||||||
|
|
||||||
let res = null;
|
switch (arg.func) {
|
||||||
|
case 'add':
|
||||||
|
res = await DbTagLink.add(arg.uuid, arg.tag)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
res = await DbTagLink.delete(arg.uuid, arg.tag)
|
||||||
|
break
|
||||||
|
case 'delete-tag':
|
||||||
|
res = await DbTagLink.deleteTag(arg.tag)
|
||||||
|
break
|
||||||
|
case 'delete-record':
|
||||||
|
res = await DbTagLink.deleteRecord(arg.uuid)
|
||||||
|
break
|
||||||
|
case 'get-records':
|
||||||
|
res = await DbTagLink.getRecords(atg.tag)
|
||||||
|
break
|
||||||
|
case 'get-tags':
|
||||||
|
res = await DbTagLink.getTags(atg.uuid)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
res = Error('Commande not known')
|
||||||
|
}
|
||||||
|
|
||||||
switch(arg.func){
|
return res
|
||||||
case 'add':
|
})
|
||||||
res = await DbTagLink.add(arg.uuid,arg.tag)
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
res = await DbTagLink.delete(arg.uuid,arg.tag);
|
|
||||||
break;
|
|
||||||
case 'delete-tag':
|
|
||||||
res = await DbTagLink.deleteTag(arg.tag);
|
|
||||||
break;
|
|
||||||
case 'delete-record':
|
|
||||||
res = await DbTagLink.deleteRecord(arg.uuid);
|
|
||||||
break;
|
|
||||||
case 'get-records':
|
|
||||||
res = await DbTagLink.getRecords(atg.tag);
|
|
||||||
break;
|
|
||||||
case 'get-tags':
|
|
||||||
res = await DbTagLink.getTags(atg.uuid);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = Error("Commande not known");
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,471 +1,563 @@
|
|||||||
const Interface = require("es6-interface");
|
const Interface = require('es6-interface')
|
||||||
const {InterfaceRecord,InterfaceFile,InterfaceTag,InterfaceTagLink} = require("./interfaces");
|
const { InterfaceRecord, InterfaceFile, InterfaceTag, InterfaceTagLink } = require('./interfaces')
|
||||||
|
const Database = require('better-sqlite3')
|
||||||
|
|
||||||
let db = null;
|
let db = null
|
||||||
|
|
||||||
const ConnectToDatabase = (path)=>{
|
const ConnectToDatabase = (path) => {
|
||||||
db = require('better-sqlite3')(path, {});
|
if (db) {
|
||||||
return db;
|
db.close()
|
||||||
|
db = null
|
||||||
|
}
|
||||||
|
db = new Database(path, {})
|
||||||
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeChainDataSqliteTag extends Interface(InterfaceTag) {
|
class TimeChainDataSqliteTag extends Interface(InterfaceTag) {
|
||||||
|
constructor () {
|
||||||
constructor(){
|
super()
|
||||||
super();
|
const table = `CREATE TABLE IF NOT EXISTS "tags" (
|
||||||
const table = `CREATE TABLE IF NOT EXISTS "tags" (
|
"tag" TEXT UNIQUE,
|
||||||
"tag" TEXT UNIQUE,
|
"created_at" INTEGER NOT NULL,
|
||||||
"created_at" INTEGER NOT NULL,
|
"updated_at" INTEGER NOT NULL,
|
||||||
"updated_at" INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY("tag")
|
PRIMARY KEY("tag")
|
||||||
);`;
|
);`
|
||||||
|
|
||||||
const table_idx = ``;
|
const table_idx = ''
|
||||||
|
|
||||||
if(!db){
|
if (!db) {
|
||||||
throw new Error("Database is not connected");
|
throw new Error('Database is not connected')
|
||||||
|
}
|
||||||
|
|
||||||
|
db.exec(table + '\n' + table_idx)
|
||||||
|
this.db = db
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_add () {
|
||||||
|
if (!this._table_add) {
|
||||||
|
this._table_add = db.prepare('INSERT INTO tags (tag,created_at,updated_at) VALUES (?,?,?)')
|
||||||
|
}
|
||||||
|
return this._table_add
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_delete () {
|
||||||
|
if (!this._table_delete) {
|
||||||
|
this._table_delete = db.prepare('DELETE FROM tags WHERE tag = ?')
|
||||||
|
}
|
||||||
|
return this._table_delete
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_get () {
|
||||||
|
if (!this._table_get) {
|
||||||
|
this._table_get = db.prepare('SELECT * FROM tags WHERE tag = ?')
|
||||||
|
}
|
||||||
|
return this._table_get
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_get_like () {
|
||||||
|
if (!this._table_get) {
|
||||||
|
this._table_get = db.prepare('SELECT * FROM tags WHERE tag LIKE ?')
|
||||||
|
}
|
||||||
|
return this._table_get
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_get_all() {
|
||||||
|
if (!this._table_get_all) {
|
||||||
|
this._table_get_all = db.prepare('SELECT * FROM tags')
|
||||||
|
}
|
||||||
|
return this._table_get_all
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_count () {
|
||||||
|
if (!this._table_count) {
|
||||||
|
this._table_count = db.prepare('SELECT count(tag) as cnt FROM tags WHERE tag = ?')
|
||||||
|
}
|
||||||
|
return this._table_count
|
||||||
|
}
|
||||||
|
|
||||||
|
add (tag) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.has(tag).then(cnt => {
|
||||||
|
if (cnt) {
|
||||||
|
return resolve(1)
|
||||||
|
} else {
|
||||||
|
const dt = Math.floor(Date.now())
|
||||||
|
const res = this.table_add.run(tag, dt, dt)
|
||||||
|
return resolve(res?.changes)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
all() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const res = this.table_get_all.all();
|
||||||
|
return resolve(res);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
db.exec(table + "\n" + table_idx);
|
like(str){
|
||||||
this.db = db;
|
return new Promise(resolve => {
|
||||||
}
|
const res = this.table_get_like.all(str + '%');
|
||||||
|
return resolve(res);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
get table_add(){
|
delete (tag) {
|
||||||
if(!this._table_add){
|
return new Promise(resolve => {
|
||||||
this._table_add = db.prepare("INSERT INTO tags (tag,created_at,updated_at) VALUES (?,?,?)");
|
const dt = Math.floor(Date.now())
|
||||||
}
|
const res = this.table_delete.run(tag)
|
||||||
return this._table_add;
|
return resolve(res?.changes)
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
get table_delete(){
|
get (tag) {
|
||||||
if(!this._table_delete){
|
return new Promise(resolve => {
|
||||||
this._table_delete = db.prepare("DELETE FROM tags WHERE tag = ?");
|
const res = this.table_get.get(tag)
|
||||||
}
|
return resolve(res)
|
||||||
return this._table_delete;
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
get table_get(){
|
|
||||||
if(!this._table_get){
|
|
||||||
this._table_get = db.prepare("SELECT * FROM tags WHERE tag = ?");
|
|
||||||
}
|
|
||||||
return this._table_get;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_count(){
|
|
||||||
if(!this._table_count){
|
|
||||||
this._table_count = db.prepare("SELECT count(tag) as cnt FROM tags WHERE tag = ?");
|
|
||||||
}
|
|
||||||
return this._table_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(tag){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
this.has(tag).then(cnt=>{
|
|
||||||
if(cnt){
|
|
||||||
return resolve(1);
|
|
||||||
}else{
|
|
||||||
const dt = Math.floor(Date.now());
|
|
||||||
const res = this.table_add.run(tag,dt,dt);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(tag){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const dt = Math.floor(Date.now());
|
|
||||||
const res = this.table_delete.run(tag);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get(tag){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const res = this.table_get.get(tag);
|
|
||||||
return resolve(res);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
has(tag){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const res = this.table_count.get(tag);
|
|
||||||
return resolve(res && res.cnt>0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
has (tag) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const res = this.table_count.get(tag)
|
||||||
|
return resolve(res && res.cnt > 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeChainDataSqliteTagLink extends Interface(InterfaceTagLink) {
|
class TimeChainDataSqliteTagLink extends Interface(InterfaceTagLink) {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
|
||||||
constructor(){
|
this.table = `CREATE TABLE IF NOT EXISTS "taglink" (
|
||||||
super();
|
"uuid" TEXT NOT NULL,
|
||||||
|
"tag" TEXT NOT NULL,
|
||||||
this.table = `CREATE TABLE IF NOT EXISTS "taglink" (
|
"created_at" INTEGER NOT NULL
|
||||||
"uuid" TEXT NOT NULL,
|
);`
|
||||||
"tag" TEXT NOT NULL,
|
this.table_idx = `
|
||||||
"created_at" INTEGER NOT NULL
|
|
||||||
);`;
|
|
||||||
this.table_idx = `
|
|
||||||
CREATE INDEX IF NOT EXISTS "uuid_idx" ON "taglink" (
|
CREATE INDEX IF NOT EXISTS "uuid_idx" ON "taglink" (
|
||||||
"uuid"
|
"uuid"
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS "tag_idx" ON "taglink" (
|
CREATE INDEX IF NOT EXISTS "tag_idx" ON "taglink" (
|
||||||
"tag"
|
"tag"
|
||||||
);
|
);
|
||||||
`;
|
`
|
||||||
|
|
||||||
db.exec(this.table + "\n" + this.table_idx);
|
db.exec(this.table + '\n' + this.table_idx)
|
||||||
this.db = db;
|
this.db = db
|
||||||
}
|
}
|
||||||
|
|
||||||
get table_add(){
|
|
||||||
if(!this._table_add){
|
|
||||||
this._table_add = db.prepare('INSERT INTO taglink (uuid,tag,created_at) VALUES (?,?,?)');
|
|
||||||
}
|
|
||||||
return this._table_add;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_delete(){
|
get table_add () {
|
||||||
if(!this._table_delete){
|
if (!this._table_add) {
|
||||||
this._table_delete = db.prepare('DELETE FROM taglink WHERE uuid=? AND tag=?');
|
this._table_add = db.prepare('INSERT INTO taglink (uuid,tag,created_at) VALUES (?,?,?)')
|
||||||
}
|
|
||||||
return this._table_delete;
|
|
||||||
}
|
}
|
||||||
|
return this._table_add
|
||||||
|
}
|
||||||
|
|
||||||
get table_delete_tag(){
|
get table_delete () {
|
||||||
if(!this._table_delete_tag){
|
if (!this._table_delete) {
|
||||||
this._table_delete_tag = db.prepare('DELETE FROM taglink WHERE tag=?');
|
this._table_delete = db.prepare('DELETE FROM taglink WHERE uuid=? AND tag=?')
|
||||||
}
|
|
||||||
return this._table_delete_tag;
|
|
||||||
}
|
}
|
||||||
|
return this._table_delete
|
||||||
|
}
|
||||||
|
|
||||||
get table_delete_record(){
|
get table_delete_tag () {
|
||||||
if(!this._table_delete_record){
|
if (!this._table_delete_tag) {
|
||||||
this._table_delete_record = db.prepare('DELETE FROM taglink WHERE uuid=?');
|
this._table_delete_tag = db.prepare('DELETE FROM taglink WHERE tag=?')
|
||||||
}
|
|
||||||
return this._table_delete_record;
|
|
||||||
}
|
}
|
||||||
|
return this._table_delete_tag
|
||||||
|
}
|
||||||
|
|
||||||
get table_get_records(){
|
get table_delete_record () {
|
||||||
if(!this._table_get_records){
|
if (!this._table_delete_record) {
|
||||||
this._table_get_records = db.prepare("SELECT * FROM taglink WHERE tag=?");
|
this._table_delete_record = db.prepare('DELETE FROM taglink WHERE uuid=?')
|
||||||
}
|
|
||||||
return this._table_get_records;
|
|
||||||
}
|
}
|
||||||
|
return this._table_delete_record
|
||||||
|
}
|
||||||
|
|
||||||
get table_get_tags(){
|
get table_get_records () {
|
||||||
if(!this._table_get_tags){
|
if (!this._table_get_records) {
|
||||||
this._table_get_tags = db.prepare("SELECT * FROM taglink WHERE uuid=?");
|
this._table_get_records = db.prepare('SELECT * FROM taglink WHERE tag=?')
|
||||||
}
|
|
||||||
return this._table_get_tags;
|
|
||||||
}
|
}
|
||||||
|
return this._table_get_records
|
||||||
|
}
|
||||||
|
|
||||||
add(uuid,tag){
|
get table_get_tags () {
|
||||||
return new Promise(resolve=>{
|
if (!this._table_get_tags) {
|
||||||
const prepare = this.table_add;
|
this._table_get_tags = db.prepare('SELECT * FROM taglink WHERE uuid=?')
|
||||||
const dt = Math.floor(Date.now());
|
|
||||||
const res = prepare.run(uuid,tag,dt);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return this._table_get_tags
|
||||||
|
}
|
||||||
|
|
||||||
delete(uuid,tag){
|
add (uuid, tag) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_delete;
|
const prepare = this.table_add
|
||||||
const res = prepare.run(uuid,tag);
|
const dt = Math.floor(Date.now())
|
||||||
return resolve(res?.changes);
|
const res = prepare.run(uuid, tag, dt)
|
||||||
});
|
return resolve(res?.changes)
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
deleteTag(tag){
|
delete (uuid, tag) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_delete_tag;
|
const prepare = this.table_delete
|
||||||
const res = prepare.run(tag);
|
const res = prepare.run(uuid, tag)
|
||||||
return resolve(res?.changes);
|
return resolve(res?.changes)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteRecord(uuid){
|
deleteTag (tag) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_delete_record;
|
const prepare = this.table_delete_tag
|
||||||
const res = prepare.run(uuid);
|
const res = prepare.run(tag)
|
||||||
return resolve(res?.changes);
|
return resolve(res?.changes)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getRecords(tag){
|
deleteRecord (uuid) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_get_records;
|
const prepare = this.table_delete_record
|
||||||
const res = prepare.all(tag);
|
const res = prepare.run(uuid)
|
||||||
return resolve(res);
|
return resolve(res?.changes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(uuid){
|
getRecords (tag) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_get_tags;
|
const prepare = this.table_get_records
|
||||||
const res = prepare.all(uuid);
|
const res = prepare.all(tag)
|
||||||
return resolve(res);
|
return resolve(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTags (uuid) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const prepare = this.table_get_tags
|
||||||
|
const res = prepare.all(uuid)
|
||||||
|
return resolve(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeChainDataSqliteFile extends Interface(InterfaceFile) {
|
class TimeChainDataSqliteFile extends Interface(InterfaceFile) {
|
||||||
|
constructor () {
|
||||||
constructor(){
|
super()
|
||||||
super();
|
const table = `CREATE TABLE IF NOT EXISTS "files" (
|
||||||
const table = `CREATE TABLE IF NOT EXISTS "files" (
|
"uuid" TEXT UNIQUE,
|
||||||
"uuid" TEXT UNIQUE,
|
"uuid_record" TEXT NOT NULL,
|
||||||
"uuid_record" TEXT NOT NULL,
|
"timestamp" INTEGER NOT NULL,
|
||||||
"timestamp" INTEGER NOT NULL,
|
"content" BLOB NOT NULL,
|
||||||
"content" BLOB NOT NULL,
|
"mime" TEXT NOT NULL,
|
||||||
"mime" TEXT NOT NULL,
|
"hash" TEXT,
|
||||||
"hash" TEXT,
|
"created_at" INTEGER NOT NULL,
|
||||||
"created_at" INTEGER NOT NULL,
|
"updated_at" INTEGER NOT NULL,
|
||||||
"updated_at" INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY("uuid")
|
PRIMARY KEY("uuid")
|
||||||
);`;
|
);`
|
||||||
const table_idx = `
|
const table_idx = `
|
||||||
CREATE INDEX IF NOT EXISTS "files_idx_record" ON "files" (
|
CREATE INDEX IF NOT EXISTS "files_idx_record" ON "files" (
|
||||||
"uuid_record"
|
"uuid_record"
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS "files_idx_time" ON "files" (
|
CREATE INDEX IF NOT EXISTS "files_idx_time" ON "files" (
|
||||||
"timestamp" DESC
|
"timestamp" DESC
|
||||||
);`;
|
);`
|
||||||
|
|
||||||
if(!db){
|
if (!db) {
|
||||||
throw new Error("Database is not connected");
|
throw new Error('Database is not connected')
|
||||||
}
|
|
||||||
|
|
||||||
db.exec(table + "\n" + table_idx);
|
|
||||||
this.db = db;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get table_insert() {
|
db.exec(table + '\n' + table_idx)
|
||||||
if(!this._table_insert){
|
this.db = db
|
||||||
this._table_insert = db.prepare(`INSERT INTO files (uuid,uuid_record,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)`);
|
}
|
||||||
}
|
|
||||||
return this._table_insert;
|
get table_insert () {
|
||||||
|
if (!this._table_insert) {
|
||||||
|
this._table_insert = db.prepare('INSERT INTO files (uuid,uuid_record,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)')
|
||||||
|
}
|
||||||
|
return this._table_insert
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_update () {
|
||||||
|
if (!this._table_update) {
|
||||||
|
this._table_update = db.prepare('UPDATE files SET timestamp = ?, content = ?, mime = ? hash = ?, updated_at = ? WHERE uuid = ?')
|
||||||
|
}
|
||||||
|
return this._table_update
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_delete () {
|
||||||
|
if (!this._table_delete) {
|
||||||
|
this._table_delete = db.prepare('DELETE FROM files WHERE uuid = ?')
|
||||||
|
}
|
||||||
|
return this._table_delete
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_delete_record () {
|
||||||
|
if (!this._table_delete_record) {
|
||||||
|
this._table_delete_record = db.prepare('DELETE FROM files WHERE uuid_record = ?')
|
||||||
}
|
}
|
||||||
|
|
||||||
get table_update() {
|
return this._table_delete_record
|
||||||
if(!this._table_update){
|
}
|
||||||
this._table_update = db.prepare(`UPDATE files SET timestamp = ?, content = ?, mime = ? hash = ?, updated_at = ? WHERE uuid = ?`);
|
|
||||||
}
|
|
||||||
return this._table_update;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_delete() {
|
get table_find_one () {
|
||||||
if(!this._table_delete){
|
if (!this._table_find_one) {
|
||||||
this._table_delete = db.prepare(`DELETE FROM files WHERE uuid = ?`);
|
this._table_find_one = db.prepare('SELECT * FROM files WHERE uuid = ?')
|
||||||
}
|
|
||||||
return this._table_delete;
|
|
||||||
}
|
}
|
||||||
|
return this._table_find_one
|
||||||
|
}
|
||||||
|
|
||||||
get table_delete_record() {
|
get table_find_record () {
|
||||||
|
if (!this._table_find_record) {
|
||||||
if(!this._table_delete_record){
|
this._table_find_record = db.prepare('SELECT * FROM files WHERE uuid_record = ?')
|
||||||
this._table_delete_record = db.prepare(`DELETE FROM files WHERE uuid_record = ?`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._table_delete_record;
|
|
||||||
}
|
}
|
||||||
|
return this._table_find_record
|
||||||
|
}
|
||||||
|
|
||||||
get table_find_one() {
|
add (uuid_record, uuid, timestamp, content, mime, hash) {
|
||||||
if(!this._table_find_one){
|
return new Promise(resolve => {
|
||||||
this._table_find_one = db.prepare(`SELECT * FROM files WHERE uuid = ?`);
|
const dt = Math.floor(Date.now())
|
||||||
}
|
const res = this.table_insert.run(uuid, uuid_record, timestamp, content, mime, hash, dt, dt)
|
||||||
return this._table_find_one;
|
return resolve(res?.changes)
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
get table_find_record(){
|
getByRecord (uuid_record) {
|
||||||
if(!this._table_find_record){
|
return new Promise(resolve => {
|
||||||
this._table_find_record = db.prepare(`SELECT * FROM files WHERE uuid_record = ?`);
|
const res = this.table_find_record.get(uuid_record)
|
||||||
}
|
return resolve(res)
|
||||||
return this._table_find_record;
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
add(uuid_record,uuid,timestamp,content,mime,hash){
|
get (uuid) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const dt = Math.floor(Date.now());
|
const res = this.table_find_one.get(uuid)
|
||||||
const res = this.table_insert.run(uuid,uuid_record,timestamp,content,mime,hash,dt,dt);
|
return resolve(res)
|
||||||
return resolve(res?.changes);
|
})
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
getByRecord(uuid_record){
|
delete (uuid) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const res = this.table_find_record.get(uuid_record);
|
const prepare = this.table_delete
|
||||||
return resolve(res);
|
const res = prepare.run(uuid)
|
||||||
});
|
return resolve(res?.changes)
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
get(uuid){
|
deleteRecord (uuid_record) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const res = this.table_find_one.get(uuid);
|
const res = this.table_delete_record.run(uuid_record)
|
||||||
return resolve(res);
|
return resolve(res?.changes)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(uuid){
|
update (uuid, timestamp, content, mime, hash) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_delete;
|
const res = this.table_update.run(timestamp, content, mime, hash, uuid)
|
||||||
const res = prepare.run(uuid);
|
return resolve(res?.changes)
|
||||||
return resolve(res?.changes);
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
deleteRecord(uuid_record){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const res = this.table_delete_record.run(uuid_record);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
update(uuid,timestamp,content,mime,hash){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const res = this.table_update.run(timestamp,content,mime,hash,uuid);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
||||||
|
constructor () {
|
||||||
constructor(){
|
super()
|
||||||
super();
|
// TODO: Create Tables Here if not exist
|
||||||
//TODO: Create Tables Here if not exist
|
const table = `CREATE TABLE IF NOT EXISTS "records" (
|
||||||
const table = `CREATE TABLE IF NOT EXISTS "records" (
|
"uuid" TEXT NOT NULL UNIQUE,
|
||||||
"uuid" TEXT NOT NULL UNIQUE,
|
"timestamp" INTEGER NOT NULL,
|
||||||
"timestamp" INTEGER NOT NULL,
|
"content" TEXT NOT NULL,
|
||||||
"content" TEXT NOT NULL,
|
"mime" TEXT NOT NULL,
|
||||||
"mime" TEXT NOT NULL,
|
"hash" TEXT,
|
||||||
"hash" TEXT,
|
"created_at" INTEGER NOT NULL,
|
||||||
"created_at" INTEGER NOT NULL,
|
"updated_at" INTEGER NOT NULL,
|
||||||
"updated_at" INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY("uuid")
|
PRIMARY KEY("uuid")
|
||||||
);`;
|
);`
|
||||||
const table_idx = `CREATE INDEX IF NOT EXISTS "records_idx_timestamp" ON "records" (
|
const table_idx = `CREATE INDEX IF NOT EXISTS "records_idx_timestamp" ON "records" (
|
||||||
"timestamp" DESC
|
"timestamp" DESC
|
||||||
);`
|
);`
|
||||||
|
|
||||||
if(!db){
|
if (!db) {
|
||||||
throw new Error("Database is not connected");
|
throw new Error('Database is not connected')
|
||||||
}
|
|
||||||
|
|
||||||
db.exec(table + "\n" + table_idx);
|
|
||||||
this.db = db;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get table_insert() {
|
db.exec(table + '\n' + table_idx)
|
||||||
if(!this._table_insert){
|
this.db = db
|
||||||
this._table_insert = db.prepare(`INSERT INTO records (uuid,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)`);
|
}
|
||||||
}
|
|
||||||
return this._table_insert;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_update(){
|
get table_insert () {
|
||||||
if(!this._table_update){
|
if (!this._table_insert) {
|
||||||
this._table_update = db.prepare(`UPDATE records SET timestamp = ?, content = ?, mime = ?, hash = ? updated_at = ? WHERE uuid = ?`);
|
this._table_insert = db.prepare('INSERT INTO records (uuid,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)')
|
||||||
}
|
|
||||||
return this._table_update;
|
|
||||||
}
|
}
|
||||||
|
return this._table_insert
|
||||||
|
}
|
||||||
|
|
||||||
get table_delete(){
|
get table_update () {
|
||||||
if(!this._table_delete){
|
if (!this._table_update) {
|
||||||
this._table_delete = db.prepare(`DELETE FROM records WHERE uuid = ?`);
|
this._table_update = db.prepare('UPDATE records SET timestamp = ?, content = ?, mime = ?, hash = ? updated_at = ? WHERE uuid = ?')
|
||||||
}
|
|
||||||
return this._table_delete;
|
|
||||||
}
|
}
|
||||||
|
return this._table_update
|
||||||
|
}
|
||||||
|
|
||||||
get table_fine_one(){
|
get table_delete () {
|
||||||
if(!this._table_fine_one){
|
if (!this._table_delete) {
|
||||||
this._table_fine_one = db.prepare(`SELECT * FROM records WHERE uuid = ?`);
|
this._table_delete = db.prepare('DELETE FROM records WHERE uuid = ?')
|
||||||
}
|
|
||||||
return this._table_fine_one;
|
|
||||||
}
|
}
|
||||||
|
return this._table_delete
|
||||||
|
}
|
||||||
|
|
||||||
get table_find(){
|
get table_fine_one () {
|
||||||
if(!this._table_find){
|
if (!this._table_fine_one) {
|
||||||
this._table_find = db.prepare(`
|
this._table_fine_one = db.prepare('SELECT * FROM records WHERE uuid = ?')
|
||||||
select records.*, GROUP_CONCAT(taglink.tag,',') AS tags
|
}
|
||||||
|
return this._table_fine_one
|
||||||
|
}
|
||||||
|
|
||||||
|
get table_find () {
|
||||||
|
if (!this._table_find) {
|
||||||
|
this._table_find = db.prepare(`
|
||||||
|
select records.*,
|
||||||
|
(SELECT GROUP_CONCAT(tag,',') FROM taglink WHERE taglink.uuid = records.uuid) as tags
|
||||||
from records
|
from records
|
||||||
left join taglink on (taglink.uuid = records.uuid)
|
|
||||||
group by records.uuid
|
|
||||||
order by records.timestamp DESC
|
order by records.timestamp DESC
|
||||||
limit ? offset ?
|
limit ? offset ?
|
||||||
`);
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._table_find
|
||||||
|
}
|
||||||
|
|
||||||
|
generator_find_sql (tags) {
|
||||||
|
let query = `
|
||||||
|
select records.*,
|
||||||
|
(SELECT GROUP_CONCAT(tag,',') FROM taglink WHERE taglink.uuid = records.uuid) as tags
|
||||||
|
from records
|
||||||
|
left join taglink on (taglink.uuid = records.uuid)
|
||||||
|
{where}
|
||||||
|
group by records.uuid
|
||||||
|
order by records.timestamp DESC
|
||||||
|
limit ? offset ?
|
||||||
|
`;
|
||||||
|
|
||||||
|
const where = [];
|
||||||
|
|
||||||
|
tags.forEach(tag => {
|
||||||
|
|
||||||
|
if( tag.indexOf(':') != -1 ){
|
||||||
|
//Skip Filter
|
||||||
|
const parts = tag.split(':');
|
||||||
|
const cmd = parts[0];
|
||||||
|
|
||||||
|
const dayjs = require('dayjs');
|
||||||
|
|
||||||
|
switch (cmd){
|
||||||
|
case 'before':
|
||||||
|
const time_before = Math.floor(dayjs(parts[1]).toDate().getTime());
|
||||||
|
where.push(`records.timestamp < ${time_before}`);
|
||||||
|
break;
|
||||||
|
case 'after':
|
||||||
|
const time_after = Math.floor(dayjs(parts[1]).toDate().getTime());
|
||||||
|
where.push(`records.timestamp > ${time_after}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
let cleantag = tag.replace(/\'/g,"''");
|
||||||
|
where.push(`taglink.tag = '${cleantag}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._table_find;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
add(uuid,timestamp,content,mime,hash){
|
let where_string = "WHERE " + where.join(" AND ");
|
||||||
return new Promise(resolve=>{
|
|
||||||
const dt = Math.floor(Date.now());
|
|
||||||
const res = this.table_insert.run(uuid,timestamp,content,mime,hash,dt,dt);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get(uuid){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const rec = this.table_fine_one.get(uuid);
|
|
||||||
return resolve(rec);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
find(search,sort=null,limit=undefined,offset=0){
|
query = query.replace('{where}', where_string);
|
||||||
//TODO: add logic for seach and sort (Currently does nothing)
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const prepare = this.table_find;
|
|
||||||
|
|
||||||
const res = prepare.all(100,0);
|
console.log(query);
|
||||||
|
|
||||||
//TODO: add count here
|
return db.prepare(query);
|
||||||
const rescount = {cnt:100};
|
|
||||||
|
|
||||||
return resolve({
|
}
|
||||||
data: res,
|
|
||||||
count: rescount?.cnt,
|
|
||||||
limit: limit,
|
|
||||||
offset: offset
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(uuid){
|
add (uuid, timestamp, content, mime, hash) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const prepare = this.table_delete;
|
const dt = Math.floor(Date.now())
|
||||||
const res = prepare.run(uuid);
|
const res = this.table_insert.run(uuid, timestamp, content, mime, hash, dt, dt)
|
||||||
return resolve(res?.changes);
|
return resolve(res?.changes)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
update(uuid,content,mime,hash){
|
get (uuid) {
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
const dt = Math.floor(Date.now());
|
const rec = this.table_fine_one.get(uuid)
|
||||||
const res = this.table_update.run(content,mime,hash,dt,uuid);
|
return resolve(rec)
|
||||||
return resolve(res?.changes);
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
find (search, sort = null, limit = undefined, offset = 0) {
|
||||||
|
// TODO: add logic for seach and sort (Currently does nothing)
|
||||||
|
return new Promise(resolve => {
|
||||||
|
|
||||||
|
if(!search || !search.tags || Object.keys(search.tags).length === 0){
|
||||||
|
const prepare = this.table_find
|
||||||
|
|
||||||
|
const res = prepare.all(100, 0)
|
||||||
|
|
||||||
|
// TODO: add count here
|
||||||
|
const rescount = { cnt: 100 }
|
||||||
|
|
||||||
|
return resolve({
|
||||||
|
data: res,
|
||||||
|
count: rescount?.cnt,
|
||||||
|
limit: limit,
|
||||||
|
offset: offset
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
console.log(search);
|
||||||
|
|
||||||
|
const prepare = this.generator_find_sql(search.tags);
|
||||||
|
const res = prepare.all(100, 0)
|
||||||
|
const rescount = { cnt: 100 }
|
||||||
|
return resolve({
|
||||||
|
data: res,
|
||||||
|
count: rescount?.cnt,
|
||||||
|
limit: limit,
|
||||||
|
offset: offset
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
delete (uuid) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const prepare = this.table_delete
|
||||||
|
const res = prepare.run(uuid)
|
||||||
|
return resolve(res?.changes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
update (uuid, content, mime, hash) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const dt = Math.floor(Date.now())
|
||||||
|
const res = this.table_update.run(content, mime, hash, dt, uuid)
|
||||||
|
return resolve(res?.changes)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeChainDataSqlite {
|
class TimeChainDataSqlite {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ConnectToDatabase,
|
ConnectToDatabase,
|
||||||
TimeChainDataSqlite,
|
TimeChainDataSqlite,
|
||||||
TimeChainDataSqliteRecord,
|
TimeChainDataSqliteRecord,
|
||||||
TimeChainDataSqliteFile,
|
TimeChainDataSqliteFile,
|
||||||
TimeChainDataSqliteTagLink,
|
TimeChainDataSqliteTagLink,
|
||||||
TimeChainDataSqliteTag
|
TimeChainDataSqliteTag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
src/lib/toast.js
Normal file
15
src/lib/toast.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Swal from 'sweetalert2'
|
||||||
|
|
||||||
|
const Toast = Swal.mixin({
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end',
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 3000,
|
||||||
|
timerProgressBar: true,
|
||||||
|
didOpen: (toast) => {
|
||||||
|
toast.addEventListener('mouseenter', Swal.stopTimer)
|
||||||
|
toast.addEventListener('mouseleave', Swal.resumeTimer)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {Toast};
|
||||||
102
src/ui/app.riot
102
src/ui/app.riot
@ -13,6 +13,12 @@
|
|||||||
import TimechainInput from './timechain-input.riot'
|
import TimechainInput from './timechain-input.riot'
|
||||||
import TimechainList from './timechain-list.riot'
|
import TimechainList from './timechain-list.riot'
|
||||||
import AppDivider from './app-divider.riot'
|
import AppDivider from './app-divider.riot'
|
||||||
|
import keymage from 'keymage';
|
||||||
|
import pubsub from 'pubsub-js';
|
||||||
|
|
||||||
|
if(window.Timechain_isElectron){
|
||||||
|
const { ipcRenderer } = window.require('electron')
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -20,7 +26,103 @@
|
|||||||
TimechainInput,
|
TimechainInput,
|
||||||
TimechainList,
|
TimechainList,
|
||||||
AppDivider
|
AppDivider
|
||||||
|
},
|
||||||
|
onBeforeMount(){
|
||||||
|
console.log('Init');
|
||||||
|
},
|
||||||
|
onMounted(){
|
||||||
|
|
||||||
|
console.log("Application Mounted");
|
||||||
|
|
||||||
|
if(window.Timechain_isElectron){
|
||||||
|
console.log("Is Electron");
|
||||||
|
this.setupElectronKeyEvents();
|
||||||
|
}else{
|
||||||
|
console.log("Is Browser");
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
setupElectronKeyEvents(){
|
||||||
|
const kevents = [];
|
||||||
|
kevents.push( keymage('ctrl-o', this.onElectronOpenDatabase.bind(this)) );
|
||||||
|
kevents.push( keymage('ctrl-n', this.onElectronCreateDatabase.bind(this)) );
|
||||||
|
|
||||||
|
this._keyEvents = kevents;
|
||||||
|
},
|
||||||
|
async onElectronOpenDatabase(){
|
||||||
|
const file = await ipcRenderer.invoke('select-sqlite-file',{});
|
||||||
|
console.log(file)
|
||||||
|
|
||||||
|
const filepath = (file && file.filePaths) ? file.filePaths[0] : false;
|
||||||
|
console.log(filepath);
|
||||||
|
|
||||||
|
if(!filepath){
|
||||||
|
return alert("Could not load file. Filename not provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Loading new database");
|
||||||
|
const loaded = await ipcRenderer.invoke('timechain-database-open',{filename:filepath});
|
||||||
|
|
||||||
|
if(!loaded){
|
||||||
|
return alert("Database loading failed");
|
||||||
|
}else{
|
||||||
|
console.log("%c Database Reloaded","background-color:red;color:white;");
|
||||||
|
pubsub.publish('database-reloaded',true);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
async onElectronCreateDatabase(){
|
||||||
|
|
||||||
|
console.log("Create Datbase Event");
|
||||||
|
|
||||||
|
const file = await ipcRenderer.invoke('create-sqlite-file',{});
|
||||||
|
console.log("Returned")
|
||||||
|
console.log(file);
|
||||||
|
|
||||||
|
//const filepath = (file && file.filePaths) ? file.filePaths[0] : false;
|
||||||
|
//console.log(filepath);
|
||||||
|
|
||||||
|
const filepath = file;
|
||||||
|
|
||||||
|
if(!filepath){
|
||||||
|
console.warn("No file name");
|
||||||
|
return alert("Could not create file. Filename not provided.",filepath);
|
||||||
|
}else{
|
||||||
|
console.log("We have a file name.. Time to make db");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Creating new database")
|
||||||
|
|
||||||
|
const loaded = await ipcRenderer.invoke('timechain-database-create',{filename:filepath});
|
||||||
|
|
||||||
|
if(!loaded){
|
||||||
|
return alert("Database not created");
|
||||||
|
}else{
|
||||||
|
console.log("%c Database Created","background-color:red;color:white;");
|
||||||
|
pubsub.publish('database-reloaded', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/*onElectronCreateDatabaseOld(){
|
||||||
|
return ipcRenderer.invoke('select-sqlite-file',{}).then(file=>{
|
||||||
|
console.log(file)
|
||||||
|
const filepath = (file && file.filePaths) ? file.filePaths[0] : false;
|
||||||
|
console.log(filepath);
|
||||||
|
if(!filepath){
|
||||||
|
return alert("Could not load file. Filename not provided.")
|
||||||
|
|
||||||
|
return ipcRenderer.invoke('timechain-database-open',{}).then(success=>{
|
||||||
|
console.log("DB RETURNED");
|
||||||
|
if(success){
|
||||||
|
console.log("%c Database Reloaded","background-color:red;color:white;");
|
||||||
|
pubsub.publish('database-reloaded',true);
|
||||||
|
}else{
|
||||||
|
console.log("Database loading failed");
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -54,6 +54,10 @@
|
|||||||
onMounted(){
|
onMounted(){
|
||||||
document.addEventListener('paste', this.pasteEvent.bind(this));
|
document.addEventListener('paste', this.pasteEvent.bind(this));
|
||||||
|
|
||||||
|
this.event_dbreloaded = pubsub.subscribe('database-reloaded', (event,res)=>{
|
||||||
|
pubsub.publish('timechain-list-update', true);
|
||||||
|
})
|
||||||
|
|
||||||
this.setupKeyEvents();
|
this.setupKeyEvents();
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -86,6 +90,7 @@
|
|||||||
this._keyevents.forEach(f=>{
|
this._keyevents.forEach(f=>{
|
||||||
f();
|
f();
|
||||||
});
|
});
|
||||||
|
pubsub.unsubscribe(this.event_dbreloaded);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Window paste event has been fire.
|
* Window paste event has been fire.
|
||||||
@ -121,8 +126,11 @@
|
|||||||
break;
|
break;
|
||||||
}else if(t == 'image/png'){
|
}else if(t == 'image/png'){
|
||||||
isFile = true;
|
isFile = true;
|
||||||
this.isIMAGE(e.clipboardData.items[i], 'image/png')
|
this.isIMAGE(e.clipboardData.items[i], 'image/png');
|
||||||
break;
|
break;
|
||||||
|
}else if(t == 'image/gif'){
|
||||||
|
isFile = true;
|
||||||
|
this.isIMAGE(e.clipboardData.items[i], 'image/gif');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
src/ui/timechain-item-menu.riot
Normal file
17
src/ui/timechain-item-menu.riot
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<timechain-item-menu>
|
||||||
|
|
||||||
|
<div id="context-menu">
|
||||||
|
<div class="item">Copy to Clipboard</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</timechain-item-menu>
|
||||||
@ -1,16 +1,22 @@
|
|||||||
<timechain-list>
|
<timechain-list>
|
||||||
|
|
||||||
|
<div class="search-row">
|
||||||
|
<div class="search-tag">
|
||||||
|
<timechain-tag ontag="{onTags}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="top-gradient"></div>
|
<div class="top-gradient"></div>
|
||||||
<div class="timechain-list">
|
<div class="timechain-list">
|
||||||
|
|
||||||
<div class="timechange-item" each="{r in state.records}" key="{r.uuid}" if="{!state.loading}">
|
<div class="timechange-item item-{r.iid}" data-iid="{r.iid}" each="{r in state.records}" key="{r.uuid}" if="{!state.loading}" oncontextmenu="{onContextMenu}">
|
||||||
|
|
||||||
<div class="timechain-timestamp">
|
<div class="timechain-timestamp">
|
||||||
<timestamp-static time={r.timestamp} />
|
<timestamp-static time={r.timestamp} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timechain-tag-list">
|
<div class="timechain-tag-list">
|
||||||
<timechain-tag-list tags="{r.tags}" />
|
<timechain-tag-list tags="{r.tags}" canedit="1" rid="{r.uuid}" ontag="{onTagChange}"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timechain-item-text" if="{r.mime == 'text/plain'}">
|
<div class="timechain-item-text" if="{r.mime == 'text/plain'}">
|
||||||
@ -22,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timechain-item-image" if="{r.imageURL}">
|
<div class="timechain-item-image" if="{r.imageURL}">
|
||||||
<img src="{r.imageURL}" style="max-width:100%">
|
<img src="{r.imageURL}" style="max-width:100%" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -41,8 +47,16 @@
|
|||||||
import TimechainTagList from './timechain-tag-list.riot'
|
import TimechainTagList from './timechain-tag-list.riot'
|
||||||
import pubsub from 'pubsub-js'
|
import pubsub from 'pubsub-js'
|
||||||
|
|
||||||
|
import TimechainTag from './timechain-tag.riot'
|
||||||
|
|
||||||
|
import {dataURLtoBlob} from '../lib/blobconvert.js'
|
||||||
|
import {Toast} from '../lib/toast.js'
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
TimeChainDataSqliteRecord
|
TimeChainDataSqliteTag,
|
||||||
|
TimeChainDataSqliteRecord,
|
||||||
|
TimeChainDataSqliteTagLink
|
||||||
} = require('../data/sqlite-client');
|
} = require('../data/sqlite-client');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -54,7 +68,8 @@
|
|||||||
components: {
|
components: {
|
||||||
Raw,
|
Raw,
|
||||||
TimestampStatic,
|
TimestampStatic,
|
||||||
TimechainTagList
|
TimechainTagList,
|
||||||
|
TimechainTag
|
||||||
},
|
},
|
||||||
onMounted(){
|
onMounted(){
|
||||||
console.log("List mounted");
|
console.log("List mounted");
|
||||||
@ -67,12 +82,21 @@
|
|||||||
pubsub.unsubscribe(this.event_load);
|
pubsub.unsubscribe(this.event_load);
|
||||||
},
|
},
|
||||||
|
|
||||||
loadRecords(){
|
loadRecords(search){
|
||||||
this.update({loading:true});
|
this.update({loading:true});
|
||||||
const TR = new TimeChainDataSqliteRecord();
|
const TR = new TimeChainDataSqliteRecord();
|
||||||
|
|
||||||
TR.find({},null,100,0).then(records=>{
|
if(!search) {
|
||||||
|
if(this.last_search){
|
||||||
|
search = this.last_search
|
||||||
|
}else{
|
||||||
|
search = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TR.find(search,null,100,0).then(records=>{
|
||||||
console.log("Records", records);
|
console.log("Records", records);
|
||||||
|
if(records) records.data.forEach(r=>r.iid=this.uid());
|
||||||
this.update({records:records.data,loading:false});
|
this.update({records:records.data,loading:false});
|
||||||
}).then(()=>{
|
}).then(()=>{
|
||||||
this.processImages();
|
this.processImages();
|
||||||
@ -82,12 +106,114 @@
|
|||||||
processImages(){
|
processImages(){
|
||||||
var URLObj = window.URL || window.webkitURL;
|
var URLObj = window.URL || window.webkitURL;
|
||||||
this.state.records.forEach(r=>{
|
this.state.records.forEach(r=>{
|
||||||
if(r.mime == "image/jpeg" || r.mime == "image/png"){
|
if(typeof r.mime == 'string' && r.mime.startsWith("image/")){
|
||||||
r.imageURL = r.content;
|
r.imageURL = r.content;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.update();
|
this.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
onTags(tags){
|
||||||
|
|
||||||
|
if(tags==''){
|
||||||
|
return this.loadRecords({});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(tags);
|
||||||
|
tags = JSON.parse(tags);
|
||||||
|
const search = [];
|
||||||
|
tags.map(t=>{
|
||||||
|
//console.log(t.value);
|
||||||
|
search.push(t.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loadRecords({
|
||||||
|
tags:search
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onContextMenu(e){
|
||||||
|
const t = e.target.closest('.timechange-item');
|
||||||
|
const id = t.dataset.iid;
|
||||||
|
const record = this.state.records.find(r=>r.iid==id);
|
||||||
|
console.log("Right click", id, record);
|
||||||
|
|
||||||
|
if(!record) return;
|
||||||
|
|
||||||
|
|
||||||
|
if(record.mime && record.mime.includes('image/')){
|
||||||
|
const b = dataURLtoBlob(record.content);
|
||||||
|
|
||||||
|
console.log(b);
|
||||||
|
|
||||||
|
const items = { [b.type]: b };
|
||||||
|
const clipboardItem = new ClipboardItem(items);
|
||||||
|
navigator.clipboard.write([clipboardItem]).then(()=>{
|
||||||
|
Toast.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Copied to clipboard'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}else if(record.mime && (record.mime == 'text/html' || record.mime == 'text/plain')){
|
||||||
|
const t = record.mime;
|
||||||
|
const b = new Blob([record.content], {type:t});
|
||||||
|
|
||||||
|
console.log(t);
|
||||||
|
console.log(b);
|
||||||
|
|
||||||
|
const data = [new ClipboardItem({ [t]: b })];
|
||||||
|
navigator.clipboard.write(data).then(()=>{
|
||||||
|
Toast.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Copied to clipboard'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
}else{
|
||||||
|
alert("Can't copy");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onTagChange(tags,rid){
|
||||||
|
const TAG = new TimeChainDataSqliteTag();
|
||||||
|
const TL = new TimeChainDataSqliteTagLink();
|
||||||
|
|
||||||
|
console.log('LIST', tags,rid);
|
||||||
|
|
||||||
|
if(typeof tags == 'string'){
|
||||||
|
tags = JSON.parse(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!rid) return;
|
||||||
|
|
||||||
|
return TL.deleteRecord(rid).then(()=>{
|
||||||
|
|
||||||
|
const tasks = tags.map(t=>{
|
||||||
|
const tag = t.value;
|
||||||
|
if(!tag) return false;
|
||||||
|
|
||||||
|
return TAG.has(tag).then(v=>{
|
||||||
|
return v;
|
||||||
|
}).then(v=>{
|
||||||
|
if(!v){
|
||||||
|
return TAG.add(tag);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).then(v=>{
|
||||||
|
TL.add(rid,tag);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(tasks).then(()=>{
|
||||||
|
console.log("finish adding tags");
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
<timechain-tag-list>
|
<timechain-tag-list>
|
||||||
|
|
||||||
<div class="timechain-tags">
|
<div class="timechain-tags" ondblclick="{goEdit}">
|
||||||
<span class="timechain-tag" each="{t in state.tags}">{t}</span>
|
<span class="timechain-tag" each="{t in state.tags}" if="{!state.isEditing}">{t}</span>
|
||||||
|
<timechain-tag if="{state.isEditing}" tags="{state.tags_text}" rid="{state.rid}" ontag="{onTagChange}" onEnter="{onEnter}"></timechain-tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -11,6 +12,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
min-height: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timechain-tags .timechain-tag {
|
.timechain-tags .timechain-tag {
|
||||||
@ -24,17 +26,72 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import TimechainTag from './timechain-tag.riot'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
tags: []
|
tags: [],
|
||||||
|
tags_text: "",
|
||||||
|
canEdit: false,
|
||||||
|
isEditing: false,
|
||||||
|
key: '',
|
||||||
|
rid: '',
|
||||||
},
|
},
|
||||||
onMounted: function(props){
|
components: {
|
||||||
|
TimechainTag
|
||||||
|
},
|
||||||
|
onBeforeMount(props){
|
||||||
|
if(props.canedit=='1'){
|
||||||
|
this.state.canEdit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(props.rid){
|
||||||
|
this.state.rid = props.rid;
|
||||||
|
}else{
|
||||||
|
//console.log("No rid in list");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMounted(props){
|
||||||
if(!props.tags) return;
|
if(!props.tags) return;
|
||||||
this.update({
|
this.update({
|
||||||
|
tags_text: props.tags,
|
||||||
tags: props.tags.split(',')
|
tags: props.tags.split(',')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if(this.state.tags.length==0 && this.state.canEdit){
|
||||||
|
this.update({isEditing:true});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goEdit(e){
|
||||||
|
if(!this.state.canEdit) return;
|
||||||
|
this.state.isEditing = !this.state.isEditing;
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
onTagChange(tags,key){
|
||||||
|
console.log(tags,key);
|
||||||
|
|
||||||
|
if(typeof tags == 'string'){
|
||||||
|
tags = JSON.parse(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tagArr = [];
|
||||||
|
tags.forEach(t=>{
|
||||||
|
tagArr.push(t.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.update({
|
||||||
|
tags_text: tagArr.join(','),
|
||||||
|
tags: tagArr
|
||||||
|
});
|
||||||
|
|
||||||
|
if(this.props?.ontag){
|
||||||
|
this.props.ontag(tags,key);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnter(){
|
||||||
|
this.update({isEditing:false});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,27 +1,132 @@
|
|||||||
<timechain-tag>
|
<timechain-tag>
|
||||||
<div class="timechain-tagging">
|
<div class="timechain-tagging">
|
||||||
<input id="tagging" placeholder="tag your paste">
|
<input id="{state.id}" placeholder="tag your paste">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Tagify from '@yaireo/tagify'
|
import Tagify from '@yaireo/tagify'
|
||||||
const pubsub = require('pubsub-js');
|
const pubsub = require('pubsub-js');
|
||||||
|
const debounce = require('debounce');
|
||||||
|
|
||||||
|
const {
|
||||||
|
TimeChainDataSqliteTag
|
||||||
|
} = require('../data/sqlite-client');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onMounted(){
|
state:{
|
||||||
const inputElm = this.$('#tagging');
|
id:'tagging',
|
||||||
|
rid: ''
|
||||||
|
},
|
||||||
|
onBeforeMount(props){
|
||||||
|
this.state.id = "tagging"+this.makeid(5);
|
||||||
|
this.tagdb = new TimeChainDataSqliteTag();
|
||||||
|
},
|
||||||
|
onMounted(props, state){
|
||||||
|
const inputElm = this.$('#'+this.state.id);
|
||||||
|
|
||||||
|
if(props.rid){
|
||||||
|
state.rid = props.rid;
|
||||||
|
}else{
|
||||||
|
//console.log("no rid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(props.tags){
|
||||||
|
console.log("We have tags", props.tags);
|
||||||
|
inputElm.value = props.tags;
|
||||||
|
}else{
|
||||||
|
console.log("No tags");
|
||||||
|
console.log(props.tags);
|
||||||
|
}
|
||||||
|
|
||||||
this.tagify = new Tagify(inputElm);
|
this.tagify = new Tagify(inputElm);
|
||||||
inputElm.addEventListener('change', this.onChange.bind(this));
|
inputElm.addEventListener('change', this.onChange.bind(this));
|
||||||
this.event_clean = pubsub.subscribe('tag.clean', this.onClean.bind(this));
|
this.event_clean = pubsub.subscribe('tag.clean', this.onClean.bind(this));
|
||||||
|
|
||||||
|
this.tagify.on('input', debounce( this.onInputEvent.bind(this), 400) )
|
||||||
|
|
||||||
|
if(props.tags){
|
||||||
|
this.setFocus();
|
||||||
|
this.tagify.on('keydown', this.onKeyDown.bind(this) );
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
onUnmounted(){
|
onUnmounted(){
|
||||||
pubsub.unsubscribe(this.event_clean);
|
pubsub.unsubscribe(this.event_clean);
|
||||||
},
|
},
|
||||||
onChange(e){
|
onChange(e){
|
||||||
this.props?.ontag(e.target.value);
|
if(this.props?.ontag){
|
||||||
|
if(this.state.rid){
|
||||||
|
this.props.ontag(e.target.value, this.state.rid);
|
||||||
|
}else{
|
||||||
|
console.log("No RID");
|
||||||
|
this.props?.ontag(e.target.value);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
console.log("No on tag function");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onClean(){
|
onClean(){
|
||||||
this.tagify.removeAllTags();
|
this.tagify.removeAllTags();
|
||||||
|
},
|
||||||
|
makeid(length) {
|
||||||
|
var result = '';
|
||||||
|
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
var charactersLength = characters.length;
|
||||||
|
for ( var i = 0; i < length; i++ ) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
setFocus(){
|
||||||
|
const i = this.$('#'+this.state.id);
|
||||||
|
if(!i) {
|
||||||
|
return console.log("No input");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag = i.closest('.timechain-tagging');
|
||||||
|
|
||||||
|
if(!tag){
|
||||||
|
return console.log("No Tagg");
|
||||||
|
}
|
||||||
|
|
||||||
|
const s = tag.querySelector('.tagify__input');
|
||||||
|
|
||||||
|
if(!s){
|
||||||
|
return console.log("No tag imput");
|
||||||
|
}
|
||||||
|
|
||||||
|
s.focus();
|
||||||
|
},
|
||||||
|
onKeyDown(e){
|
||||||
|
console.log(e);
|
||||||
|
|
||||||
|
if(e.detail && e.detail.originalEvent && (e.detail.originalEvent.key == "Enter" || e.detail.originalEvent.key == "Escape") ){
|
||||||
|
//e.detail.originalEvent.stopPropagation();
|
||||||
|
//e.detail.originalEvent.preventDefault();
|
||||||
|
//console.log("ENTER");
|
||||||
|
|
||||||
|
if(this.props?.onEnter){
|
||||||
|
this.props.onEnter(e.detail.originalEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onInputEvent(e){
|
||||||
|
const val = e.detail.value;
|
||||||
|
this.tagify.whitelist = null;
|
||||||
|
|
||||||
|
console.log('%c Value '+val,'background-color:black;');
|
||||||
|
|
||||||
|
this.tagify.loading(true); //dropdown.hide();
|
||||||
|
|
||||||
|
this.tagdb.like(val).then(res=>{
|
||||||
|
const cleaned = res.map(r=>r.tag);
|
||||||
|
console.log(cleaned);
|
||||||
|
this.tagify.whitelist = cleaned;
|
||||||
|
this.tagify.loading(false).dropdown.show(val);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
3
src/ui/timechain-tags.riot
Normal file
3
src/ui/timechain-tags.riot
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<timechain-tags>
|
||||||
|
|
||||||
|
</timechain-tags>
|
||||||
43
start.js
43
start.js
@ -1,34 +1,23 @@
|
|||||||
import './src/less/main.less';
|
import './src/less/main.less'
|
||||||
import './src/css/tagify.scss';
|
import './src/css/tagify.scss'
|
||||||
|
|
||||||
import * as Sentry from "@sentry/browser";
|
|
||||||
import { BrowserTracing } from "@sentry/tracing";
|
|
||||||
|
|
||||||
Sentry.init({
|
|
||||||
dsn: "http://a12d5c5f800b406f8d1c0c5d2ed63a78@216.128.138.128:8000/1",
|
|
||||||
|
|
||||||
// Alternatively, use `process.env.npm_package_version` for a dynamic release version
|
|
||||||
// if your build tool supports it.
|
|
||||||
release: "timechain@1.0.0",
|
|
||||||
integrations: [new BrowserTracing()],
|
|
||||||
|
|
||||||
// Set tracesSampleRate to 1.0 to capture 100%
|
|
||||||
// of transactions for performance monitoring.
|
|
||||||
// We recommend adjusting this value in production
|
|
||||||
tracesSampleRate: 1.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
import App from './src/ui/app.riot'
|
import App from './src/ui/app.riot'
|
||||||
|
|
||||||
import { component } from 'riot'
|
import { component, install } from 'riot'
|
||||||
|
|
||||||
window.debugging = true;
|
let id = 0
|
||||||
|
|
||||||
setTimeout(()=>{
|
install(function(component) {
|
||||||
document.getElementById('main-loading')?.remove();
|
// all components will pass through here
|
||||||
component(App)(document.getElementById('timechain'));
|
component.uid = ()=>{
|
||||||
Sentry.captureMessage('Application Started');
|
return ++id;
|
||||||
},0)
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
window.debugging = true
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById('main-loading')?.remove()
|
||||||
|
component(App)(document.getElementById('timechain'))
|
||||||
|
Sentry.captureMessage('Application Started')
|
||||||
|
}, 0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user