Skip to content

Commit

Permalink
Address #68 (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
mewim authored Feb 13, 2024
1 parent 48c430d commit 889d334
Show file tree
Hide file tree
Showing 10 changed files with 1,103 additions and 47 deletions.
872 changes: 853 additions & 19 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
"pino": "^8.16.1",
"pino-pretty": "^10.2.3",
"randomcolor": "^0.6.2",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"uuid": "^9.0.1",
"vue": "^3.2.13"
},
Expand Down
12 changes: 7 additions & 5 deletions src/components/MainLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -231,16 +231,16 @@ export default {
this.updateNavbarHeight();
this.accessModeModal = new Modal(this.$refs.modal);
window.addEventListener("resize", this.updateNavbarHeight);
this.loadGptApiTokenFromLocalStorage();
},
beforeUnmount() {
this.accessModeModal.dispose();
window.removeEventListener("resize", this.updateNavbarHeight);
},
created() {
this.getMode();
this.getSchema().then(() => {
this.initDefaultSettings(this.schema);
Promise.all([this.getSchema(), this.getStoredSettings()]).then((res) => {
const storedSettings = res[1];
this.initSettings(this.schema, storedSettings);
this.$refs.schemaView.drawGraph();
});
},
Expand Down Expand Up @@ -290,6 +290,9 @@ export default {
}
});
},
async getStoredSettings() {
return (await Axios.get("/api/session/settings")).data;
},
async reloadSchema() {
await this.getSchema();
this.handleSchemaReload(this.schema);
Expand Down Expand Up @@ -384,13 +387,12 @@ export default {
this.navbarHeight = this.$refs.navbar.clientHeight;
},
...mapActions(useSettingsStore, [
'initDefaultSettings',
'initSettings',
'handleSchemaReload',
'setPlaceholderNodeTable',
'setPlaceholderRelTable',
'unsetPlaceholderNodeTable',
'unsetPlaceholderRelTable',
'loadGptApiTokenFromLocalStorage'
])
},
};
Expand Down
7 changes: 5 additions & 2 deletions src/components/SchemaView/SchemaViewMain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ export default {
this.$nextTick(() => {
this.cancelAdd();
});
}else if (action.type === SCHEMA_ACTION_TYPES.ADD_RDF) {
} else if (action.type === SCHEMA_ACTION_TYPES.ADD_RDF) {
this.$refs.overview.cancelAddRdf();
}
},
Expand Down Expand Up @@ -656,6 +656,9 @@ export default {
handleSettingsChange() {
const { nodes, edges, combos } = this.extractGraphFromSchema(this.schema);
if (!this.g6graph) {
return;
}
this.g6graph.changeData({ nodes, edges, combos });
const layoutConfig = this.getLayoutConfig(edges);
this.g6graph.updateLayout(layoutConfig);
Expand Down Expand Up @@ -816,7 +819,7 @@ export default {
});
},
addRdf(name){
addRdf(name) {
this.$refs.actionDialog.addRdf(name);
},
Expand Down
12 changes: 10 additions & 2 deletions src/components/SettingsView/SettingsMainView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,12 @@
href="https://platform.openai.com/"
target="_blank"
>OpenAI</a>. We only
store the API key in your browser.
store the API key in your browser. Click
<a
href="#"
@click="clearGptToken()"
>here</a> to clear the API key from the
browser.
</small>
</div>

Expand Down Expand Up @@ -289,7 +294,6 @@ export default {
},
saveAndHideModal() {
this.settingsStore.updateSettings(this.currentSettings);
this.settingsStore.saveGptApiTokenToLocalStorage();
this.$nextTick(() => {
this.hideModal();
});
Expand Down Expand Up @@ -331,6 +335,10 @@ export default {
// This way ensures that we can get the event when the modal is closed.
this.currentSettings = {};
},
clearGptToken() {
this.currentSettings.gpt.apiToken = "";
this.settingsStore.clearGptApiToken();
},
},
}
</script>
Expand Down
3 changes: 3 additions & 0 deletions src/components/ShellView/ResultGraph.vue
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,9 @@ export default {
handleSettingsChange() {
const { nodes, edges, counters } = this.extractGraphFromQueryResult(this.queryResult);
if (!this.g6graph) {
return;
}
this.g6graph.changeData({ nodes, edges });
this.counters = counters;
}
Expand Down
2 changes: 2 additions & 0 deletions src/server/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ const cypher = require("./Cypher");
const datasets = require("./Datasets");
const mode = require("./Mode");
const gpt = require("./Gpt");
const session = require("./Session");

router.use("/schema", schema);
router.use("/cypher", cypher);
router.use("/datasets", datasets);
router.use("/mode", mode);
router.use("/gpt", gpt);
router.use("/session", session);

module.exports = router;
24 changes: 24 additions & 0 deletions src/server/Session.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const sessionDb = require("./utils/SessionDatabase");
const express = require("express");
const router = express.Router();

router.get("/settings", async (_, res) => {
try {
const settings = await sessionDb.getSetting();
res.send(settings);
} catch (err) {
return res.status(400).send({ error: err.message });
}
});

router.post("/settings", async (req, res) => {
try {
await sessionDb.setSetting(req.body);
res.send({ success: true });
} catch (err) {
console.error(err);
return res.status(400).send({ error: err.message });
}
});

module.exports = router;
135 changes: 135 additions & 0 deletions src/server/utils/SessionDatabase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
const path = require("path");
const fs = require("fs").promises;
const sqlite3 = require("sqlite3");
const sqlite = require("sqlite");
const constants = require("./Constants");

const MODES = constants.MODES;
const DB_FILE_NAME = "explorer.db";

class SessionDatabase {
constructor() {
this.isInitialized = false;
const dbPath = process.env.KUZU_PATH;
if (!dbPath) {
return;
}
this.dbPath = path.resolve(path.join(dbPath, DB_FILE_NAME));
this.isReadOnly = !!(
process.env.MODE && process.env.MODE !== MODES.READ_WRITE
);
this.initSqlite();
}

initSqlite() {
if (this.isInitialized) {
return null;
}
if (this.sqlInitPromise) {
return this.sqlInitPromise;
}
this.sqlInitPromise = (async () => {
let isDbFileExists = false;
try {
await fs.access(this.dbPath, fs.constants.R_OK);
isDbFileExists = true;
} catch (err) {
// File does not exist
}
// Double check if the file is writable
if (isDbFileExists) {
try {
await fs.access(this.dbPath, fs.constants.W_OK);
} catch (err) {
this.isReadOnly = true;
}
} else {
try {
await fs.writeFile(this.dbPath, "");
await fs.access(this.dbPath, fs.constants.W_OK);
await fs.unlink(this.dbPath);
} catch (err) {
this.isReadOnly = true;
}
if (this.isReadOnly) {
// In read-only mode, if the db file does not exist, we should not create it,
// but if it exists, we can still use it.
return;
}
try {
await new Promise((resolve, reject) => {
const newDb = new sqlite3.Database(
this.dbPath,
sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
(err) => {
if (err) {
return reject(err);
}
newDb.close();
resolve();
}
);
});
} catch (err) {
return;
}
}
this.db = await sqlite.open({
filename: this.dbPath,
driver: sqlite3.Database,
});
if (!isDbFileExists) {
await this.createDbSchema();
}
this.isInitialized = true;
delete this.sqlInitPromise;
})();
return this.sqlInitPromise;
}

async createDbSchema() {
await this.db.exec(`
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT
);
`);
await this.db.exec(`
CREATE TABLE history (
uuid TEXT PRIMARY KEY,
isQueryGenerationMode BOOLEAN,
gptQuestion TEXT,
cypherQuery TEXT
);`);
}

async getSetting(key = "allSettings") {
await this.initSqlite();
if (!this.isInitialized) {
return {};
}
let settings = await this.db.get(
"SELECT * FROM settings WHERE key = ?",
key
);
settings = settings ? settings.value : {};
return settings;
}

async setSetting(value, key = "allSettings") {
await this.initSqlite();
if (!this.isInitialized) {
return;
}
if (this.isReadOnly) {
return;
}
await this.db.run(
`INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)`,
key,
JSON.stringify(value)
);
}
}

module.exports = new SessionDatabase();
Loading

0 comments on commit 889d334

Please sign in to comment.