mirror of https://github.com/louislam/uptime-kuma
				
				
				
			Drop unused code
							parent
							
								
									4b913c8b4c
								
							
						
					
					
						commit
						df8fcffb19
					
				| 
						 | 
				
			
			@ -133,6 +133,15 @@
 | 
			
		|||
                "node": "14.* || 16.* || 18.*"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/@aashutoshrathi/word-wrap": {
 | 
			
		||||
            "version": "1.2.6",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
 | 
			
		||||
            "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
 | 
			
		||||
            "dev": true,
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">=0.10.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/@actions/github": {
 | 
			
		||||
            "version": "5.0.3",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -15193,17 +15202,17 @@
 | 
			
		|||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/optionator": {
 | 
			
		||||
            "version": "0.9.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
 | 
			
		||||
            "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
 | 
			
		||||
            "version": "0.9.3",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
 | 
			
		||||
            "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
 | 
			
		||||
            "dev": true,
 | 
			
		||||
            "dependencies": {
 | 
			
		||||
                "@aashutoshrathi/word-wrap": "^1.2.3",
 | 
			
		||||
                "deep-is": "^0.1.3",
 | 
			
		||||
                "fast-levenshtein": "^2.0.6",
 | 
			
		||||
                "levn": "^0.4.1",
 | 
			
		||||
                "prelude-ls": "^1.2.1",
 | 
			
		||||
                "type-check": "^0.4.0",
 | 
			
		||||
                "word-wrap": "^1.2.3"
 | 
			
		||||
                "type-check": "^0.4.0"
 | 
			
		||||
            },
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">= 0.8.0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ const { R } = require("redbean-node");
 | 
			
		|||
const { setSetting, setting } = require("./util-server");
 | 
			
		||||
const { log, sleep } = require("../src/util");
 | 
			
		||||
const knex = require("knex");
 | 
			
		||||
const { PluginsManager } = require("./plugins-manager");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Database & App Data Folder
 | 
			
		||||
| 
						 | 
				
			
			@ -88,12 +88,6 @@ class Database {
 | 
			
		|||
        // Data Directory (must be end with "/")
 | 
			
		||||
        Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
 | 
			
		||||
 | 
			
		||||
        // Plugin feature is working only if the dataDir = "./data";
 | 
			
		||||
        if (Database.dataDir !== "./data/") {
 | 
			
		||||
            log.warn("PLUGIN", "Warning: In order to enable plugin feature, you need to use the default data directory: ./data/");
 | 
			
		||||
            PluginsManager.disable = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Database.path = Database.dataDir + "kuma.db";
 | 
			
		||||
        if (! fs.existsSync(Database.dataDir)) {
 | 
			
		||||
            fs.mkdirSync(Database.dataDir, { recursive: true });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,24 +0,0 @@
 | 
			
		|||
const childProcess = require("child_process");
 | 
			
		||||
 | 
			
		||||
class Git {
 | 
			
		||||
 | 
			
		||||
    static clone(repoURL, cwd, targetDir = ".") {
 | 
			
		||||
        let result = childProcess.spawnSync("git", [
 | 
			
		||||
            "clone",
 | 
			
		||||
            repoURL,
 | 
			
		||||
            targetDir,
 | 
			
		||||
        ], {
 | 
			
		||||
            cwd: cwd,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (result.status !== 0) {
 | 
			
		||||
            throw new Error(result.stderr.toString("utf-8"));
 | 
			
		||||
        } else {
 | 
			
		||||
            return result.stdout.toString("utf-8") + result.stderr.toString("utf-8");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    Git,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,13 +0,0 @@
 | 
			
		|||
class Plugin {
 | 
			
		||||
    async load() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async unload() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    Plugin,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,256 +0,0 @@
 | 
			
		|||
const fs = require("fs");
 | 
			
		||||
const { log } = require("../src/util");
 | 
			
		||||
const path = require("path");
 | 
			
		||||
const axios = require("axios");
 | 
			
		||||
const { Git } = require("./git");
 | 
			
		||||
const childProcess = require("child_process");
 | 
			
		||||
 | 
			
		||||
class PluginsManager {
 | 
			
		||||
 | 
			
		||||
    static disable = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Plugin List
 | 
			
		||||
     * @type {PluginWrapper[]}
 | 
			
		||||
     */
 | 
			
		||||
    pluginList = [];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Plugins Dir
 | 
			
		||||
     */
 | 
			
		||||
    pluginsDir;
 | 
			
		||||
 | 
			
		||||
    server;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {UptimeKumaServer} server
 | 
			
		||||
     */
 | 
			
		||||
    constructor(server) {
 | 
			
		||||
        this.server = server;
 | 
			
		||||
 | 
			
		||||
        if (!PluginsManager.disable) {
 | 
			
		||||
            this.pluginsDir = "./data/plugins/";
 | 
			
		||||
 | 
			
		||||
            if (! fs.existsSync(this.pluginsDir)) {
 | 
			
		||||
                fs.mkdirSync(this.pluginsDir, { recursive: true });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            log.debug("plugin", "Scanning plugin directory");
 | 
			
		||||
            let list = fs.readdirSync(this.pluginsDir);
 | 
			
		||||
 | 
			
		||||
            this.pluginList = [];
 | 
			
		||||
            for (let item of list) {
 | 
			
		||||
                this.loadPlugin(item);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            log.warn("PLUGIN", "Skip scanning plugin directory");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Install a Plugin
 | 
			
		||||
     */
 | 
			
		||||
    async loadPlugin(name) {
 | 
			
		||||
        log.info("plugin", "Load " + name);
 | 
			
		||||
        let plugin = new PluginWrapper(this.server, this.pluginsDir + name);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await plugin.load();
 | 
			
		||||
            this.pluginList.push(plugin);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log.error("plugin", "Failed to load plugin: " + this.pluginsDir + name);
 | 
			
		||||
            log.error("plugin", "Reason: " + e.message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Download a Plugin
 | 
			
		||||
     * @param {string} repoURL Git repo url
 | 
			
		||||
     * @param {string} name Directory name, also known as plugin unique name
 | 
			
		||||
     */
 | 
			
		||||
    downloadPlugin(repoURL, name) {
 | 
			
		||||
        if (fs.existsSync(this.pluginsDir + name)) {
 | 
			
		||||
            log.info("plugin", "Plugin folder already exists? Removing...");
 | 
			
		||||
            fs.rmSync(this.pluginsDir + name, {
 | 
			
		||||
                recursive: true
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        log.info("plugin", "Installing plugin: " + name + " " + repoURL);
 | 
			
		||||
        let result = Git.clone(repoURL, this.pluginsDir, name);
 | 
			
		||||
        log.info("plugin", "Install result: " + result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove a plugin
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     */
 | 
			
		||||
    async removePlugin(name) {
 | 
			
		||||
        log.info("plugin", "Removing plugin: " + name);
 | 
			
		||||
        for (let plugin of this.pluginList) {
 | 
			
		||||
            if (plugin.info.name === name) {
 | 
			
		||||
                await plugin.unload();
 | 
			
		||||
 | 
			
		||||
                // Delete the plugin directory
 | 
			
		||||
                fs.rmSync(this.pluginsDir + name, {
 | 
			
		||||
                    recursive: true
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.pluginList.splice(this.pluginList.indexOf(plugin), 1);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        log.warn("plugin", "Plugin not found: " + name);
 | 
			
		||||
        throw new Error("Plugin not found: " + name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * TODO: Update a plugin
 | 
			
		||||
     * Only available for plugins which were downloaded from the official list
 | 
			
		||||
     * @param pluginID
 | 
			
		||||
     */
 | 
			
		||||
    updatePlugin(pluginID) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the plugin list from server + local installed plugin list
 | 
			
		||||
     * Item will be merged if the `name` is the same.
 | 
			
		||||
     * @returns {Promise<[]>}
 | 
			
		||||
     */
 | 
			
		||||
    async fetchPluginList() {
 | 
			
		||||
        let remotePluginList;
 | 
			
		||||
        try {
 | 
			
		||||
            const res = await axios.get("https://uptime.kuma.pet/c/plugins.json");
 | 
			
		||||
            remotePluginList = res.data.pluginList;
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log.error("plugin", "Failed to fetch plugin list: " + e.message);
 | 
			
		||||
            remotePluginList = [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let plugin of this.pluginList) {
 | 
			
		||||
            let find = false;
 | 
			
		||||
            // Try to merge
 | 
			
		||||
            for (let remotePlugin of remotePluginList) {
 | 
			
		||||
                if (remotePlugin.name === plugin.info.name) {
 | 
			
		||||
                    find = true;
 | 
			
		||||
                    remotePlugin.installed = true;
 | 
			
		||||
                    remotePlugin.name = plugin.info.name;
 | 
			
		||||
                    remotePlugin.fullName = plugin.info.fullName;
 | 
			
		||||
                    remotePlugin.description = plugin.info.description;
 | 
			
		||||
                    remotePlugin.version = plugin.info.version;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Local plugin
 | 
			
		||||
            if (!find) {
 | 
			
		||||
                plugin.info.local = true;
 | 
			
		||||
                remotePluginList.push(plugin.info);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Sort Installed first, then sort by name
 | 
			
		||||
        return remotePluginList.sort((a, b) => {
 | 
			
		||||
            if (a.installed === b.installed) {
 | 
			
		||||
                if (a.fullName < b.fullName) {
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
                if (a.fullName > b.fullName) {
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
                return 0;
 | 
			
		||||
            } else if (a.installed) {
 | 
			
		||||
                return -1;
 | 
			
		||||
            } else {
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PluginWrapper {
 | 
			
		||||
 | 
			
		||||
    server = undefined;
 | 
			
		||||
    pluginDir = undefined;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Must be an `new-able` class.
 | 
			
		||||
     * @type {function}
 | 
			
		||||
     */
 | 
			
		||||
    pluginClass = undefined;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @type {Plugin}
 | 
			
		||||
     */
 | 
			
		||||
    object = undefined;
 | 
			
		||||
    info = {};
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {UptimeKumaServer} server
 | 
			
		||||
     * @param {string} pluginDir
 | 
			
		||||
     */
 | 
			
		||||
    constructor(server, pluginDir) {
 | 
			
		||||
        this.server = server;
 | 
			
		||||
        this.pluginDir = pluginDir;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async load() {
 | 
			
		||||
        let indexFile = this.pluginDir + "/index.js";
 | 
			
		||||
        let packageJSON = this.pluginDir + "/package.json";
 | 
			
		||||
 | 
			
		||||
        log.info("plugin", "Installing dependencies");
 | 
			
		||||
 | 
			
		||||
        if (fs.existsSync(indexFile)) {
 | 
			
		||||
            // Install dependencies
 | 
			
		||||
            let result = childProcess.spawnSync("npm", [ "install" ], {
 | 
			
		||||
                cwd: this.pluginDir,
 | 
			
		||||
                env: {
 | 
			
		||||
                    ...process.env,
 | 
			
		||||
                    PLAYWRIGHT_BROWSERS_PATH: "../../browsers",    // Special handling for read-browser-monitor
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (result.stdout) {
 | 
			
		||||
                log.info("plugin", "Install dependencies result: " + result.stdout.toString("utf-8"));
 | 
			
		||||
            } else {
 | 
			
		||||
                log.warn("plugin", "Install dependencies result: no output");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.pluginClass = require(path.join(process.cwd(), indexFile));
 | 
			
		||||
 | 
			
		||||
            let pluginClassType = typeof this.pluginClass;
 | 
			
		||||
 | 
			
		||||
            if (pluginClassType === "function") {
 | 
			
		||||
                this.object = new this.pluginClass(this.server);
 | 
			
		||||
                await this.object.load();
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new Error("Invalid plugin, it does not export a class");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (fs.existsSync(packageJSON)) {
 | 
			
		||||
                this.info = require(path.join(process.cwd(), packageJSON));
 | 
			
		||||
            } else {
 | 
			
		||||
                this.info.fullName = this.pluginDir;
 | 
			
		||||
                this.info.name = "[unknown]";
 | 
			
		||||
                this.info.version = "[unknown-version]";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.info.installed = true;
 | 
			
		||||
            log.info("plugin", `${this.info.fullName} v${this.info.version} loaded`);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async unload() {
 | 
			
		||||
        await this.object.unload();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    PluginsManager,
 | 
			
		||||
    PluginWrapper
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,6 @@ const { apiKeySocketHandler } = require("./socket-handlers/api-key-socket-handle
 | 
			
		|||
const { generalSocketHandler } = require("./socket-handlers/general-socket-handler");
 | 
			
		||||
const { Settings } = require("./settings");
 | 
			
		||||
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
 | 
			
		||||
const { pluginsHandler } = require("./socket-handlers/plugins-handler");
 | 
			
		||||
const apicache = require("./modules/apicache");
 | 
			
		||||
 | 
			
		||||
app.use(express.json());
 | 
			
		||||
| 
						 | 
				
			
			@ -177,7 +176,6 @@ let needSetup = false;
 | 
			
		|||
    Database.init(args);
 | 
			
		||||
    await initDatabase(testMode);
 | 
			
		||||
    await server.initAfterDatabaseReady();
 | 
			
		||||
    server.loadPlugins();
 | 
			
		||||
    server.entryPage = await Settings.get("entryPage");
 | 
			
		||||
    await StatusPage.loadDomainMappingList();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1537,7 +1535,6 @@ let needSetup = false;
 | 
			
		|||
        maintenanceSocketHandler(socket);
 | 
			
		||||
        apiKeySocketHandler(socket);
 | 
			
		||||
        generalSocketHandler(socket, server);
 | 
			
		||||
        pluginsHandler(socket, server);
 | 
			
		||||
 | 
			
		||||
        log.debug("server", "added all socket handlers");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,69 +0,0 @@
 | 
			
		|||
const { checkLogin } = require("../util-server");
 | 
			
		||||
const { PluginsManager } = require("../plugins-manager");
 | 
			
		||||
const { log } = require("../../src/util.js");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handlers for plugins
 | 
			
		||||
 * @param {Socket} socket Socket.io instance
 | 
			
		||||
 * @param {UptimeKumaServer} server
 | 
			
		||||
 */
 | 
			
		||||
module.exports.pluginsHandler = (socket, server) => {
 | 
			
		||||
 | 
			
		||||
    const pluginManager = server.getPluginManager();
 | 
			
		||||
 | 
			
		||||
    // Get Plugin List
 | 
			
		||||
    socket.on("getPluginList", async (callback) => {
 | 
			
		||||
        try {
 | 
			
		||||
            checkLogin(socket);
 | 
			
		||||
 | 
			
		||||
            log.debug("plugin", "PluginManager.disable: " + PluginsManager.disable);
 | 
			
		||||
 | 
			
		||||
            if (PluginsManager.disable) {
 | 
			
		||||
                throw new Error("Plugin Disabled: In order to enable plugin feature, you need to use the default data directory: ./data/");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let pluginList = await pluginManager.fetchPluginList();
 | 
			
		||||
            callback({
 | 
			
		||||
                ok: true,
 | 
			
		||||
                pluginList,
 | 
			
		||||
            });
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            log.warn("plugin", "Error: " + error.message);
 | 
			
		||||
            callback({
 | 
			
		||||
                ok: false,
 | 
			
		||||
                msg: error.message,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    socket.on("installPlugin", async (repoURL, name, callback) => {
 | 
			
		||||
        try {
 | 
			
		||||
            checkLogin(socket);
 | 
			
		||||
            pluginManager.downloadPlugin(repoURL, name);
 | 
			
		||||
            await pluginManager.loadPlugin(name);
 | 
			
		||||
            callback({
 | 
			
		||||
                ok: true,
 | 
			
		||||
            });
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            callback({
 | 
			
		||||
                ok: false,
 | 
			
		||||
                msg: error.message,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    socket.on("uninstallPlugin", async (name, callback) => {
 | 
			
		||||
        try {
 | 
			
		||||
            checkLogin(socket);
 | 
			
		||||
            await pluginManager.removePlugin(name);
 | 
			
		||||
            callback({
 | 
			
		||||
                ok: true,
 | 
			
		||||
            });
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            callback({
 | 
			
		||||
                ok: false,
 | 
			
		||||
                msg: error.message,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,6 @@ const util = require("util");
 | 
			
		|||
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
 | 
			
		||||
const { Settings } = require("./settings");
 | 
			
		||||
const dayjs = require("dayjs");
 | 
			
		||||
const { PluginsManager } = require("./plugins-manager");
 | 
			
		||||
// DO NOT IMPORT HERE IF THE MODULES USED `UptimeKumaServer.getInstance()`
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -47,12 +46,6 @@ class UptimeKumaServer {
 | 
			
		|||
     */
 | 
			
		||||
    indexHTML = "";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Plugins Manager
 | 
			
		||||
     * @type {PluginsManager}
 | 
			
		||||
     */
 | 
			
		||||
    pluginsManager = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @type {{}}
 | 
			
		||||
| 
						 | 
				
			
			@ -289,46 +282,6 @@ class UptimeKumaServer {
 | 
			
		|||
    async stop() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    loadPlugins() {
 | 
			
		||||
        this.pluginsManager = new PluginsManager(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @returns {PluginsManager}
 | 
			
		||||
     */
 | 
			
		||||
    getPluginManager() {
 | 
			
		||||
        return this.pluginsManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {MonitorType} monitorType
 | 
			
		||||
     */
 | 
			
		||||
    addMonitorType(monitorType) {
 | 
			
		||||
        if (monitorType instanceof MonitorType && monitorType.name) {
 | 
			
		||||
            if (monitorType.name in UptimeKumaServer.monitorTypeList) {
 | 
			
		||||
                log.error("", "Conflict Monitor Type name");
 | 
			
		||||
            }
 | 
			
		||||
            UptimeKumaServer.monitorTypeList[monitorType.name] = monitorType;
 | 
			
		||||
        } else {
 | 
			
		||||
            log.error("", "Invalid Monitor Type: " + monitorType.name);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {MonitorType} monitorType
 | 
			
		||||
     */
 | 
			
		||||
    removeMonitorType(monitorType) {
 | 
			
		||||
        if (UptimeKumaServer.monitorTypeList[monitorType.name] === monitorType) {
 | 
			
		||||
            delete UptimeKumaServer.monitorTypeList[monitorType.name];
 | 
			
		||||
        } else {
 | 
			
		||||
            log.error("", "Remove MonitorType failed: " + monitorType.name);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,102 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div v-if="! (!plugin.installed && plugin.local)" class="plugin-item pt-4 pb-2">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
            <h5>{{ plugin.fullName }}</h5>
 | 
			
		||||
            <p class="description">
 | 
			
		||||
                {{ plugin.description }}
 | 
			
		||||
            </p>
 | 
			
		||||
            <span class="version">{{ $t("Version") }}: {{ plugin.version }} <a v-if="plugin.repo" :href="plugin.repo" target="_blank">Repo</a></span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="buttons">
 | 
			
		||||
            <button v-if="status === 'installing'" class="btn btn-primary" disabled>{{ $t("installing") }}</button>
 | 
			
		||||
            <button v-else-if="status === 'uninstalling'" class="btn btn-danger" disabled>{{ $t("uninstalling") }}</button>
 | 
			
		||||
            <button v-else-if="plugin.installed || status === 'installed'" class="btn btn-danger" @click="deleteConfirm">{{ $t("uninstall") }}</button>
 | 
			
		||||
            <button v-else class="btn btn-primary" @click="install">{{ $t("install") }}</button>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="uninstall">
 | 
			
		||||
            {{ $t("confirmUninstallPlugin") }}
 | 
			
		||||
        </Confirm>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Confirm from "./Confirm.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    components: {
 | 
			
		||||
        Confirm,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
        plugin: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            status: "",
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        /**
 | 
			
		||||
         * Show confirmation for deleting a tag
 | 
			
		||||
         */
 | 
			
		||||
        deleteConfirm() {
 | 
			
		||||
            this.$refs.confirmDelete.show();
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        install() {
 | 
			
		||||
            this.status = "installing";
 | 
			
		||||
 | 
			
		||||
            this.$root.getSocket().emit("installPlugin", this.plugin.repo, this.plugin.name, (res) => {
 | 
			
		||||
                if (res.ok) {
 | 
			
		||||
                    this.status = "";
 | 
			
		||||
                    // eslint-disable-next-line vue/no-mutating-props
 | 
			
		||||
                    this.plugin.installed = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$root.toastRes(res);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        uninstall() {
 | 
			
		||||
            this.status = "uninstalling";
 | 
			
		||||
 | 
			
		||||
            this.$root.getSocket().emit("uninstallPlugin", this.plugin.name, (res) => {
 | 
			
		||||
                if (res.ok) {
 | 
			
		||||
                    this.status = "";
 | 
			
		||||
                    // eslint-disable-next-line vue/no-mutating-props
 | 
			
		||||
                    this.plugin.installed = false;
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$root.toastRes(res);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
@import "../assets/vars.scss";
 | 
			
		||||
 | 
			
		||||
.plugin-item {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    align-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    .info {
 | 
			
		||||
        margin-right: 10px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .description {
 | 
			
		||||
        font-size: 13px;
 | 
			
		||||
        margin-bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .version {
 | 
			
		||||
        font-size: 13px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,57 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <div class="mt-3">{{ remotePluginListMsg }}</div>
 | 
			
		||||
        <PluginItem v-for="plugin in remotePluginList" :key="plugin.id" :plugin="plugin" />
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import PluginItem from "../PluginItem.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    components: {
 | 
			
		||||
        PluginItem
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            remotePluginList: [],
 | 
			
		||||
            remotePluginListMsg: "",
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computed: {
 | 
			
		||||
        pluginList() {
 | 
			
		||||
            return this.$parent.$parent.$parent.pluginList;
 | 
			
		||||
        },
 | 
			
		||||
        settings() {
 | 
			
		||||
            return this.$parent.$parent.$parent.settings;
 | 
			
		||||
        },
 | 
			
		||||
        saveSettings() {
 | 
			
		||||
            return this.$parent.$parent.$parent.saveSettings;
 | 
			
		||||
        },
 | 
			
		||||
        settingsLoaded() {
 | 
			
		||||
            return this.$parent.$parent.$parent.settingsLoaded;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async mounted() {
 | 
			
		||||
        this.loadList();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        loadList() {
 | 
			
		||||
            this.remotePluginListMsg = this.$t("Loading") + "...";
 | 
			
		||||
 | 
			
		||||
            this.$root.getSocket().emit("getPluginList", (res) => {
 | 
			
		||||
                if (res.ok) {
 | 
			
		||||
                    this.remotePluginList = res.pluginList;
 | 
			
		||||
                    this.remotePluginListMsg = "";
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.remotePluginListMsg = this.$t("loadingError") + " " + res.msg;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -116,12 +116,6 @@ export default {
 | 
			
		|||
                backup: {
 | 
			
		||||
                    title: this.$t("Backup"),
 | 
			
		||||
                },
 | 
			
		||||
                /*
 | 
			
		||||
                Hidden for now: Unfortunately, after some test, I found that Playwright requires a lot of libraries to be installed on the Linux host in order to start Chrome or Firefox.
 | 
			
		||||
                It will be hard to install, so I hide this feature for now. But it still accessible via URL: /settings/plugins.
 | 
			
		||||
                plugins: {
 | 
			
		||||
                    title: this.$tc("plugin", 2),
 | 
			
		||||
                },*/
 | 
			
		||||
                about: {
 | 
			
		||||
                    title: this.$t("About"),
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,6 @@ import DockerHosts from "./components/settings/Docker.vue";
 | 
			
		|||
import MaintenanceDetails from "./pages/MaintenanceDetails.vue";
 | 
			
		||||
import ManageMaintenance from "./pages/ManageMaintenance.vue";
 | 
			
		||||
import APIKeys from "./components/settings/APIKeys.vue";
 | 
			
		||||
import Plugins from "./components/settings/Plugins.vue";
 | 
			
		||||
 | 
			
		||||
// Settings - Sub Pages
 | 
			
		||||
import Appearance from "./components/settings/Appearance.vue";
 | 
			
		||||
| 
						 | 
				
			
			@ -130,10 +129,6 @@ const routes = [
 | 
			
		|||
                                path: "backup",
 | 
			
		||||
                                component: Backup,
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                path: "plugins",
 | 
			
		||||
                                component: Plugins,
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                path: "about",
 | 
			
		||||
                                component: About,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue