mirror of
https://github.com/rajnandan1/kener.git
synced 2026-06-23 04:10:22 +00:00
feat: support for postgres using knex
This commit is contained in:
@@ -5,24 +5,7 @@ let interval = 1000;
|
||||
let waitTime = 0;
|
||||
|
||||
async function allFilesExist() {
|
||||
let tablesCreated = (await db.checkTables()).map((table) => table.name);
|
||||
let tablesRequired = [
|
||||
"monitoring_data",
|
||||
"monitor_alerts",
|
||||
"site_data",
|
||||
"monitors",
|
||||
"triggers",
|
||||
"users",
|
||||
"api_keys"
|
||||
];
|
||||
|
||||
for (let table of tablesRequired) {
|
||||
let tableExists = tablesCreated.includes(table);
|
||||
if (!tableExists) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return await db.checkTables();
|
||||
}
|
||||
|
||||
//use setTimeout to create a delay promise
|
||||
@@ -37,13 +20,13 @@ let requiredFilesExist = false;
|
||||
while (!requiredFilesExist && waitTime < maxWait) {
|
||||
await delay(1000);
|
||||
requiredFilesExist = await allFilesExist();
|
||||
|
||||
waitTime += interval;
|
||||
}
|
||||
if (!requiredFilesExist) {
|
||||
console.error("Error loading site data");
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log("✅ All files exist. Starting Frontend server...");
|
||||
console.log("✅ All files exist. Starting server...");
|
||||
process.exit(0);
|
||||
}
|
||||
})();
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// @ts-nocheck
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const dbType = process.env.DATABASE_TYPE || "sqlite";
|
||||
|
||||
const knexOb = {
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: process.env.SQLITE_FILEPATH || "./database/kener.local7.db"
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
migrations: {
|
||||
directory: "./migrations"
|
||||
},
|
||||
seeds: {
|
||||
directory: "./seeds"
|
||||
}
|
||||
};
|
||||
|
||||
if (dbType === "postgres") {
|
||||
knexOb.client = "pg";
|
||||
knexOb.connection = process.env.POSTGRES_DATABASE_URL;
|
||||
}
|
||||
|
||||
export default knexOb;
|
||||
@@ -0,0 +1,135 @@
|
||||
// migrations/YYYYMMDDHHMMSS_create_monitoring_tables.js
|
||||
|
||||
export function up(knex) {
|
||||
return (
|
||||
knex.schema
|
||||
// Create monitoring_data table
|
||||
.createTable("monitoring_data", (table) => {
|
||||
table.text("monitor_tag").notNullable();
|
||||
table.integer("timestamp").notNullable();
|
||||
table.text("status");
|
||||
table.float("latency");
|
||||
table.text("type");
|
||||
table.primary(["monitor_tag", "timestamp"]);
|
||||
})
|
||||
// Create monitor_alerts table
|
||||
.createTable("monitor_alerts", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("monitor_tag").notNullable();
|
||||
table.text("monitor_status").notNullable();
|
||||
table.text("alert_status").notNullable();
|
||||
table.integer("health_checks").notNullable();
|
||||
table.integer("incident_number").defaultTo(0);
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
// Add index to monitor_alerts table
|
||||
.raw(
|
||||
"CREATE INDEX idx_monitor_tag_created_at ON monitor_alerts (monitor_tag, created_at)"
|
||||
)
|
||||
.createTable("site_data", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("key").notNullable().unique();
|
||||
table.text("value").notNullable();
|
||||
table.text("data_type").notNullable();
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
.createTable("monitors", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("tag").notNullable().unique();
|
||||
table.text("name").notNullable().unique();
|
||||
table.text("description");
|
||||
table.text("image");
|
||||
table.text("cron");
|
||||
table.text("default_status");
|
||||
table.text("status");
|
||||
table.text("category_name");
|
||||
table.text("monitor_type");
|
||||
table.text("down_trigger");
|
||||
table.text("degraded_trigger");
|
||||
table.text("type_data");
|
||||
table.integer("day_degraded_minimum_count");
|
||||
table.integer("day_down_minimum_count");
|
||||
table.text("include_degraded_in_downtime").defaultTo("NO");
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
.createTable("triggers", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("name").notNullable().unique();
|
||||
table.text("trigger_type");
|
||||
table.text("trigger_desc");
|
||||
table.text("trigger_status");
|
||||
table.text("trigger_meta");
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
.createTable("users", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("email").notNullable().unique();
|
||||
table.text("name").notNullable();
|
||||
table.text("password_hash").notNullable();
|
||||
table.integer("is_active").defaultTo(1);
|
||||
table.integer("is_verified").defaultTo(0);
|
||||
table.text("role").defaultTo("user");
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
.createTable("api_keys", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("name").notNullable().unique();
|
||||
table.text("hashed_key").notNullable().unique();
|
||||
table.text("masked_key").notNullable();
|
||||
table.text("status").defaultTo("ACTIVE");
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
.createTable("incidents", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("title").notNullable();
|
||||
table.integer("start_date_time").notNullable();
|
||||
table.integer("end_date_time");
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
table.text("status").defaultTo("ACTIVE");
|
||||
table.text("state").defaultTo("INVESTIGATING");
|
||||
})
|
||||
.createTable("incident_monitors", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("monitor_tag").notNullable();
|
||||
table.text("monitor_impact");
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
table.integer("incident_id").notNullable();
|
||||
table.unique(["monitor_tag", "incident_id"]);
|
||||
})
|
||||
.createTable("incident_comments", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("comment").notNullable();
|
||||
table.integer("incident_id").notNullable();
|
||||
table.integer("commented_at").notNullable();
|
||||
table.timestamp("created_at").defaultTo(knex.fn.now());
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
table.text("status").defaultTo("ACTIVE");
|
||||
table.text("state").defaultTo("INVESTIGATING");
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function down(knex) {
|
||||
return (
|
||||
knex.schema
|
||||
// Drop tables in reverse order
|
||||
.dropTableIfExists("monitor_alerts")
|
||||
.dropTableIfExists("monitoring_data")
|
||||
.dropTableIfExists("site_data")
|
||||
.dropTableIfExists("monitors")
|
||||
.dropTableIfExists("triggers")
|
||||
.dropTableIfExists("users")
|
||||
.dropTableIfExists("api_keys")
|
||||
.dropTableIfExists("incidents")
|
||||
.dropTableIfExists("incident_monitors")
|
||||
.dropTableIfExists("incident_comments")
|
||||
);
|
||||
}
|
||||
Generated
+169
-3
@@ -27,6 +27,7 @@
|
||||
"fs-extra": "^11.1.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"knex": "^3.1.0",
|
||||
"lucide-svelte": "^0.292.0",
|
||||
"marked": "^11.1.1",
|
||||
"mode-watcher": "^0.4.1",
|
||||
@@ -1872,6 +1873,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "2.0.19",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
|
||||
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@@ -2531,7 +2538,6 @@
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -2551,6 +2557,15 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esm": {
|
||||
"version": "3.2.25",
|
||||
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/esm-env": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.0.tgz",
|
||||
@@ -2955,6 +2970,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-package-type": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
|
||||
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-symbol-description": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
|
||||
@@ -2972,6 +2996,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/getopts": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz",
|
||||
"integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
@@ -3273,6 +3303,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/interpret": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
|
||||
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
@@ -3687,6 +3726,104 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/knex": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz",
|
||||
"integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"colorette": "2.0.19",
|
||||
"commander": "^10.0.0",
|
||||
"debug": "4.3.4",
|
||||
"escalade": "^3.1.1",
|
||||
"esm": "^3.2.25",
|
||||
"get-package-type": "^0.1.0",
|
||||
"getopts": "2.3.0",
|
||||
"interpret": "^2.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"pg-connection-string": "2.6.2",
|
||||
"rechoir": "^0.8.0",
|
||||
"resolve-from": "^5.0.0",
|
||||
"tarn": "^3.0.2",
|
||||
"tildify": "2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"knex": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"better-sqlite3": {
|
||||
"optional": true
|
||||
},
|
||||
"mysql": {
|
||||
"optional": true
|
||||
},
|
||||
"mysql2": {
|
||||
"optional": true
|
||||
},
|
||||
"pg": {
|
||||
"optional": true
|
||||
},
|
||||
"pg-native": {
|
||||
"optional": true
|
||||
},
|
||||
"sqlite3": {
|
||||
"optional": true
|
||||
},
|
||||
"tedious": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/knex/node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/knex/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/knex/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/knex/node_modules/pg-connection-string": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
|
||||
"integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/knex/node_modules/resolve-from": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
|
||||
@@ -3732,8 +3869,7 @@
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.castarray": {
|
||||
"version": "4.4.0",
|
||||
@@ -5258,6 +5394,18 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rechoir": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
|
||||
"integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"resolve": "^1.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
||||
@@ -6389,6 +6537,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tarn": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
|
||||
"integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/thenify": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
@@ -6408,6 +6565,15 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/tildify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
|
||||
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"configure": "node build.js",
|
||||
"preseed": "npx knex migrate:latest",
|
||||
"seed": "npx knex seed:run",
|
||||
"predev": "npm run seed",
|
||||
"devschedule": "node src/lib/server/startup.js",
|
||||
"schedule": "node src/lib/server/startup.js",
|
||||
"predevelopment": "node delay.js",
|
||||
@@ -80,6 +83,7 @@
|
||||
"fs-extra": "^11.1.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"knex": "^3.1.0",
|
||||
"lucide-svelte": "^0.292.0",
|
||||
"marked": "^11.1.1",
|
||||
"mode-watcher": "^0.4.1",
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import monitorSeed from "../src/lib/server/db/seedMonitorData.js";
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
export async function seed(knex) {
|
||||
// Check if the table is empty
|
||||
const count = await knex("monitors").count("id as CNT").first();
|
||||
if (count.CNT == 0) {
|
||||
// Deletes ALL existing entries
|
||||
for (const monitor of monitorSeed) {
|
||||
await knex("monitors").insert({
|
||||
tag: monitor.tag,
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
image: monitor.image,
|
||||
cron: monitor.cron,
|
||||
default_status: monitor.default_status,
|
||||
status: monitor.status,
|
||||
category_name: monitor.category_name,
|
||||
monitor_type: monitor.monitor_type,
|
||||
type_data: monitor.type_data,
|
||||
day_degraded_minimum_count: monitor.day_degraded_minimum_count,
|
||||
day_down_minimum_count: monitor.day_down_minimum_count,
|
||||
include_degraded_in_downtime: monitor.include_degraded_in_downtime,
|
||||
created_at: knex.fn.now(),
|
||||
updated_at: knex.fn.now()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import seedSiteData from "../src/lib/server/db/seedSiteData.js";
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
export async function seed(knex) {
|
||||
// Check if the table is empty
|
||||
const count = await knex("site_data").count("id as CNT").first();
|
||||
|
||||
for (const key in seedSiteData) {
|
||||
if (Object.prototype.hasOwnProperty.call(seedSiteData, key)) {
|
||||
let value = seedSiteData[key];
|
||||
let data_type = typeof value;
|
||||
if (data_type === "object") {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
const existingEntry = await knex("site_data").where({ key: key }).first();
|
||||
if (!existingEntry) {
|
||||
await knex("site_data").insert([{ key: key, value: value, data_type: data_type }]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+100
@@ -727,3 +727,103 @@ textarea::placeholder {
|
||||
),
|
||||
linear-gradient(90deg, #ffffff, #ffffff);
|
||||
}
|
||||
|
||||
/* CSS */
|
||||
.button-77 {
|
||||
align-items: center;
|
||||
appearance: none;
|
||||
background-clip: padding-box;
|
||||
background-color: initial;
|
||||
background-image: none;
|
||||
border-style: none;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
justify-content: center;
|
||||
line-height: 24px;
|
||||
margin: 0;
|
||||
min-height: 64px;
|
||||
outline: none;
|
||||
overflow: visible;
|
||||
padding: 19px 26px;
|
||||
pointer-events: auto;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
touch-action: manipulation;
|
||||
vertical-align: middle;
|
||||
width: auto;
|
||||
word-break: keep-all;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.button-77 {
|
||||
padding: 19px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.button-77:before,
|
||||
.button-77:after {
|
||||
border-radius: 80px;
|
||||
}
|
||||
|
||||
.button-77:before {
|
||||
background-color: rgba(249, 58, 19, 0.32);
|
||||
content: "";
|
||||
display: block;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.button-77:after {
|
||||
background-color: initial;
|
||||
background-image: linear-gradient(92.83deg, #ff7426 0, #f93a13 100%);
|
||||
bottom: 4px;
|
||||
content: "";
|
||||
display: block;
|
||||
left: 4px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
transition: all 100ms ease-out;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.button-77:hover:not(:disabled):after {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition-timing-function: ease-in;
|
||||
}
|
||||
|
||||
.button-77:active:not(:disabled) {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.button-77:active:not(:disabled):after {
|
||||
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
|
||||
linear-gradient(92.83deg, #ff7426 0, #f93a13 100%);
|
||||
bottom: 4px;
|
||||
left: 4px;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.button-77:disabled {
|
||||
cursor: default;
|
||||
opacity: 0.24;
|
||||
}
|
||||
|
||||
@@ -148,14 +148,10 @@
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-neutral-700">
|
||||
{#each alerts as alert}
|
||||
<tr>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-sm font-medium text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm font-medium">
|
||||
{alert.id}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-xs font-semibold text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-xs font-semibold">
|
||||
{#if alert.monitor_status === "DOWN"}
|
||||
<span class="text-red-500">
|
||||
{alert.monitor_status}
|
||||
@@ -166,14 +162,10 @@
|
||||
</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-sm text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm">
|
||||
{alert.monitor_tag}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-xs font-semibold text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-xs font-semibold">
|
||||
{#if alert.alert_status === "RESOLVED"}
|
||||
<span class="text-blue-500">
|
||||
{alert.alert_status}
|
||||
@@ -184,14 +176,10 @@
|
||||
</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-sm text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm">
|
||||
{alert.health_checks}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-xs font-semibold text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-xs font-semibold">
|
||||
{#if !!alert.incident_number}
|
||||
<a
|
||||
target="_blank"
|
||||
@@ -204,10 +192,11 @@
|
||||
-
|
||||
{/if}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-sm text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
{moment(alert.created_at).format("YYYY-MM-DD HH:mm:ss")}
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm">
|
||||
{moment
|
||||
.utc(alert.created_at, "YYYY-MM-DD HH:mm:ss")
|
||||
.local()
|
||||
.format("YYYY-MM-DD HH:mm:ss")}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
@@ -139,7 +139,9 @@
|
||||
</Button>
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Your new API key has been created. It will be not shown again, so make sure to save it.
|
||||
Your new API key has been created. It will be <b class="uppercase underline"
|
||||
>not be shown again</b
|
||||
>, so make sure to save it.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -187,7 +189,10 @@
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-sm text-gray-800 dark:text-neutral-200"
|
||||
>
|
||||
{moment(apiKey.created_at).format("YYYY-MM-DD HH:mm:ss")}
|
||||
{moment
|
||||
.utc(apiKey.created_at, "YYYY-MM-DD HH:mm:ss")
|
||||
.local()
|
||||
.format("YYYY-MM-DD HH:mm:ss")}
|
||||
</td>
|
||||
<td
|
||||
class="whitespace-nowrap px-6 py-4 text-xs font-semibold text-gray-800 dark:text-neutral-200"
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
}).metaTags;
|
||||
|
||||
let analytics = siteDataExtractFromDb(data.siteData, {
|
||||
analytics: "[]"
|
||||
analytics: []
|
||||
}).analytics;
|
||||
|
||||
//merge analyticsSupported with analytics
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
let formState = "idle";
|
||||
|
||||
let themeData = {
|
||||
pattern: "dots",
|
||||
pattern: "none",
|
||||
theme: "light",
|
||||
themeToggle: "YES",
|
||||
barStyle: "PARTIAL",
|
||||
@@ -37,7 +37,7 @@
|
||||
};
|
||||
|
||||
themeData = siteDataExtractFromDb(data.siteData, themeData);
|
||||
themeData.colorsJ = data.siteData.colors;
|
||||
|
||||
if (data.siteData.colors) {
|
||||
themeData.colorsJ = data.siteData.colors;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,17 @@
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { base } from "$app/paths";
|
||||
import { Share2, Link, CopyCheck, Code, TrendingUp, Percent, Loader } from "lucide-svelte";
|
||||
import {
|
||||
Share2,
|
||||
Link,
|
||||
CopyCheck,
|
||||
Code,
|
||||
TrendingUp,
|
||||
Percent,
|
||||
Loader,
|
||||
ChevronLeft,
|
||||
ChevronRight
|
||||
} from "lucide-svelte";
|
||||
import { buttonVariants } from "$lib/components/ui/button";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { afterUpdate } from "svelte";
|
||||
@@ -111,7 +121,7 @@
|
||||
let rolledAt = 0;
|
||||
let rollerLoading = false;
|
||||
async function rollSummary(r) {
|
||||
let newRolledAt = (rolledAt + 1) % uptimesRollers.length;
|
||||
let newRolledAt = (rolledAt + r) % uptimesRollers.length;
|
||||
|
||||
if (uptimesRollers[newRolledAt].value === undefined) {
|
||||
rollerLoading = true;
|
||||
@@ -218,56 +228,67 @@
|
||||
: 'overflow-hidden'} min-h-[94px] pt-2"
|
||||
>
|
||||
<div class="col-span-12">
|
||||
<div class="grid grid-cols-12">
|
||||
<div class="gap- flex justify-between">
|
||||
<div
|
||||
class="{monitor.embed === undefined
|
||||
class=" {monitor.embed === undefined
|
||||
? 'col-span-12'
|
||||
: 'col-span-8'} md:col-span-8"
|
||||
>
|
||||
<Button
|
||||
class="h-8 justify-start text-xs font-semibold transition-all"
|
||||
variant="secondary"
|
||||
disabled={rollerLoading}
|
||||
style="transition: width 2s ease-in;"
|
||||
on:click={() => {
|
||||
scrollToRight();
|
||||
rollSummary();
|
||||
}}
|
||||
>
|
||||
<span class="text-left">
|
||||
{uptimesRollers[rolledAt].text}
|
||||
</span>
|
||||
<div class="flex gap-x-1">
|
||||
{#if rolledAt > 0}
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="h-5 w-5 p-0"
|
||||
on:click={() => rollSummary(-1)}
|
||||
>
|
||||
<ChevronLeft class="h-4 w-4" />
|
||||
</Button>
|
||||
{/if}
|
||||
<div class="flex text-xs font-semibold">
|
||||
<span>
|
||||
{uptimesRollers[rolledAt].text}
|
||||
</span>
|
||||
|
||||
<span class="block w-full pl-2 text-right">
|
||||
{#if rollerLoading}
|
||||
<Loader class="mx-1 inline h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<TrendingUp class="ml-1 mr-1 inline h-3 w-3" />
|
||||
{/if}
|
||||
{#if isNaN(uptimesRollers[rolledAt].value)}
|
||||
<span class="text-muted-foreground">-</span>
|
||||
{:else}
|
||||
<NumberFlow
|
||||
value={uptimesRollers[rolledAt].value}
|
||||
format={{
|
||||
notation: "standard",
|
||||
minimumFractionDigits: 4,
|
||||
maximumFractionDigits: 4
|
||||
}}
|
||||
suffix="%"
|
||||
/>
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
<span class="">
|
||||
{#if rollerLoading}
|
||||
<Loader class="mx-1 -mt-0.5 inline h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<TrendingUp class="mx-1 -mt-0.5 inline h-3 w-3" />
|
||||
{/if}
|
||||
{#if isNaN(uptimesRollers[rolledAt].value)}
|
||||
<span class="text-muted-foreground">-</span>
|
||||
{:else}
|
||||
<NumberFlow
|
||||
value={uptimesRollers[rolledAt].value}
|
||||
format={{
|
||||
notation: "standard",
|
||||
minimumFractionDigits: 4,
|
||||
maximumFractionDigits: 4
|
||||
}}
|
||||
suffix="%"
|
||||
/>
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
{#if rolledAt < uptimesRollers.length - 1}
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="h-5 w-5 p-0"
|
||||
on:click={() => rollSummary(1)}
|
||||
>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="{monitor.embed === undefined
|
||||
class="pt-0.5 {monitor.embed === undefined
|
||||
? 'col-span-12'
|
||||
: 'col-span-4'} text-right md:col-span-4"
|
||||
: 'col-span-4'} text-right md:col-span-4"
|
||||
>
|
||||
<div
|
||||
class="text-api-up mt-3 truncate text-xs font-semibold text-{monitor
|
||||
.pageData.summaryColorClass}"
|
||||
class="text-api-up truncate text-xs font-semibold text-{monitor.pageData
|
||||
.summaryColorClass}"
|
||||
title={monitor.pageData.summaryText}
|
||||
>
|
||||
{summaryTime(lang, monitor.pageData.summaryText)}
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
GetAllTriggers,
|
||||
CreateIncident,
|
||||
AddIncidentComment,
|
||||
AddIncidentMonitor
|
||||
AddIncidentMonitor,
|
||||
InsertNewAlert
|
||||
} from "./controllers/controller.js";
|
||||
|
||||
import db from "./db/db.js";
|
||||
@@ -151,7 +152,7 @@ async function alerting(m) {
|
||||
activeAlert = await db.getActiveAlert(monitor_tag, monitor_status, TRIGGERED);
|
||||
}
|
||||
if (isAffected && !alertExists) {
|
||||
activeAlert = await db.insertAlert({
|
||||
activeAlert = await InsertNewAlert({
|
||||
monitor_tag: monitor_tag,
|
||||
monitor_status: monitor_status,
|
||||
alert_status: TRIGGERED,
|
||||
|
||||
@@ -376,7 +376,6 @@ export const GetDataGroupByDayAlternative = async (
|
||||
const offsetSeconds = offsetMinutes * 60;
|
||||
|
||||
const rawData = await db.getDataGroupByDayAlternative(monitor_tag, start, end);
|
||||
|
||||
const groupedData = rawData.reduce((acc, row) => {
|
||||
// Calculate day group considering timezone offset
|
||||
const dayGroup = Math.floor((row.timestamp + offsetSeconds) / 86400);
|
||||
@@ -673,3 +672,47 @@ export const GetIncidentsByIDS = async (ids) => {
|
||||
|
||||
return incidents;
|
||||
};
|
||||
|
||||
export const InsertNewAlert = async (data) => {
|
||||
if (await db.alertExists(data.monitor_tag, data.monitor_status, data.alert_status)) {
|
||||
return;
|
||||
}
|
||||
await db.insertAlert(data);
|
||||
return await db.getActiveAlert(data.monitor_tag, data.monitor_status, data.alert_status);
|
||||
};
|
||||
|
||||
export const IsLoggedInSession = async (cookies) => {
|
||||
let tokenData = cookies.get("kener-user");
|
||||
if (!!!tokenData) {
|
||||
//redirect to signin page if user is not authenticated
|
||||
//throw redirect(302, base + "/signin");
|
||||
return {
|
||||
error: "User not authenticated",
|
||||
action: "redirect",
|
||||
location: "/signin"
|
||||
};
|
||||
}
|
||||
let tokenUser = await VerifyToken(tokenData);
|
||||
if (!!!tokenUser) {
|
||||
//redirect to signin page if user is not authenticated
|
||||
// throw redirect(302, base + "/signin/logout");
|
||||
return {
|
||||
error: "User not authenticated",
|
||||
action: "redirect",
|
||||
location: "/signin/logout"
|
||||
};
|
||||
}
|
||||
let userDB = await db.getUserByEmail(tokenUser.email);
|
||||
if (!!!userDB) {
|
||||
//redirect to signin page if user is not authenticated
|
||||
// throw redirect(302, base + "/signin");
|
||||
return {
|
||||
error: "User not authenticated",
|
||||
action: "redirect",
|
||||
location: "/signin"
|
||||
};
|
||||
}
|
||||
return {
|
||||
user: userDB
|
||||
};
|
||||
};
|
||||
|
||||
+2
-31
@@ -1,35 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import Sqlite from "./sqlite.js";
|
||||
import Postgres from "./postgres.js";
|
||||
|
||||
let instance = null;
|
||||
|
||||
let database = {
|
||||
sqlite: {
|
||||
dbName: "kener.local5.db"
|
||||
}
|
||||
};
|
||||
const supportedDatabases = ["sqlite"];
|
||||
const dbType = Object.keys(database)[0] || "sqlite";
|
||||
const dbConfig = database[dbType];
|
||||
|
||||
if (!supportedDatabases.includes(dbType)) {
|
||||
console.error(`Database type ${dbType} is not supported`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (dbType === "sqlite") {
|
||||
if (dbConfig.dbName === undefined) {
|
||||
console.error("dbName name is required for sqlite database");
|
||||
process.exit(1);
|
||||
}
|
||||
instance = new Sqlite({
|
||||
dbName: `./database/${dbConfig.dbName}`
|
||||
});
|
||||
}
|
||||
|
||||
//migration2(instance, "./database");
|
||||
|
||||
//create anonymous function to call the init function
|
||||
import knexOb from "../../../../knexfile.js";
|
||||
|
||||
let instance = new Sqlite(knexOb);
|
||||
export default instance;
|
||||
|
||||
@@ -5,12 +5,6 @@ const seedSiteData = {
|
||||
home: "/",
|
||||
logo: "https://kener.ing/logo.png",
|
||||
favicon: "https://kener.ing/logo96.png",
|
||||
github: {
|
||||
apiURL: "https://api.github.com",
|
||||
owner: "rajnandan1",
|
||||
repo: "kener",
|
||||
incidentSince: 720
|
||||
},
|
||||
metaTags: [
|
||||
{
|
||||
key: "description",
|
||||
@@ -45,7 +39,6 @@ const seedSiteData = {
|
||||
}
|
||||
],
|
||||
nav: [
|
||||
{ name: "Manage", url: "/manage", iconURL: "" },
|
||||
{ name: "Documentation", url: "/docs/home", iconURL: "" },
|
||||
{ name: "Github", iconURL: "", url: "https://github.com/rajnandan1/kener" },
|
||||
{ name: "Buy me a coffee", iconURL: "", url: "https://buymeacoffee.com/rajnandan1" }
|
||||
@@ -66,7 +59,7 @@ const seedSiteData = {
|
||||
{ code: "vi", name: "Tiếng Việt", selected: true, disabled: false }
|
||||
]
|
||||
},
|
||||
pattern: "squares",
|
||||
pattern: "none",
|
||||
analytics: [
|
||||
{
|
||||
id: "G-Q3MLRXCBFT",
|
||||
@@ -101,7 +94,9 @@ const seedSiteData = {
|
||||
cssSrc: "https://fonts.googleapis.com/css2?family=Albert+Sans:ital,wght@0,100..900;1,100..900&display=swap",
|
||||
family: "Albert Sans"
|
||||
},
|
||||
categories: [{ name: "Home", description: "Monitors for Home Page" }]
|
||||
categories: [{ name: "Home", description: "Monitors for Home Page" }],
|
||||
homeIncidentCount: 5,
|
||||
homeIncidentStartTimeWithin: 30
|
||||
};
|
||||
|
||||
export default seedSiteData;
|
||||
|
||||
+525
-623
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,6 @@
|
||||
import { json, redirect } from "@sveltejs/kit";
|
||||
import { base } from "$app/paths";
|
||||
import db from "$lib/server/db/db.js";
|
||||
import seedSiteData from "$lib/server/db/seedSiteData.js";
|
||||
import seedMonitorData from "$lib/server/db/seedMonitorData.js";
|
||||
import { HashPassword, GenerateSalt } from "$lib/server/controllers/controller.js";
|
||||
|
||||
//function to validate a strong password
|
||||
@@ -52,21 +50,5 @@ export async function POST({ request }) {
|
||||
}
|
||||
|
||||
await db.insertUser(user);
|
||||
|
||||
for (const key in seedSiteData) {
|
||||
if (Object.prototype.hasOwnProperty.call(seedSiteData, key)) {
|
||||
let value = seedSiteData[key];
|
||||
let data_type = typeof value;
|
||||
if (data_type === "object") {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
await db.insertOrUpdateSiteData(key, value, data_type);
|
||||
}
|
||||
}
|
||||
//loop through array seedMonitorData
|
||||
for (const monitor of seedMonitorData) {
|
||||
await db.insertMonitor(monitor);
|
||||
}
|
||||
|
||||
throw redirect(302, base + "");
|
||||
throw redirect(302, base + "/");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
import i18n from "$lib/i18n/server";
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
import { base } from "$app/paths";
|
||||
import { GetAllSiteData, IsSetupComplete } from "$lib/server/controllers/controller.js";
|
||||
import {
|
||||
GetAllSiteData,
|
||||
IsSetupComplete,
|
||||
IsLoggedInSession
|
||||
} from "$lib/server/controllers/controller.js";
|
||||
|
||||
export async function load({ params, route, url, cookies, request }) {
|
||||
let isSetupComplete = await IsSetupComplete();
|
||||
@@ -14,6 +18,8 @@ export async function load({ params, route, url, cookies, request }) {
|
||||
throw redirect(302, base + "/setup");
|
||||
}
|
||||
|
||||
let isLoggedIn = await IsLoggedInSession(cookies);
|
||||
|
||||
let site = await GetAllSiteData();
|
||||
const headers = request.headers;
|
||||
const userAgent = headers.get("user-agent");
|
||||
@@ -56,6 +62,7 @@ export async function load({ params, route, url, cookies, request }) {
|
||||
lang: i18n(String(selectedLang)),
|
||||
selectedLang: selectedLang,
|
||||
embed,
|
||||
bgc
|
||||
bgc,
|
||||
isLoggedIn: !!isLoggedIn.user
|
||||
};
|
||||
}
|
||||
|
||||
@@ -202,6 +202,11 @@
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if data.isLoggedIn}
|
||||
<a href="{base}/manage/site" class="button-77 fixed bottom-8 left-8" role="button">
|
||||
Manage
|
||||
</a>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -15,9 +15,9 @@ export async function POST({ request }) {
|
||||
const start = payload.startTs;
|
||||
let end = GetMinuteStartNowTimestampUTC();
|
||||
let aggregatedData = await db.getAggregatedMonitoringData(monitor.tag, start, end);
|
||||
let ups = Number(aggregatedData.UP);
|
||||
let downs = Number(aggregatedData.DOWN);
|
||||
let degradeds = Number(aggregatedData.DEGRADED);
|
||||
let ups = Number(aggregatedData.UP || aggregatedData.up);
|
||||
let downs = Number(aggregatedData.DOWN || aggregatedData.down);
|
||||
let degradeds = Number(aggregatedData.DEGRADED || aggregatedData.degraded);
|
||||
|
||||
let total = ups + downs + degradeds;
|
||||
let uptime = ParseUptime(ups + degradeds, total);
|
||||
|
||||
@@ -38,9 +38,9 @@ export async function GET({ params, url }) {
|
||||
}
|
||||
|
||||
let dbData = await db.getAggregatedMonitoringData(tag, since, now);
|
||||
dbData.UP = Number(dbData.UP);
|
||||
dbData.DOWN = Number(dbData.DOWN);
|
||||
dbData.DEGRADED = Number(dbData.DEGRADED);
|
||||
dbData.UP = Number(dbData.UP || dbData.up);
|
||||
dbData.DOWN = Number(dbData.DOWN || dbData.down);
|
||||
dbData.DEGRADED = Number(dbData.DEGRADED || dbData.degraded);
|
||||
let numerator = dbData.UP + dbData.DEGRADED;
|
||||
let denominator = dbData.UP + dbData.DEGRADED + dbData.DOWN;
|
||||
if (include_degraded_in_downtime === "YES") {
|
||||
|
||||
@@ -89,10 +89,7 @@
|
||||
class="mx-auto mb-2 mt-4 flex w-full flex-1 flex-col items-start justify-center bg-transparent md:w-[655px]"
|
||||
>
|
||||
{#if sortedIncidentSmartDates.length == 0}
|
||||
<div
|
||||
class="mx-auto w-full rounded-md bg-clip-text p-12 text-center text-transparent"
|
||||
style="background-image: linear-gradient( 135deg, #2AFADF 10%, #4C83FF 100%);"
|
||||
>
|
||||
<div class="mx-auto w-full rounded-md bg-clip-text p-12 text-center">
|
||||
<div class="mx-auto mb-4 h-[32px] w-[32px] text-primary">
|
||||
<picture>
|
||||
<source
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
</script>
|
||||
|
||||
<div class="min-h-[70vh]">
|
||||
<div class="mt-4 flex justify-between">
|
||||
<div class="mt-4 flex justify-end">
|
||||
<div class="flex w-40">
|
||||
<Select.Root
|
||||
portal={null}
|
||||
@@ -375,7 +375,7 @@
|
||||
fetchData();
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="statusmonitor">
|
||||
<Select.Trigger class="hidden" id="statusmonitor">
|
||||
<Select.Value bind:value={status} placeholder={status} />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
@@ -385,10 +385,10 @@
|
||||
ALL
|
||||
</Select.Item>
|
||||
<Select.Item value="OPEN" label="OPEN" class="text-sm font-medium">
|
||||
OPEN
|
||||
ACTIVE
|
||||
</Select.Item>
|
||||
<Select.Item value="CLOSED" label="CLOSED" class="text-sm font-medium">
|
||||
CLOSED
|
||||
DELETED
|
||||
</Select.Item>
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="min-h-[70vh]">
|
||||
<MonitorsAdd
|
||||
categories={data.siteData?.categories}
|
||||
colorDown={data.siteData?.colors.DOWN}
|
||||
colorDegraded={data.siteData?.colors.DEGRADED}
|
||||
colorDown={data.siteData?.colors?.DOWN || "#ca3038"}
|
||||
colorDegraded={data.siteData?.colors?.DEGRADED || "#e6ca61"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user