Browse Source

WIP: Add tags functionality

remotes/philippdormann/main
Nelson Chan 4 years ago
parent
commit
f31dc07d33
  1. 18
      db/patch9.sql
  2. 3
      server/model/monitor.js
  3. 12
      server/model/tag.js
  4. 148
      server/server.js
  5. 18
      src/components/Tag.vue
  6. 42
      src/components/TagsManager.vue
  7. 16
      src/pages/EditMonitor.vue

18
db/patch9.sql

@ -0,0 +1,18 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
CREATE TABLE tag (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255) NOT NULL,
created_date DATETIME DEFAULT (DATETIME('now')) NOT NULL
);
CREATE TABLE monitor_tag (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
monitor_id INTEGER NOT NULL,
tag_id INTEGER NOT NULL,
value TEXT,
CONSTRAINT FK_tag FOREIGN KEY (tag_id) REFERENCES tag(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FK_monitor FOREIGN KEY (monitor_id) REFERENCES monitor(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX monitor_tag_monitor_id_index ON monitor_tag (monitor_id);
CREATE INDEX monitor_tag_tag_id_index ON monitor_tag (tag_id);

3
server/model/monitor.js

@ -32,6 +32,8 @@ class Monitor extends BeanModel {
notificationIDList[bean.notification_id] = true; notificationIDList[bean.notification_id] = true;
} }
const tags = await R.getAll("SELECT * FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]);
return { return {
id: this.id, id: this.id,
name: this.name, name: this.name,
@ -52,6 +54,7 @@ class Monitor extends BeanModel {
dns_resolve_server: this.dns_resolve_server, dns_resolve_server: this.dns_resolve_server,
dns_last_result: this.dns_last_result, dns_last_result: this.dns_last_result,
notificationIDList, notificationIDList,
tags: tags,
}; };
} }

12
server/model/tag.js

@ -0,0 +1,12 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
class Tag extends BeanModel {
toJSON() {
return {
id: this._id,
name: this._name,
};
}
}
module.exports = Tag;

148
server/server.js

@ -446,6 +446,154 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString();
} }
}); });
socket.on("getTags", async (callback) => {
try {
checkLogin(socket)
const list = await R.findAll("tag")
callback({
ok: true,
tags: list.map(bean => bean.toJSON()),
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("addTag", async (tag, callback) => {
try {
checkLogin(socket)
let bean = R.dispense("tag")
bean.name = tag.name
await R.store(bean)
callback({
ok: true,
tag: await bean.toJSON(),
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("editTag", async (tag, callback) => {
try {
checkLogin(socket)
let bean = await R.findOne("monitor", " id = ? ", [ tag.id ])
bean.name = tag.name
await R.store(bean)
callback({
ok: true,
tag: await bean.toJSON(),
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("deleteTag", async (tagID, callback) => {
try {
checkLogin(socket)
await R.exec("DELETE FROM tag WHERE id = ? ", [ tagID ])
callback({
ok: true,
msg: "Deleted Successfully.",
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("addMonitorTag", async (tagID, monitorID, value, callback) => {
try {
checkLogin(socket)
await R.exec("INSERT INTO monitor_tag (tag_id, monitor_id, value) VALUES (?, ?, ?)", [
tagID,
monitorID,
value,
])
callback({
ok: true,
msg: "Added Successfully.",
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("editMonitorTag", async (tagID, monitorID, value, callback) => {
try {
checkLogin(socket)
await R.exec("UPDATE monitor_tag SET value = ? WHERE tag_id = ? AND monitor_id = ?", [
value,
tagID,
monitorID,
])
callback({
ok: true,
msg: "Edited Successfully.",
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("deleteMonitorTag", async (tagID, monitorID, callback) => {
try {
checkLogin(socket)
await R.exec("DELETE FROM monitor_tag WHERE tag_id = ? AND monitor_id = ?", [
tagID,
monitorID,
])
callback({
ok: true,
msg: "Deleted Successfully.",
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("changePassword", async (password, callback) => { socket.on("changePassword", async (password, callback) => {
try { try {
checkLogin(socket) checkLogin(socket)

18
src/components/Tag.vue

@ -0,0 +1,18 @@
<template>
<span class="p-2">{{ name }}:{{ value }}</span>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true,
},
value: {
type: String,
default: "",
},
}
}
</script>

42
src/components/TagsManager.vue

@ -0,0 +1,42 @@
<template>
<div>
<tag v-for="(item) in selectedTags" :key="item.name+item.value" :name="item.name" :value="item.value" />
</div>
</template>
<script>
import Tag from "../components/Tag.vue";
export default {
components: {
Tag,
},
props: {
tags: {
type: Array,
required: true,
},
preSelectedTags: {
type: Array,
default: () => [],
},
},
data() {
return {
newTags: [],
selectedTags: this.preSelectedTags,
}
},
watch: {
preSelectedTags(gotTags) {
if (gotTags.length > 0 && this.selectedTags.length === 0) {
this.selectedTags = gotTags;
}
}
}
}
</script>
<style>
</style>

16
src/pages/EditMonitor.vue

@ -158,6 +158,10 @@
</div> </div>
</template> </template>
<div class="my-3">
<tags-manager :pre-selected-tags="monitor.tags" :tags="tags"></tags-manager>
</div>
<div class="mt-5 mb-1"> <div class="mt-5 mb-1">
<button class="btn btn-primary" type="submit" :disabled="processing">{{ $t("Save") }}</button> <button class="btn btn-primary" type="submit" :disabled="processing">{{ $t("Save") }}</button>
</div> </div>
@ -195,6 +199,7 @@
<script> <script>
import NotificationDialog from "../components/NotificationDialog.vue"; import NotificationDialog from "../components/NotificationDialog.vue";
import TagsManager from "../components/TagsManager.vue";
import { useToast } from "vue-toastification" import { useToast } from "vue-toastification"
import VueMultiselect from "vue-multiselect" import VueMultiselect from "vue-multiselect"
import { isDev } from "../util.ts"; import { isDev } from "../util.ts";
@ -203,6 +208,7 @@ const toast = useToast()
export default { export default {
components: { components: {
NotificationDialog, NotificationDialog,
TagsManager,
VueMultiselect, VueMultiselect,
}, },
@ -218,6 +224,8 @@ export default {
// Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/ // Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
ipRegexPattern: "((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))", ipRegexPattern: "((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))",
tags: [],
} }
}, },
@ -280,6 +288,14 @@ export default {
}, },
methods: { methods: {
init() { init() {
this.$root.getSocket().emit("getTags", (res) => {
if (res.ok) {
this.tags = res.tags;
} else {
toast.error(res.msg)
}
});
if (this.isAdd) { if (this.isAdd) {
console.log("??????") console.log("??????")
this.monitor = { this.monitor = {

Loading…
Cancel
Save