From 710dbacb03b885a26ee3675b1e79b63fe03738cb Mon Sep 17 00:00:00 2001 From: TfT Hacker Date: Sun, 27 Oct 2024 13:09:16 +0100 Subject: [PATCH] Biome linting adjustments --- .vscode/settings.json | 5 + CHANGELOG.md | 10 + esbuild.config.mjs | 1 + package.json | 4 +- src/features/BetaPlugins.ts | 1055 +++++++++++++++---------------- src/features/githubUtils.ts | 508 ++++++++------- src/features/themes.ts | 262 ++++---- src/main.ts | 164 +++-- src/settings.ts | 160 ++--- src/types.d.ts | 6 +- src/ui/AddNewPluginModal.ts | 306 ++++----- src/ui/AddNewTheme.ts | 188 +++--- src/ui/GenericFuzzySuggester.ts | 132 ++-- src/ui/PluginCommands.ts | 730 ++++++++++----------- src/ui/Promotional.ts | 50 +- src/ui/SettingsTab.ts | 468 +++++++------- src/ui/icons.ts | 8 +- src/utils/BratAPI.ts | 126 ++-- src/utils/internetconnection.ts | 12 +- src/utils/logging.ts | 54 +- src/utils/notifications.ts | 38 +- styles.css | 4 +- version-bump.mjs | 6 +- 23 files changed, 2153 insertions(+), 2144 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f7f3d8c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.codeActionsOnSave":{ + "source.organizeImports.biome": "explicit" + } +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b708c0e..bc6178f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# 1.0.4 + +### New +- The internal command names have been renamed. Any plugins using these internal command names will need to be updated. + +### Updates +- Transition to Biome from EsLint and Prettier. +- Updating plugint to newest Obsidian recommendations https://docs.obsidian.md/oo24/plugin + + # 1.0.3 ### fix diff --git a/esbuild.config.mjs b/esbuild.config.mjs index a0c48f6..f6efe8c 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -16,6 +16,7 @@ const prod = process.argv[2] === "production"; const context = await esbuild.context({ entryPoints: ["src/main.ts"], bundle: true, + minify: prod, external: [ "obsidian", "electron", diff --git a/package.json b/package.json index 401c226..fdb41f8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "node --no-warnings esbuild.config.mjs", "build": "node --no-warnings esbuild.config.mjs production", - "lint": "biome check .", + "lint": "biome check ./src", "version": "node version-bump.mjs", "githubaction": "node version-github-action.mjs" }, @@ -19,10 +19,8 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@types/node": "^22.5.5", - "@types/obsidian-typings": "github:Fevol/obsidian-typings", "builtin-modules": "4.0.0", "esbuild": "0.23.1", - "eslint": "^8.57.0", "jsdom": "^25.0.0", "obsidian": "1.7.2", "ts-node": "^10.9.2", diff --git a/src/features/BetaPlugins.ts b/src/features/BetaPlugins.ts index 4421a2a..3c9ab7e 100644 --- a/src/features/BetaPlugins.ts +++ b/src/features/BetaPlugins.ts @@ -1,574 +1,567 @@ -import type ThePlugin from "../main"; -import AddNewPluginModal from "../ui/AddNewPluginModal"; -import { - grabManifestJsonFromRepository, - grabReleaseFileFromRepository, -} from "./githubUtils"; import type { PluginManifest } from "obsidian"; -import { normalizePath, Notice, requireApiVersion, apiVersion } from "obsidian"; +import { Notice, apiVersion, normalizePath, requireApiVersion } from "obsidian"; +import type BratPlugin from "../main"; import { addBetaPluginToList } from "../settings"; -import { toastMessage } from "../utils/notifications"; +import AddNewPluginModal from "../ui/AddNewPluginModal"; import { isConnectedToInternet } from "../utils/internetconnection"; +import { toastMessage } from "../utils/notifications"; +import { + grabManifestJsonFromRepository, + grabReleaseFileFromRepository, +} from "./githubUtils"; /** * all the files needed for a plugin based on the release files are hre */ interface ReleaseFiles { - mainJs: string | null; - manifest: string | null; - styles: string | null; + mainJs: string | null; + manifest: string | null; + styles: string | null; } /** * Primary handler for adding, updating, deleting beta plugins tracked by this plugin */ export default class BetaPlugins { - plugin: ThePlugin; + plugin: BratPlugin; - constructor(plugin: ThePlugin) { - this.plugin = plugin; - } + constructor(plugin: BratPlugin) { + this.plugin = plugin; + } - /** - * opens the AddNewPluginModal to get info for a new beta plugin - * @param openSettingsTabAfterwards - will open settings screen afterwards. Used when this command is called from settings tab - * @param useFrozenVersion - install the plugin using frozen version. - */ - displayAddNewPluginModal( - openSettingsTabAfterwards = false, - useFrozenVersion = false - ): void { - const newPlugin = new AddNewPluginModal( - this.plugin, - this, - openSettingsTabAfterwards, - useFrozenVersion - ); - newPlugin.open(); - } + /** + * opens the AddNewPluginModal to get info for a new beta plugin + * @param openSettingsTabAfterwards - will open settings screen afterwards. Used when this command is called from settings tab + * @param useFrozenVersion - install the plugin using frozen version. + */ + displayAddNewPluginModal( + openSettingsTabAfterwards = false, + useFrozenVersion = false, + ): void { + const newPlugin = new AddNewPluginModal( + this.plugin, + this, + openSettingsTabAfterwards, + useFrozenVersion, + ); + newPlugin.open(); + } - /** - * Validates that a GitHub repository is plugin - * - * @param repositoryPath - GithubUser/RepositoryName (example: TfThacker/obsidian42-brat) - * @param getBetaManifest - test the beta version of the manifest, not at the root - * @param false - [false description] - * @param reportIssues - will display notices as it finds issues - * - * @returns the manifest file if found, or null if its incomplete - */ - async validateRepository( - repositoryPath: string, - getBetaManifest = false, - reportIssues = false - ): Promise { - const noticeTimeout = 15; - const manifestJson = await grabManifestJsonFromRepository( - repositoryPath, - !getBetaManifest, - this.plugin.settings.debuggingMode, - this.plugin.settings.personalAccessToken - ); - if (!manifestJson) { - // this is a plugin with a manifest json, try to see if there is a beta version - if (reportIssues) { - toastMessage( - this.plugin, - `${repositoryPath}\nThis does not seem to be an obsidian plugin, as there is no manifest.json file.`, - noticeTimeout - ); - console.error( - "BRAT: validateRepository", - repositoryPath, - getBetaManifest, - reportIssues - ); - } - return null; - } - // Test that the mainfest has some key elements, like ID and version - if (!("id" in manifestJson)) { - // this is a plugin with a manifest json, try to see if there is a beta version - if (reportIssues) - toastMessage( - this.plugin, - `${repositoryPath}\nThe plugin id attribute for the release is missing from the manifest file`, - noticeTimeout - ); - return null; - } - if (!("version" in manifestJson)) { - // this is a plugin with a manifest json, try to see if there is a beta version - if (reportIssues) - toastMessage( - this.plugin, - `${repositoryPath}\nThe version attribute for the release is missing from the manifest file`, - noticeTimeout - ); - return null; - } - return manifestJson; - } + /** + * Validates that a GitHub repository is plugin + * + * @param repositoryPath - GithubUser/RepositoryName (example: TfThacker/obsidian42-brat) + * @param getBetaManifest - test the beta version of the manifest, not at the root + * @param false - [false description] + * @param reportIssues - will display notices as it finds issues + * + * @returns the manifest file if found, or null if its incomplete + */ + async validateRepository( + repositoryPath: string, + getBetaManifest = false, + reportIssues = false, + ): Promise { + const noticeTimeout = 15; + const manifestJson = await grabManifestJsonFromRepository( + repositoryPath, + !getBetaManifest, + this.plugin.settings.debuggingMode, + this.plugin.settings.personalAccessToken, + ); + if (!manifestJson) { + // this is a plugin with a manifest json, try to see if there is a beta version + if (reportIssues) { + toastMessage( + this.plugin, + `${repositoryPath}\nThis does not seem to be an obsidian plugin, as there is no manifest.json file.`, + noticeTimeout, + ); + console.error( + "BRAT: validateRepository", + repositoryPath, + getBetaManifest, + reportIssues, + ); + } + return null; + } + // Test that the mainfest has some key elements, like ID and version + if (!("id" in manifestJson)) { + // this is a plugin with a manifest json, try to see if there is a beta version + if (reportIssues) + toastMessage( + this.plugin, + `${repositoryPath}\nThe plugin id attribute for the release is missing from the manifest file`, + noticeTimeout, + ); + return null; + } + if (!("version" in manifestJson)) { + // this is a plugin with a manifest json, try to see if there is a beta version + if (reportIssues) + toastMessage( + this.plugin, + `${repositoryPath}\nThe version attribute for the release is missing from the manifest file`, + noticeTimeout, + ); + return null; + } + return manifestJson; + } - /** - * Gets all the release files based on the version number in the manifest - * - * @param repositoryPath - path to the GitHub repository - * @param manifest - manifest file - * @param getManifest - grab the remote manifest file - * @param specifyVersion - grab the specified version if set - * - * @returns all relase files as strings based on the ReleaseFiles interaface - */ - async getAllReleaseFiles( - repositoryPath: string, - manifest: PluginManifest, - getManifest: boolean, - specifyVersion = "" - ): Promise { - const version = specifyVersion === "" ? manifest.version : specifyVersion; + /** + * Gets all the release files based on the version number in the manifest + * + * @param repositoryPath - path to the GitHub repository + * @param manifest - manifest file + * @param getManifest - grab the remote manifest file + * @param specifyVersion - grab the specified version if set + * + * @returns all relase files as strings based on the ReleaseFiles interaface + */ + async getAllReleaseFiles( + repositoryPath: string, + manifest: PluginManifest, + getManifest: boolean, + specifyVersion = "", + ): Promise { + const version = specifyVersion === "" ? manifest.version : specifyVersion; - // if we have version specified, we always want to get the remote manifest file. - const reallyGetManifestOrNot = getManifest || specifyVersion !== ""; + // if we have version specified, we always want to get the remote manifest file. + const reallyGetManifestOrNot = getManifest || specifyVersion !== ""; - console.log({ reallyGetManifestOrNot, version }); + console.log({ reallyGetManifestOrNot, version }); - return { - mainJs: await grabReleaseFileFromRepository( - repositoryPath, - version, - "main.js", - this.plugin.settings.debuggingMode, - this.plugin.settings.personalAccessToken - ), - manifest: reallyGetManifestOrNot - ? await grabReleaseFileFromRepository( - repositoryPath, - version, - "manifest.json", - this.plugin.settings.debuggingMode, - this.plugin.settings.personalAccessToken - ) - : "", - styles: await grabReleaseFileFromRepository( - repositoryPath, - version, - "styles.css", - this.plugin.settings.debuggingMode, - this.plugin.settings.personalAccessToken - ), - }; - } + return { + mainJs: await grabReleaseFileFromRepository( + repositoryPath, + version, + "main.js", + this.plugin.settings.debuggingMode, + this.plugin.settings.personalAccessToken, + ), + manifest: reallyGetManifestOrNot + ? await grabReleaseFileFromRepository( + repositoryPath, + version, + "manifest.json", + this.plugin.settings.debuggingMode, + this.plugin.settings.personalAccessToken, + ) + : "", + styles: await grabReleaseFileFromRepository( + repositoryPath, + version, + "styles.css", + this.plugin.settings.debuggingMode, + this.plugin.settings.personalAccessToken, + ), + }; + } - /** - * Writes the plugin release files to the local obsidian .plugins folder - * - * @param betaPluginId - the id of the plugin (not the repository path) - * @param relFiles - release file as strings, based on the ReleaseFiles interface - * - */ - async writeReleaseFilesToPluginFolder( - betaPluginId: string, - relFiles: ReleaseFiles - ): Promise { - const pluginTargetFolderPath = - normalizePath( - this.plugin.app.vault.configDir + "/plugins/" + betaPluginId - ) + "/"; - const { adapter } = this.plugin.app.vault; - if ( - !(await adapter.exists(pluginTargetFolderPath)) || - !(await adapter.exists(`${pluginTargetFolderPath}manifest.json`)) - ) { - // if plugin folder doesnt exist or manifest.json doesn't exist, create it and save the plugin files - await adapter.mkdir(pluginTargetFolderPath); - } - await adapter.write( - `${pluginTargetFolderPath}main.js`, - relFiles.mainJs ?? "" - ); - await adapter.write( - `${pluginTargetFolderPath}manifest.json`, - relFiles.manifest ?? "" - ); - if (relFiles.styles) - await adapter.write( - `${pluginTargetFolderPath}styles.css`, - relFiles.styles - ); - } + /** + * Writes the plugin release files to the local obsidian .plugins folder + * + * @param betaPluginId - the id of the plugin (not the repository path) + * @param relFiles - release file as strings, based on the ReleaseFiles interface + * + */ + async writeReleaseFilesToPluginFolder( + betaPluginId: string, + relFiles: ReleaseFiles, + ): Promise { + const pluginTargetFolderPath = `${normalizePath( + `${this.plugin.app.vault.configDir}/plugins/${betaPluginId}`, + )}/`; + const { adapter } = this.plugin.app.vault; + if ( + !(await adapter.exists(pluginTargetFolderPath)) || + !(await adapter.exists(`${pluginTargetFolderPath}manifest.json`)) + ) { + // if plugin folder doesnt exist or manifest.json doesn't exist, create it and save the plugin files + await adapter.mkdir(pluginTargetFolderPath); + } + await adapter.write( + `${pluginTargetFolderPath}main.js`, + relFiles.mainJs ?? "", + ); + await adapter.write( + `${pluginTargetFolderPath}manifest.json`, + relFiles.manifest ?? "", + ); + if (relFiles.styles) + await adapter.write( + `${pluginTargetFolderPath}styles.css`, + relFiles.styles, + ); + } - /** - * Primary function for adding a new beta plugin to Obsidian. - * Also this function is used for updating existing plugins. - * - * @param repositoryPath - path to GitHub repository formated as USERNAME/repository - * @param updatePluginFiles - true if this is just an update not an install - * @param seeIfUpdatedOnly - if true, and updatePluginFiles true, will just check for updates, but not do the update. will report to user that there is a new plugin - * @param reportIfNotUpdted - if true, report if an update has not succed - * @param specifyVersion - if not empty, need to install a specified version instead of the value in manifest-beta.json - * @param forceReinstall - if true, will force a reinstall of the plugin, even if it is already installed - * - * @returns true if succeeds - */ - async addPlugin( - repositoryPath: string, - updatePluginFiles = false, - seeIfUpdatedOnly = false, - reportIfNotUpdted = false, - specifyVersion = "", - forceReinstall = false, - enableAfterInstall = this.plugin.settings.enableAfterInstall - ): Promise { - if (this.plugin.settings.debuggingMode) - console.log( - "BRAT: addPlugin", - repositoryPath, - updatePluginFiles, - seeIfUpdatedOnly, - reportIfNotUpdted, - specifyVersion, - forceReinstall, - enableAfterInstall - ); + /** + * Primary function for adding a new beta plugin to Obsidian. + * Also this function is used for updating existing plugins. + * + * @param repositoryPath - path to GitHub repository formated as USERNAME/repository + * @param updatePluginFiles - true if this is just an update not an install + * @param seeIfUpdatedOnly - if true, and updatePluginFiles true, will just check for updates, but not do the update. will report to user that there is a new plugin + * @param reportIfNotUpdted - if true, report if an update has not succed + * @param specifyVersion - if not empty, need to install a specified version instead of the value in manifest-beta.json + * @param forceReinstall - if true, will force a reinstall of the plugin, even if it is already installed + * + * @returns true if succeeds + */ + async addPlugin( + repositoryPath: string, + updatePluginFiles = false, + seeIfUpdatedOnly = false, + reportIfNotUpdted = false, + specifyVersion = "", + forceReinstall = false, + enableAfterInstall = this.plugin.settings.enableAfterInstall, + ): Promise { + if (this.plugin.settings.debuggingMode) + console.log( + "BRAT: addPlugin", + repositoryPath, + updatePluginFiles, + seeIfUpdatedOnly, + reportIfNotUpdted, + specifyVersion, + forceReinstall, + enableAfterInstall, + ); - const noticeTimeout = 10; - // attempt to get manifest-beta.json - let primaryManifest = await this.validateRepository( - repositoryPath, - true, - false - ); - const usingBetaManifest: boolean = primaryManifest ? true : false; - // attempt to get manifest.json - if (!usingBetaManifest) - primaryManifest = await this.validateRepository( - repositoryPath, - false, - true - ); + const noticeTimeout = 10; + // attempt to get manifest-beta.json + let primaryManifest = await this.validateRepository( + repositoryPath, + true, + false, + ); + const usingBetaManifest: boolean = !!primaryManifest; + // attempt to get manifest.json + if (!usingBetaManifest) + primaryManifest = await this.validateRepository( + repositoryPath, + false, + true, + ); - if (primaryManifest === null) { - const msg = `${repositoryPath}\nA manifest.json or manifest-beta.json file does not exist in the root directory of the repository. This plugin cannot be installed.`; - await this.plugin.log(msg, true); - toastMessage(this.plugin, msg, noticeTimeout); - return false; - } + if (primaryManifest === null) { + const msg = `${repositoryPath}\nA manifest.json or manifest-beta.json file does not exist in the root directory of the repository. This plugin cannot be installed.`; + await this.plugin.log(msg, true); + toastMessage(this.plugin, msg, noticeTimeout); + return false; + } - if (!Object.hasOwn(primaryManifest, "version")) { - const msg = `${repositoryPath}\nThe manifest${ - usingBetaManifest ? "-beta" : "" - }.json file in the root directory of the repository does not have a version number in the file. This plugin cannot be installed.`; - await this.plugin.log(msg, true); - toastMessage(this.plugin, msg, noticeTimeout); - return false; - } + if (!Object.hasOwn(primaryManifest, "version")) { + const msg = `${repositoryPath}\nThe manifest${ + usingBetaManifest ? "-beta" : "" + }.json file in the root directory of the repository does not have a version number in the file. This plugin cannot be installed.`; + await this.plugin.log(msg, true); + toastMessage(this.plugin, msg, noticeTimeout); + return false; + } - // Check manifest minAppVersion and current version of Obisidan, don't load plugin if not compatible - if (!Object.hasOwn(primaryManifest, "minAppVersion")) { - if (!requireApiVersion(primaryManifest.minAppVersion)) { - const msg = - `Plugin: ${repositoryPath}\n\n` + - `The manifest${ - usingBetaManifest ? "-beta" : "" - }.json for this plugin indicates that the Obsidian ` + - `version of the app needs to be ${primaryManifest.minAppVersion}, ` + - `but this installation of Obsidian is ${apiVersion}. \n\nYou will need to update your ` + - `Obsidian to use this plugin or contact the plugin developer for more information.`; - await this.plugin.log(msg, true); - toastMessage(this.plugin, msg, 30); - return false; - } - } + // Check manifest minAppVersion and current version of Obisidan, don't load plugin if not compatible + if (!Object.hasOwn(primaryManifest, "minAppVersion")) { + if (!requireApiVersion(primaryManifest.minAppVersion)) { + const msg = `Plugin: ${repositoryPath}\n\nThe manifest${ + usingBetaManifest ? "-beta" : "" + }.json for this plugin indicates that the Obsidian version of the app needs to be ${primaryManifest.minAppVersion}, but this installation of Obsidian is ${apiVersion}. \n\nYou will need to update your Obsidian to use this plugin or contact the plugin developer for more information.`; + await this.plugin.log(msg, true); + toastMessage(this.plugin, msg, 30); + return false; + } + } - // now the user must be able to access the repo + // now the user must be able to access the repo - interface ErrnoType { - errno: number; - } + interface ErrnoType { + errno: number; + } - const getRelease = async () => { - const rFiles = await this.getAllReleaseFiles( - repositoryPath, - primaryManifest, - usingBetaManifest, - specifyVersion - ); + const getRelease = async () => { + const rFiles = await this.getAllReleaseFiles( + repositoryPath, + primaryManifest, + usingBetaManifest, + specifyVersion, + ); - console.log("rFiles", rFiles); - // if beta, use that manifest, or if there is no manifest in release, use the primaryManifest - if (usingBetaManifest || rFiles.manifest === "") - rFiles.manifest = JSON.stringify(primaryManifest); + console.log("rFiles", rFiles); + // if beta, use that manifest, or if there is no manifest in release, use the primaryManifest + if (usingBetaManifest || rFiles.manifest === "") + rFiles.manifest = JSON.stringify(primaryManifest); - if (this.plugin.settings.debuggingMode) - console.log("BRAT: rFiles.manifest", usingBetaManifest, rFiles); + if (this.plugin.settings.debuggingMode) + console.log("BRAT: rFiles.manifest", usingBetaManifest, rFiles); - if (rFiles.mainJs === null) { - const msg = `${repositoryPath}\nThe release is not complete and cannot be download. main.js is missing from the Release`; - await this.plugin.log(msg, true); - toastMessage(this.plugin, msg, noticeTimeout); - return null; - } - return rFiles; - }; + if (rFiles.mainJs === null) { + const msg = `${repositoryPath}\nThe release is not complete and cannot be download. main.js is missing from the Release`; + await this.plugin.log(msg, true); + toastMessage(this.plugin, msg, noticeTimeout); + return null; + } + return rFiles; + }; - if (!updatePluginFiles || forceReinstall) { - const releaseFiles = await getRelease(); - if (releaseFiles === null) return false; - await this.writeReleaseFilesToPluginFolder( - primaryManifest.id, - releaseFiles - ); - if (!forceReinstall) - addBetaPluginToList(this.plugin, repositoryPath, specifyVersion); - if (enableAfterInstall) { - const { plugins } = this.plugin.app; - const pluginTargetFolderPath = normalizePath( - `${plugins.getPluginFolder()}/${primaryManifest.id}` - ); - await plugins.loadManifest(pluginTargetFolderPath); - await plugins.enablePluginAndSave(primaryManifest.id); - } - await this.plugin.app.plugins.loadManifests(); - if (forceReinstall) { - // reload if enabled - await this.reloadPlugin(primaryManifest.id); - await this.plugin.log(`${repositoryPath} reinstalled`, true); - toastMessage( - this.plugin, - `${repositoryPath}\nPlugin has been reinstalled and reloaded.`, - noticeTimeout - ); - } else { - const versionText = - specifyVersion === "" ? "" : ` (version: ${specifyVersion})`; - let msg = `${repositoryPath}${versionText}\nThe plugin has been registered with BRAT.`; - if (!enableAfterInstall) { - msg += " You may still need to enable it the Community Plugin List."; - } - await this.plugin.log(msg, true); - toastMessage(this.plugin, msg, noticeTimeout); - } - } else { - // test if the plugin needs to be updated - // if a specified version is provided, then we shall skip the update - const pluginTargetFolderPath = - this.plugin.app.vault.configDir + - "/plugins/" + - primaryManifest.id + - "/"; - let localManifestContents = ""; - try { - localManifestContents = await this.plugin.app.vault.adapter.read( - pluginTargetFolderPath + "manifest.json" - ); - } catch (e) { - if ((e as ErrnoType).errno === -4058 || (e as ErrnoType).errno === -2) { - // file does not exist, try installing the plugin - await this.addPlugin( - repositoryPath, - false, - usingBetaManifest, - false, - specifyVersion - ); - // even though failed, return true since install will be attempted - return true; - } else - console.log( - "BRAT - Local Manifest Load", - primaryManifest.id, - JSON.stringify(e, null, 2) - ); - } + if (!updatePluginFiles || forceReinstall) { + const releaseFiles = await getRelease(); + if (releaseFiles === null) return false; + await this.writeReleaseFilesToPluginFolder( + primaryManifest.id, + releaseFiles, + ); + if (!forceReinstall) + addBetaPluginToList(this.plugin, repositoryPath, specifyVersion); + if (enableAfterInstall) { + const { plugins } = this.plugin.app; + const pluginTargetFolderPath = normalizePath( + `${plugins.getPluginFolder()}/${primaryManifest.id}`, + ); + await plugins.loadManifest(pluginTargetFolderPath); + await plugins.enablePluginAndSave(primaryManifest.id); + } + await this.plugin.app.plugins.loadManifests(); + if (forceReinstall) { + // reload if enabled + await this.reloadPlugin(primaryManifest.id); + await this.plugin.log(`${repositoryPath} reinstalled`, true); + toastMessage( + this.plugin, + `${repositoryPath}\nPlugin has been reinstalled and reloaded.`, + noticeTimeout, + ); + } else { + const versionText = + specifyVersion === "" ? "" : ` (version: ${specifyVersion})`; + let msg = `${repositoryPath}${versionText}\nThe plugin has been registered with BRAT.`; + if (!enableAfterInstall) { + msg += " You may still need to enable it the Community Plugin List."; + } + await this.plugin.log(msg, true); + toastMessage(this.plugin, msg, noticeTimeout); + } + } else { + // test if the plugin needs to be updated + // if a specified version is provided, then we shall skip the update + const pluginTargetFolderPath = `${this.plugin.app.vault.configDir}/plugins/${primaryManifest.id}/`; + let localManifestContents = ""; + try { + localManifestContents = await this.plugin.app.vault.adapter.read( + `${pluginTargetFolderPath}manifest.json`, + ); + } catch (e) { + if ((e as ErrnoType).errno === -4058 || (e as ErrnoType).errno === -2) { + // file does not exist, try installing the plugin + await this.addPlugin( + repositoryPath, + false, + usingBetaManifest, + false, + specifyVersion, + ); + // even though failed, return true since install will be attempted + return true; + } + console.log( + "BRAT - Local Manifest Load", + primaryManifest.id, + JSON.stringify(e, null, 2), + ); + } - if ( - specifyVersion !== "" || - this.plugin.settings.pluginSubListFrozenVersion - .map((x) => x.repo) - .includes(repositoryPath) - ) { - // skip the frozen version plugin - toastMessage( - this.plugin, - `The version of ${repositoryPath} is frozen, not updating.`, - 3 - ); - return false; - } + if ( + specifyVersion !== "" || + this.plugin.settings.pluginSubListFrozenVersion + .map((x) => x.repo) + .includes(repositoryPath) + ) { + // skip the frozen version plugin + toastMessage( + this.plugin, + `The version of ${repositoryPath} is frozen, not updating.`, + 3, + ); + return false; + } - const localManifestJson = (await JSON.parse( - localManifestContents - )) as PluginManifest; - if (localManifestJson.version !== primaryManifest.version) { - // manifest files are not the same, do an update - const releaseFiles = await getRelease(); - if (releaseFiles === null) return false; + const localManifestJson = (await JSON.parse( + localManifestContents, + )) as PluginManifest; + if (localManifestJson.version !== primaryManifest.version) { + // manifest files are not the same, do an update + const releaseFiles = await getRelease(); + if (releaseFiles === null) return false; - if (seeIfUpdatedOnly) { - // dont update, just report it - const msg = `There is an update available for ${primaryManifest.id} from version ${localManifestJson.version} to ${primaryManifest.version}. `; - await this.plugin.log( - `${msg}[Release Info](https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version})`, - true - ); - toastMessage(this.plugin, msg, 30, () => { - if (primaryManifest) { - window.open( - `https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version}` - ); - } - }); - } else { - await this.writeReleaseFilesToPluginFolder( - primaryManifest.id, - releaseFiles - ); - await this.plugin.app.plugins.loadManifests(); - await this.reloadPlugin(primaryManifest.id); - const msg = `${primaryManifest.id}\nPlugin has been updated from version ${localManifestJson.version} to ${primaryManifest.version}. `; - await this.plugin.log( - `${msg}[Release Info](https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version})`, - true - ); - toastMessage(this.plugin, msg, 30, () => { - if (primaryManifest) { - window.open( - `https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version}` - ); - } - }); - } - } else if (reportIfNotUpdted) - toastMessage( - this.plugin, - `No update available for ${repositoryPath}`, - 3 - ); - } - return true; - } + if (seeIfUpdatedOnly) { + // dont update, just report it + const msg = `There is an update available for ${primaryManifest.id} from version ${localManifestJson.version} to ${primaryManifest.version}. `; + await this.plugin.log( + `${msg}[Release Info](https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version})`, + true, + ); + toastMessage(this.plugin, msg, 30, () => { + if (primaryManifest) { + window.open( + `https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version}`, + ); + } + }); + } else { + await this.writeReleaseFilesToPluginFolder( + primaryManifest.id, + releaseFiles, + ); + // @ts-ignore + await this.plugin.app.plugins.loadManifests(); + await this.reloadPlugin(primaryManifest.id); + const msg = `${primaryManifest.id}\nPlugin has been updated from version ${localManifestJson.version} to ${primaryManifest.version}. `; + await this.plugin.log( + `${msg}[Release Info](https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version})`, + true, + ); + toastMessage(this.plugin, msg, 30, () => { + if (primaryManifest) { + window.open( + `https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version}`, + ); + } + }); + } + } else if (reportIfNotUpdted) + toastMessage( + this.plugin, + `No update available for ${repositoryPath}`, + 3, + ); + } + return true; + } - /** - * reloads a plugin (assuming it has been enabled by user) - * pjeby, Thanks Bro https://github.com/pjeby/hot-reload/blob/master/main.js - * - * @param pluginName - name of plugin - * - */ - async reloadPlugin(pluginName: string): Promise { - const { plugins } = this.plugin.app; - try { - await plugins.disablePlugin(pluginName); - await plugins.enablePlugin(pluginName); - } catch (e) { - if (this.plugin.settings.debuggingMode) console.log("reload plugin", e); - } - } + /** + * reloads a plugin (assuming it has been enabled by user) + * pjeby, Thanks Bro https://github.com/pjeby/hot-reload/blob/master/main.js + * + * @param pluginName - name of plugin + * + */ + async reloadPlugin(pluginName: string): Promise { + // @ts-ignore + const { plugins } = this.plugin.app; + try { + await plugins.disablePlugin(pluginName); + await plugins.enablePlugin(pluginName); + } catch (e) { + if (this.plugin.settings.debuggingMode) console.log("reload plugin", e); + } + } - /** - * updates a beta plugin - * - * @param repositoryPath - repository path on GitHub - * @param onlyCheckDontUpdate - only looks for update - * - */ - async updatePlugin( - repositoryPath: string, - onlyCheckDontUpdate = false, - reportIfNotUpdted = false, - forceReinstall = false - ): Promise { - const result = await this.addPlugin( - repositoryPath, - true, - onlyCheckDontUpdate, - reportIfNotUpdted, - "", - forceReinstall - ); - if (!result && !onlyCheckDontUpdate) - toastMessage(this.plugin, `${repositoryPath}\nUpdate of plugin failed.`); - return result; - } + /** + * updates a beta plugin + * + * @param repositoryPath - repository path on GitHub + * @param onlyCheckDontUpdate - only looks for update + * + */ + async updatePlugin( + repositoryPath: string, + onlyCheckDontUpdate = false, + reportIfNotUpdted = false, + forceReinstall = false, + ): Promise { + const result = await this.addPlugin( + repositoryPath, + true, + onlyCheckDontUpdate, + reportIfNotUpdted, + "", + forceReinstall, + ); + if (!result && !onlyCheckDontUpdate) + toastMessage(this.plugin, `${repositoryPath}\nUpdate of plugin failed.`); + return result; + } - /** - * walks through the list of plugins without frozen version and performs an update - * - * @param showInfo - should this with a started/completed message - useful when ran from CP - * - */ - async checkForPluginUpdatesAndInstallUpdates( - showInfo = false, - onlyCheckDontUpdate = false - ): Promise { - if (!(await isConnectedToInternet())) { - console.log("BRAT: No internet detected."); - return; - } - let newNotice: Notice | undefined; - const msg1 = "Checking for plugin updates STARTED"; - await this.plugin.log(msg1, true); - if (showInfo && this.plugin.settings.notificationsEnabled) - newNotice = new Notice(`BRAT\n${msg1}`, 30000); - const pluginSubListFrozenVersionNames = new Set( - this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo) - ); - for (const bp of this.plugin.settings.pluginList) { - if (pluginSubListFrozenVersionNames.has(bp)) { - continue; - } - await this.updatePlugin(bp, onlyCheckDontUpdate); - } - const msg2 = "Checking for plugin updates COMPLETED"; - await this.plugin.log(msg2, true); - if (showInfo) { - if (newNotice) { - newNotice.hide(); - } - toastMessage(this.plugin, msg2, 10); - } - } + /** + * walks through the list of plugins without frozen version and performs an update + * + * @param showInfo - should this with a started/completed message - useful when ran from CP + * + */ + async checkForPluginUpdatesAndInstallUpdates( + showInfo = false, + onlyCheckDontUpdate = false, + ): Promise { + if (!(await isConnectedToInternet())) { + console.log("BRAT: No internet detected."); + return; + } + let newNotice: Notice | undefined; + const msg1 = "Checking for plugin updates STARTED"; + await this.plugin.log(msg1, true); + if (showInfo && this.plugin.settings.notificationsEnabled) + newNotice = new Notice(`BRAT\n${msg1}`, 30000); + const pluginSubListFrozenVersionNames = new Set( + this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo), + ); + for (const bp of this.plugin.settings.pluginList) { + if (pluginSubListFrozenVersionNames.has(bp)) { + continue; + } + await this.updatePlugin(bp, onlyCheckDontUpdate); + } + const msg2 = "Checking for plugin updates COMPLETED"; + await this.plugin.log(msg2, true); + if (showInfo) { + if (newNotice) { + newNotice.hide(); + } + toastMessage(this.plugin, msg2, 10); + } + } - /** - * Removes the beta plugin from the list of beta plugins (does not delete them from disk) - * - * @param betaPluginID - repository path - * - */ - deletePlugin(repositoryPath: string): void { - const msg = `Removed ${repositoryPath} from BRAT plugin list`; - void this.plugin.log(msg, true); - this.plugin.settings.pluginList = this.plugin.settings.pluginList.filter( - (b) => b !== repositoryPath - ); - this.plugin.settings.pluginSubListFrozenVersion = - this.plugin.settings.pluginSubListFrozenVersion.filter( - (b) => b.repo !== repositoryPath - ); - void this.plugin.saveSettings(); - } + /** + * Removes the beta plugin from the list of beta plugins (does not delete them from disk) + * + * @param betaPluginID - repository path + * + */ + deletePlugin(repositoryPath: string): void { + const msg = `Removed ${repositoryPath} from BRAT plugin list`; + void this.plugin.log(msg, true); + this.plugin.settings.pluginList = this.plugin.settings.pluginList.filter( + (b) => b !== repositoryPath, + ); + this.plugin.settings.pluginSubListFrozenVersion = + this.plugin.settings.pluginSubListFrozenVersion.filter( + (b) => b.repo !== repositoryPath, + ); + void this.plugin.saveSettings(); + } - /** - * Returns a list of plugins that are currently enabled or currently disabled - * - * @param enabled - true for enabled plugins, false for disabled plutings - * - * @returns manifests of plugins - */ - getEnabledDisabledPlugins(enabled: boolean): PluginManifest[] { - const pl = this.plugin.app.plugins; - const manifests: PluginManifest[] = Object.values(pl.manifests); - const enabledPlugins: PluginManifest[] = Object.values(pl.plugins).map( - (p) => p.manifest - ); - return enabled - ? manifests.filter((manifest) => - enabledPlugins.find((pluginName) => manifest.id === pluginName.id) - ) - : manifests.filter( - (manifest) => - !enabledPlugins.find((pluginName) => manifest.id === pluginName.id) - ); - } + /** + * Returns a list of plugins that are currently enabled or currently disabled + * + * @param enabled - true for enabled plugins, false for disabled plutings + * + * @returns manifests of plugins + */ + getEnabledDisabledPlugins(enabled: boolean): PluginManifest[] { + // @ts-ignore + const pl = this.plugin.app.plugins; + const manifests: PluginManifest[] = Object.values(pl.manifests); + const enabledPlugins: PluginManifest[] = Object.values(pl.plugins).map( + (p) => p.manifest, + ); + return enabled + ? manifests.filter((manifest) => + enabledPlugins.find((pluginName) => manifest.id === pluginName.id), + ) + : manifests.filter( + (manifest) => + !enabledPlugins.find((pluginName) => manifest.id === pluginName.id), + ); + } } diff --git a/src/features/githubUtils.ts b/src/features/githubUtils.ts index 78a2dd8..d99eea8 100644 --- a/src/features/githubUtils.ts +++ b/src/features/githubUtils.ts @@ -4,26 +4,26 @@ import { request } from "obsidian"; const GITHUB_RAW_USERCONTENT_PATH = "https://raw.githubusercontent.com/"; const isPrivateRepo = async ( - repository: string, - debugLogging = true, - personalAccessToken = "" + repository: string, + debugLogging = true, + personalAccessToken = "", ): Promise => { - const URL = `https://api.github.com/repos/${repository}`; - try { - const response = await request({ - url: URL, - headers: personalAccessToken - ? { - Authorization: `Token ${personalAccessToken}`, - } - : {}, - }); - const data = await JSON.parse(response); - return data.private; - } catch (e) { - if (debugLogging) console.log("error in isPrivateRepo", URL, e); - return false; - } + const URL = `https://api.github.com/repos/${repository}`; + try { + const response = await request({ + url: URL, + headers: personalAccessToken + ? { + Authorization: `Token ${personalAccessToken}`, + } + : {}, + }); + const data = await JSON.parse(response); + return data.private; + } catch (e) { + if (debugLogging) console.log("error in isPrivateRepo", URL, e); + return false; + } }; /** @@ -36,86 +36,85 @@ const isPrivateRepo = async ( * @returns contents of file as string from the repository's release */ export const grabReleaseFileFromRepository = async ( - repository: string, - version: string, - fileName: string, - debugLogging = true, - personalAccessToken = "" + repository: string, + version: string, + fileName: string, + debugLogging = true, + personalAccessToken = "", ): Promise => { - try { - // check if the repo is a private repo - const isPrivate = await isPrivateRepo( - repository, - debugLogging, - personalAccessToken - ); + try { + // check if the repo is a private repo + const isPrivate = await isPrivateRepo( + repository, + debugLogging, + personalAccessToken, + ); - if (isPrivate) { - type Release = { - url: string; - tag_name: string; - assets: { - name: string; - url: string; - }[]; - }; + if (isPrivate) { + type Release = { + url: string; + tag_name: string; + assets: { + name: string; + url: string; + }[]; + }; - // get the asset id - // fetch https://api.github.com/repos/{repos}/releases , parse the response - // this will return an array of releases, find the release with the version number by tag_name - // in the release object, get assets and find the correct asset by name - // then fetch the url + // get the asset id + // fetch https://api.github.com/repos/{repos}/releases , parse the response + // this will return an array of releases, find the release with the version number by tag_name + // in the release object, get assets and find the correct asset by name + // then fetch the url - const URL = `https://api.github.com/repos/${repository}/releases`; - const response = await request({ - url: URL, - headers: { - Authorization: `Token ${personalAccessToken}`, - }, - }); - const data = await JSON.parse(response); - const release = data.find( - (release: Release) => release.tag_name === version - ); - if (!release) { - return null; - } - const asset = release.assets.find( - (asset: { name: string }) => asset.name === fileName - ); - if (!asset) { - return null; - } - const download = await request({ - url: asset.url, - headers: { - Authorization: `Token ${personalAccessToken}`, - Accept: "application/octet-stream", - }, - }); - return download === "Not Found" || download === `{"error":"Not Found"}` - ? null - : download; - } else { - const URL = `https://github.com/${repository}/releases/download/${version}/${fileName}`; - const download = await request({ - url: URL, - headers: personalAccessToken - ? { - Authorization: `Token ${personalAccessToken}`, - } - : {}, - }); + const URL = `https://api.github.com/repos/${repository}/releases`; + const response = await request({ + url: URL, + headers: { + Authorization: `Token ${personalAccessToken}`, + }, + }); + const data = await JSON.parse(response); + const release = data.find( + (release: Release) => release.tag_name === version, + ); + if (!release) { + return null; + } + const asset = release.assets.find( + (asset: { name: string }) => asset.name === fileName, + ); + if (!asset) { + return null; + } + const download = await request({ + url: asset.url, + headers: { + Authorization: `Token ${personalAccessToken}`, + Accept: "application/octet-stream", + }, + }); + return download === "Not Found" || download === `{"error":"Not Found"}` + ? null + : download; + } + const URL = `https://github.com/${repository}/releases/download/${version}/${fileName}`; + const download = await request({ + url: URL, + headers: personalAccessToken + ? { + Authorization: `Token ${personalAccessToken}`, + } + : {}, + }); - return download === "Not Found" || download === `{"error":"Not Found"}` - ? null - : download; - } - } catch (error) { - if (debugLogging) - console.log("error in grabReleaseFileFromRepository", URL, error); - return null; - } + return download === "Not Found" || download === `{"error":"Not Found"}` + ? null + : download; + } catch (error) { + if (debugLogging) + console.log("error in grabReleaseFileFromRepository", URL, error); + return null; + } }; /** @@ -127,212 +126,211 @@ export const grabReleaseFileFromRepository = async ( * @returns returns manifest file for a plugin */ export const grabManifestJsonFromRepository = async ( - repositoryPath: string, - rootManifest = true, - debugLogging = true, - personalAccessToken = "" + repositoryPath: string, + rootManifest = true, + debugLogging = true, + personalAccessToken = "", ): Promise => { - const manifestJsonPath = - GITHUB_RAW_USERCONTENT_PATH + - repositoryPath + - (rootManifest ? "/HEAD/manifest.json" : "/HEAD/manifest-beta.json"); - if (debugLogging) - console.log( - "grabManifestJsonFromRepository manifestJsonPath", - manifestJsonPath - ); + const manifestJsonPath = + GITHUB_RAW_USERCONTENT_PATH + + repositoryPath + + (rootManifest ? "/HEAD/manifest.json" : "/HEAD/manifest-beta.json"); + if (debugLogging) + console.log( + "grabManifestJsonFromRepository manifestJsonPath", + manifestJsonPath, + ); - // Function to check if the token is valid - const isTokenValid = async (token: string): Promise => { - try { - await request({ - url: "https://api.github.com/user", - method: "GET", - headers: { - Authorization: `token ${token}`, - "User-Agent": "request", - accept: "application/vnd.github.v3+json", - }, - }); - return true; - } catch (error) { - if (debugLogging) console.log("Token validation error:", error); - return false; - } - }; + // Function to check if the token is valid + const isTokenValid = async (token: string): Promise => { + try { + await request({ + url: "https://api.github.com/user", + method: "GET", + headers: { + Authorization: `token ${token}`, + "User-Agent": "request", + accept: "application/vnd.github.v3+json", + }, + }); + return true; + } catch (error) { + if (debugLogging) console.log("Token validation error:", error); + return false; + } + }; - // Check if the token is valid - let tokenValid = false; - if (personalAccessToken) { - tokenValid = await isTokenValid(personalAccessToken); - if (debugLogging) console.log("Token valid:", tokenValid); - } + // Check if the token is valid + let tokenValid = false; + if (personalAccessToken) { + tokenValid = await isTokenValid(personalAccessToken); + if (debugLogging) console.log("Token valid:", tokenValid); + } - try { - const response: string = await request({ - url: manifestJsonPath, - headers: tokenValid - ? { - Authorization: `Token ${personalAccessToken}`, - } - : {}, - }); - if (debugLogging) - console.log("grabManifestJsonFromRepository response", response); - return response === "404: Not Found" - ? null - : ((await JSON.parse(response)) as PluginManifest); - } catch (error) { - if (error !== "Error: Request failed, status 404" && debugLogging) { - // normal error, ignore - console.log( - `error in grabManifestJsonFromRepository for ${manifestJsonPath}`, - error - ); - } - return null; - } + try { + const response: string = await request({ + url: manifestJsonPath, + headers: tokenValid + ? { + Authorization: `Token ${personalAccessToken}`, + } + : {}, + }); + if (debugLogging) + console.log("grabManifestJsonFromRepository response", response); + return response === "404: Not Found" + ? null + : ((await JSON.parse(response)) as PluginManifest); + } catch (error) { + if (error !== "Error: Request failed, status 404" && debugLogging) { + // normal error, ignore + console.log( + `error in grabManifestJsonFromRepository for ${manifestJsonPath}`, + error, + ); + } + return null; + } }; export interface CommunityPlugin { - id: string; - name: string; - author: string; - description: string; - repo: string; + id: string; + name: string; + author: string; + description: string; + repo: string; } export const grabCommmunityPluginList = async ( - debugLogging = true + debugLogging = true, ): Promise => { - const pluginListUrl = - "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-plugins.json"; - try { - const response = await request({ url: pluginListUrl }); - return response === "404: Not Found" - ? null - : ((await JSON.parse(response)) as CommunityPlugin[]); - } catch (error) { - if (debugLogging) console.log("error in grabCommmunityPluginList", error); - return null; - } + const pluginListUrl = + "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-plugins.json"; + try { + const response = await request({ url: pluginListUrl }); + return response === "404: Not Found" + ? null + : ((await JSON.parse(response)) as CommunityPlugin[]); + } catch (error) { + if (debugLogging) console.log("error in grabCommmunityPluginList", error); + return null; + } }; export interface CommunityTheme { - name: string; - author: string; - repo: string; + name: string; + author: string; + repo: string; } export const grabCommmunityThemesList = async ( - debugLogging = true + debugLogging = true, ): Promise => { - const themesUrl = - "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-css-themes.json"; - try { - const response = await request({ url: themesUrl }); - return response === "404: Not Found" - ? null - : ((await JSON.parse(response)) as CommunityTheme[]); - } catch (error) { - if (debugLogging) console.log("error in grabCommmunityThemesList", error); - return null; - } + const themesUrl = + "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-css-themes.json"; + try { + const response = await request({ url: themesUrl }); + return response === "404: Not Found" + ? null + : ((await JSON.parse(response)) as CommunityTheme[]); + } catch (error) { + if (debugLogging) console.log("error in grabCommmunityThemesList", error); + return null; + } }; export const grabCommmunityThemeCssFile = async ( - repositoryPath: string, - betaVersion = false, - debugLogging: boolean + repositoryPath: string, + betaVersion = false, + debugLogging = false, ): Promise => { - const themesUrl = `https://raw.githubusercontent.com/${repositoryPath}/HEAD/theme${ - betaVersion ? "-beta" : "" - }.css`; - try { - const response = await request({ url: themesUrl }); - return response === "404: Not Found" ? null : response; - } catch (error) { - if (debugLogging) console.log("error in grabCommmunityThemeCssFile", error); - return null; - } + const themesUrl = `https://raw.githubusercontent.com/${repositoryPath}/HEAD/theme${ + betaVersion ? "-beta" : "" + }.css`; + try { + const response = await request({ url: themesUrl }); + return response === "404: Not Found" ? null : response; + } catch (error) { + if (debugLogging) console.log("error in grabCommmunityThemeCssFile", error); + return null; + } }; export const grabCommmunityThemeManifestFile = async ( - repositoryPath: string, - debugLogging = true + repositoryPath: string, + debugLogging = true, ): Promise => { - const themesUrl = `https://raw.githubusercontent.com/${repositoryPath}/HEAD/manifest.json`; - try { - const response = await request({ url: themesUrl }); - return response === "404: Not Found" ? null : response; - } catch (error) { - if (debugLogging) - console.log("error in grabCommmunityThemeManifestFile", error); - return null; - } + const themesUrl = `https://raw.githubusercontent.com/${repositoryPath}/HEAD/manifest.json`; + try { + const response = await request({ url: themesUrl }); + return response === "404: Not Found" ? null : response; + } catch (error) { + if (debugLogging) + console.log("error in grabCommmunityThemeManifestFile", error); + return null; + } }; const checksum = (str: string): number => { - let sum = 0; - for (let i = 0; i < str.length; i++) { - sum += str.charCodeAt(i); - } - return sum; + let sum = 0; + for (let i = 0; i < str.length; i++) { + sum += str.charCodeAt(i); + } + return sum; }; export const checksumForString = (str: string): string => { - return checksum(str).toString(); + return checksum(str).toString(); }; export const grabChecksumOfThemeCssFile = async ( - repositoryPath: string, - betaVersion: boolean, - debugLogging: boolean + repositoryPath: string, + betaVersion: boolean, + debugLogging: boolean, ): Promise => { - const themeCss = await grabCommmunityThemeCssFile( - repositoryPath, - betaVersion, - debugLogging - ); - return themeCss ? checksumForString(themeCss) : "0"; + const themeCss = await grabCommmunityThemeCssFile( + repositoryPath, + betaVersion, + debugLogging, + ); + return themeCss ? checksumForString(themeCss) : "0"; }; interface CommitInfo { - commit: { - committer?: { - date?: string; - }; - }; + commit: { + committer?: { + date?: string; + }; + }; } export const grabLastCommitInfoForFile = async ( - repositoryPath: string, - path: string, - debugLogging = true + repositoryPath: string, + path: string, + debugLogging = true, ): Promise => { - const url = `https://api.github.com/repos/${repositoryPath}/commits?path=${path}&page=1&per_page=1`; - try { - const response = await request({ url: url }); - return response === "404: Not Found" - ? null - : (JSON.parse(response) as CommitInfo[]); - } catch (error) { - if (debugLogging) console.log("error in grabLastCommitInfoForAFile", error); - return null; - } + const url = `https://api.github.com/repos/${repositoryPath}/commits?path=${path}&page=1&per_page=1`; + try { + const response = await request({ url: url }); + return response === "404: Not Found" + ? null + : (JSON.parse(response) as CommitInfo[]); + } catch (error) { + if (debugLogging) console.log("error in grabLastCommitInfoForAFile", error); + return null; + } }; export const grabLastCommitDateForFile = async ( - repositoryPath: string, - path: string + repositoryPath: string, + path: string, ): Promise => { - const test: CommitInfo[] | null = await grabLastCommitInfoForFile( - repositoryPath, - path - ); - if (test && test.length > 0 && test[0].commit.committer?.date) { - return test[0].commit.committer.date; - } else { - return ""; - } + const test: CommitInfo[] | null = await grabLastCommitInfoForFile( + repositoryPath, + path, + ); + if (test && test.length > 0 && test[0].commit.committer?.date) { + return test[0].commit.committer.date; + } + return ""; }; diff --git a/src/features/themes.ts b/src/features/themes.ts index 7a3e8c5..dbecc5c 100644 --- a/src/features/themes.ts +++ b/src/features/themes.ts @@ -1,18 +1,18 @@ -import type ThePlugin from "../main"; -import { normalizePath, Notice } from "obsidian"; +import { Notice, normalizePath } from "obsidian"; +import type { ThemeManifest } from "obsidian-typings"; +import type BratPlugin from "../main"; import { - addBetaThemeToList, - updateBetaThemeLastUpdateChecksum, + addBetaThemeToList, + updateBetaThemeLastUpdateChecksum, } from "../settings"; +import { isConnectedToInternet } from "../utils/internetconnection"; +import { toastMessage } from "../utils/notifications"; import { - checksumForString, - grabChecksumOfThemeCssFile, - grabCommmunityThemeCssFile, - grabCommmunityThemeManifestFile, + checksumForString, + grabChecksumOfThemeCssFile, + grabCommmunityThemeCssFile, + grabCommmunityThemeManifestFile, } from "./githubUtils"; -import { toastMessage } from "../utils/notifications"; -import { isConnectedToInternet } from "../utils/internetconnection"; -import type { ThemeManifest } from "obsidian-typings"; /** * Installs or updates a theme @@ -24,89 +24,89 @@ import type { ThemeManifest } from "obsidian-typings"; * @returns true for succcess */ export const themeSave = async ( - plugin: ThePlugin, - cssGithubRepository: string, - newInstall: boolean + plugin: BratPlugin, + cssGithubRepository: string, + newInstall: boolean, ): Promise => { - // test for themes-beta.css - let themeCss = await grabCommmunityThemeCssFile( - cssGithubRepository, - true, - plugin.settings.debuggingMode - ); - // grabe themes.css if no beta - if (!themeCss) - themeCss = await grabCommmunityThemeCssFile( - cssGithubRepository, - false, - plugin.settings.debuggingMode - ); + // test for themes-beta.css + let themeCss = await grabCommmunityThemeCssFile( + cssGithubRepository, + true, + plugin.settings.debuggingMode, + ); + // grabe themes.css if no beta + if (!themeCss) + themeCss = await grabCommmunityThemeCssFile( + cssGithubRepository, + false, + plugin.settings.debuggingMode, + ); - if (!themeCss) { - toastMessage( - plugin, - "There is no theme.css or theme-beta.css file in the root path of this repository, so there is no theme to install." - ); - return false; - } + if (!themeCss) { + toastMessage( + plugin, + "There is no theme.css or theme-beta.css file in the root path of this repository, so there is no theme to install.", + ); + return false; + } - const themeManifest = await grabCommmunityThemeManifestFile( - cssGithubRepository, - plugin.settings.debuggingMode - ); - if (!themeManifest) { - toastMessage( - plugin, - "There is no manifest.json file in the root path of this repository, so theme cannot be installed." - ); - return false; - } + const themeManifest = await grabCommmunityThemeManifestFile( + cssGithubRepository, + plugin.settings.debuggingMode, + ); + if (!themeManifest) { + toastMessage( + plugin, + "There is no manifest.json file in the root path of this repository, so theme cannot be installed.", + ); + return false; + } - const manifestInfo = (await JSON.parse(themeManifest)) as ThemeManifest; + const manifestInfo = (await JSON.parse(themeManifest)) as ThemeManifest; - const themeTargetFolderPath = normalizePath( - themesRootPath(plugin) + manifestInfo.name - ); + const themeTargetFolderPath = normalizePath( + themesRootPath(plugin) + manifestInfo.name, + ); - const { adapter } = plugin.app.vault; - if (!(await adapter.exists(themeTargetFolderPath))) - await adapter.mkdir(themeTargetFolderPath); + const { adapter } = plugin.app.vault; + if (!(await adapter.exists(themeTargetFolderPath))) + await adapter.mkdir(themeTargetFolderPath); - await adapter.write( - normalizePath(`${themeTargetFolderPath}/theme.css`), - themeCss - ); - await adapter.write( - normalizePath(`${themeTargetFolderPath}/manifest.json`), - themeManifest - ); + await adapter.write( + normalizePath(`${themeTargetFolderPath}/theme.css`), + themeCss, + ); + await adapter.write( + normalizePath(`${themeTargetFolderPath}/manifest.json`), + themeManifest, + ); - updateBetaThemeLastUpdateChecksum( - plugin, - cssGithubRepository, - checksumForString(themeCss) - ); + updateBetaThemeLastUpdateChecksum( + plugin, + cssGithubRepository, + checksumForString(themeCss), + ); - let msg = ""; + let msg = ""; - if (newInstall) { - addBetaThemeToList(plugin, cssGithubRepository, themeCss); - msg = `${manifestInfo.name} theme installed from ${cssGithubRepository}. `; - setTimeout(() => { - plugin.app.customCss.setTheme(manifestInfo.name); - }, 500); - } else { - msg = `${manifestInfo.name} theme updated from ${cssGithubRepository}.`; - } + if (newInstall) { + addBetaThemeToList(plugin, cssGithubRepository, themeCss); + msg = `${manifestInfo.name} theme installed from ${cssGithubRepository}. `; + setTimeout(() => { + plugin.app.customCss.setTheme(manifestInfo.name); + }, 500); + } else { + msg = `${manifestInfo.name} theme updated from ${cssGithubRepository}.`; + } - void plugin.log( - `${msg}[Theme Info](https://github.com/${cssGithubRepository})`, - false - ); - toastMessage(plugin, msg, 20, (): void => { - window.open(`https://github.com/${cssGithubRepository}`); - }); - return true; + void plugin.log( + `${msg}[Theme Info](https://github.com/${cssGithubRepository})`, + false, + ); + toastMessage(plugin, msg, 20, (): void => { + window.open(`https://github.com/${cssGithubRepository}`); + }); + return true; }; /** @@ -117,44 +117,44 @@ export const themeSave = async ( * */ export const themesCheckAndUpdates = async ( - plugin: ThePlugin, - showInfo: boolean + plugin: BratPlugin, + showInfo: boolean, ): Promise => { - if (!(await isConnectedToInternet())) { - console.log("BRAT: No internet detected."); - return; - } - let newNotice: Notice | undefined; - const msg1 = "Checking for beta theme updates STARTED"; - await plugin.log(msg1, true); - if (showInfo && plugin.settings.notificationsEnabled) - newNotice = new Notice(`BRAT\n${msg1}`, 30000); - for (const t of plugin.settings.themesList) { - // first test to see if theme-beta.css exists - let lastUpdateOnline = await grabChecksumOfThemeCssFile( - t.repo, - true, - plugin.settings.debuggingMode - ); - // if theme-beta.css does NOT exist, try to get theme.css - if (lastUpdateOnline === "0") - lastUpdateOnline = await grabChecksumOfThemeCssFile( - t.repo, - false, - plugin.settings.debuggingMode - ); - console.log("BRAT: lastUpdateOnline", lastUpdateOnline); - if (lastUpdateOnline !== t.lastUpdate) - await themeSave(plugin, t.repo, false); - } - const msg2 = "Checking for beta theme updates COMPLETED"; - (async (): Promise => { - await plugin.log(msg2, true); - })(); - if (showInfo) { - if (plugin.settings.notificationsEnabled && newNotice) newNotice.hide(); - toastMessage(plugin, msg2); - } + if (!(await isConnectedToInternet())) { + console.log("BRAT: No internet detected."); + return; + } + let newNotice: Notice | undefined; + const msg1 = "Checking for beta theme updates STARTED"; + await plugin.log(msg1, true); + if (showInfo && plugin.settings.notificationsEnabled) + newNotice = new Notice(`BRAT\n${msg1}`, 30000); + for (const t of plugin.settings.themesList) { + // first test to see if theme-beta.css exists + let lastUpdateOnline = await grabChecksumOfThemeCssFile( + t.repo, + true, + plugin.settings.debuggingMode, + ); + // if theme-beta.css does NOT exist, try to get theme.css + if (lastUpdateOnline === "0") + lastUpdateOnline = await grabChecksumOfThemeCssFile( + t.repo, + false, + plugin.settings.debuggingMode, + ); + console.log("BRAT: lastUpdateOnline", lastUpdateOnline); + if (lastUpdateOnline !== t.lastUpdate) + await themeSave(plugin, t.repo, false); + } + const msg2 = "Checking for beta theme updates COMPLETED"; + (async (): Promise => { + await plugin.log(msg2, true); + })(); + if (showInfo) { + if (plugin.settings.notificationsEnabled && newNotice) newNotice.hide(); + toastMessage(plugin, msg2); + } }; /** @@ -165,16 +165,16 @@ export const themesCheckAndUpdates = async ( * */ export const themeDelete = ( - plugin: ThePlugin, - cssGithubRepository: string + plugin: BratPlugin, + cssGithubRepository: string, ): void => { - plugin.settings.themesList = plugin.settings.themesList.filter( - (t) => t.repo !== cssGithubRepository - ); - void plugin.saveSettings(); - const msg = `Removed ${cssGithubRepository} from BRAT themes list and will no longer be updated. However, the theme files still exist in the vault. To remove them, go into Settings > Appearance and remove the theme.`; - void plugin.log(msg, true); - toastMessage(plugin, msg); + plugin.settings.themesList = plugin.settings.themesList.filter( + (t) => t.repo !== cssGithubRepository, + ); + void plugin.saveSettings(); + const msg = `Removed ${cssGithubRepository} from BRAT themes list and will no longer be updated. However, the theme files still exist in the vault. To remove them, go into Settings > Appearance and remove the theme.`; + void plugin.log(msg, true); + toastMessage(plugin, msg); }; /** @@ -184,6 +184,6 @@ export const themeDelete = ( * * @returns path to themes folder */ -export const themesRootPath = (plugin: ThePlugin): string => { - return normalizePath(plugin.app.vault.configDir + "/themes") + "/"; +export const themesRootPath = (plugin: BratPlugin): string => { + return `${normalizePath(`${plugin.app.vault.configDir}/themes`)}/`; }; diff --git a/src/main.ts b/src/main.ts index 5013128..898c8e6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,103 +1,101 @@ import { Plugin } from "obsidian"; import type { ObsidianProtocolData } from "obsidian"; -import { BratSettingsTab } from "./ui/SettingsTab"; +import BetaPlugins from "./features/BetaPlugins"; +import { themesCheckAndUpdates } from "./features/themes"; import type { Settings } from "./settings"; import { DEFAULT_SETTINGS } from "./settings"; -import BetaPlugins from "./features/BetaPlugins"; -import { addIcons } from "./ui/icons"; -import { logger } from "./utils/logging"; +import AddNewPluginModal from "./ui/AddNewPluginModal"; +import AddNewTheme from "./ui/AddNewTheme"; import PluginCommands from "./ui/PluginCommands"; -import { themesCheckAndUpdates } from "./features/themes"; +import { BratSettingsTab } from "./ui/SettingsTab"; +import { addIcons } from "./ui/icons"; import BratAPI from "./utils/BratAPI"; +import { logger } from "./utils/logging"; import { toastMessage } from "./utils/notifications"; -import AddNewTheme from "./ui/AddNewTheme"; -import AddNewPluginModal from "./ui/AddNewPluginModal"; -export default class ThePlugin extends Plugin { - APP_NAME = "BRAT"; - APP_ID = "obsidian42-brat"; - settings: Settings = DEFAULT_SETTINGS; - betaPlugins = new BetaPlugins(this); - commands: PluginCommands = new PluginCommands(this); - bratApi: BratAPI = new BratAPI(this); +export default class BratPlugin extends Plugin { + APP_NAME = "BRAT"; + APP_ID = "obsidian42-brat"; + settings: Settings = DEFAULT_SETTINGS; + betaPlugins = new BetaPlugins(this); + commands: PluginCommands = new PluginCommands(this); + bratApi: BratAPI = new BratAPI(this); - onload() { - console.log(`loading ${this.APP_NAME}`); + onload() { + console.log(`loading ${this.APP_NAME}`); - this.loadSettings() - .then(() => { - this.addSettingTab(new BratSettingsTab(this.app, this)); + this.loadSettings() + .then(() => { + this.app.workspace.onLayoutReady(() => { + this.addSettingTab(new BratSettingsTab(this.app, this)); - addIcons(); - this.showRibbonButton(); - this.registerObsidianProtocolHandler( - "brat", - this.obsidianProtocolHandler - ); + addIcons(); + this.showRibbonButton(); + this.registerObsidianProtocolHandler( + "brat", + this.obsidianProtocolHandler, + ); - this.app.workspace.onLayoutReady(() => { - // let obsidian load and calm down before checking for updates - if (this.settings.updateAtStartup) { - setTimeout(() => { - void this.betaPlugins.checkForPluginUpdatesAndInstallUpdates( - false - ); - }, 60000); - } - if (this.settings.updateThemesAtStartup) { - setTimeout(() => { - void themesCheckAndUpdates(this, false); - }, 120000); - } - setTimeout(() => { - window.bratAPI = this.bratApi; - }, 500); - }); - }) - .catch((error: unknown) => { - console.error("Failed to load settings:", error); - }); - } + if (this.settings.updateAtStartup) { + setTimeout(() => { + void this.betaPlugins.checkForPluginUpdatesAndInstallUpdates( + false, + ); + }, 60000); + } + if (this.settings.updateThemesAtStartup) { + setTimeout(() => { + void themesCheckAndUpdates(this, false); + }, 120000); + } + setTimeout(() => { + window.bratAPI = this.bratApi; + }, 500); + }); + }) + .catch((error: unknown) => { + console.error("Failed to load settings:", error); + }); + } - showRibbonButton(): void { - this.addRibbonIcon("BratIcon", "BRAT", () => { - this.commands.ribbonDisplayCommands(); - }); - } + showRibbonButton(): void { + this.addRibbonIcon("BratIcon", "BRAT", () => { + this.commands.ribbonDisplayCommands(); + }); + } - async log(textToLog: string, verbose = false): Promise { - await logger(this, textToLog, verbose); - } + async log(textToLog: string, verbose = false): Promise { + await logger(this, textToLog, verbose); + } - onunload(): void { - console.log(`unloading ${this.APP_NAME}`); - } + onunload(): void { + console.log(`unloading ${this.APP_NAME}`); + } - async loadSettings(): Promise { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Obsidian loadData is set to return Any - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); - } + async loadSettings(): Promise { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } - async saveSettings(): Promise { - await this.saveData(this.settings); - } + async saveSettings(): Promise { + await this.saveData(this.settings); + } - obsidianProtocolHandler = (params: ObsidianProtocolData) => { - if (!params.plugin && !params.theme) { - toastMessage(this, "Could not locate the repository from the URL.", 10); - return; - } + obsidianProtocolHandler = (params: ObsidianProtocolData) => { + if (!params.plugin && !params.theme) { + toastMessage(this, "Could not locate the repository from the URL.", 10); + return; + } - for (const which of ["plugin", "theme"]) { - if (params[which]) { - const modal = - which === "plugin" - ? new AddNewPluginModal(this, this.betaPlugins) - : new AddNewTheme(this); - modal.address = params[which]; - modal.open(); - return; - } - } - }; + for (const which of ["plugin", "theme"]) { + if (params[which]) { + const modal = + which === "plugin" + ? new AddNewPluginModal(this, this.betaPlugins) + : new AddNewTheme(this); + modal.address = params[which]; + modal.open(); + return; + } + } + }; } diff --git a/src/settings.ts b/src/settings.ts index 30facfe..fbc4cfb 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,45 +1,45 @@ -import type ThePlugin from "./main"; import { checksumForString } from "./features/githubUtils"; +import type BratPlugin from "./main"; export interface ThemeInforamtion { - repo: string; - // checksum of theme file (either theme.css or theme-beta.css) - lastUpdate: string; + repo: string; + // checksum of theme file (either theme.css or theme-beta.css) + lastUpdate: string; } export interface PluginFrozenVersion { - repo: string; - version: string; + repo: string; + version: string; } export interface Settings { - pluginList: string[]; - pluginSubListFrozenVersion: PluginFrozenVersion[]; - themesList: ThemeInforamtion[]; - updateAtStartup: boolean; - updateThemesAtStartup: boolean; - enableAfterInstall: boolean; - loggingEnabled: boolean; - loggingPath: string; - loggingVerboseEnabled: boolean; - debuggingMode: boolean; - notificationsEnabled: boolean; - personalAccessToken?: string; + pluginList: string[]; + pluginSubListFrozenVersion: PluginFrozenVersion[]; + themesList: ThemeInforamtion[]; + updateAtStartup: boolean; + updateThemesAtStartup: boolean; + enableAfterInstall: boolean; + loggingEnabled: boolean; + loggingPath: string; + loggingVerboseEnabled: boolean; + debuggingMode: boolean; + notificationsEnabled: boolean; + personalAccessToken?: string; } export const DEFAULT_SETTINGS: Settings = { - pluginList: [], - pluginSubListFrozenVersion: [], - themesList: [], - updateAtStartup: true, - updateThemesAtStartup: true, - enableAfterInstall: true, - loggingEnabled: false, - loggingPath: "BRAT-log", - loggingVerboseEnabled: false, - debuggingMode: false, - notificationsEnabled: true, - personalAccessToken: "", + pluginList: [], + pluginSubListFrozenVersion: [], + themesList: [], + updateAtStartup: true, + updateThemesAtStartup: true, + enableAfterInstall: true, + loggingEnabled: false, + loggingPath: "BRAT-log", + loggingVerboseEnabled: false, + debuggingMode: false, + notificationsEnabled: true, + personalAccessToken: "", }; /** @@ -50,30 +50,30 @@ export const DEFAULT_SETTINGS: Settings = { * @param specifyVersion - if the plugin needs to stay at the frozen version, we need to also record the version */ export function addBetaPluginToList( - plugin: ThePlugin, - repositoryPath: string, - specifyVersion = "" + plugin: BratPlugin, + repositoryPath: string, + specifyVersion = "", ): void { - let save = false; - if (!plugin.settings.pluginList.contains(repositoryPath)) { - plugin.settings.pluginList.unshift(repositoryPath); - save = true; - } - if ( - specifyVersion !== "" && - plugin.settings.pluginSubListFrozenVersion.filter( - (x) => x.repo === repositoryPath - ).length === 0 - ) { - plugin.settings.pluginSubListFrozenVersion.unshift({ - repo: repositoryPath, - version: specifyVersion, - }); - save = true; - } - if (save) { - void plugin.saveSettings(); - } + let save = false; + if (!plugin.settings.pluginList.contains(repositoryPath)) { + plugin.settings.pluginList.unshift(repositoryPath); + save = true; + } + if ( + specifyVersion !== "" && + plugin.settings.pluginSubListFrozenVersion.filter( + (x) => x.repo === repositoryPath, + ).length === 0 + ) { + plugin.settings.pluginSubListFrozenVersion.unshift({ + repo: repositoryPath, + version: specifyVersion, + }); + save = true; + } + if (save) { + void plugin.saveSettings(); + } } /** @@ -84,10 +84,10 @@ export function addBetaPluginToList( * */ export function existBetaPluginInList( - plugin: ThePlugin, - repositoryPath: string + plugin: BratPlugin, + repositoryPath: string, ): boolean { - return plugin.settings.pluginList.contains(repositoryPath); + return plugin.settings.pluginList.contains(repositoryPath); } /** @@ -99,16 +99,16 @@ export function existBetaPluginInList( * */ export function addBetaThemeToList( - plugin: ThePlugin, - repositoryPath: string, - themeCss: string + plugin: BratPlugin, + repositoryPath: string, + themeCss: string, ): void { - const newTheme: ThemeInforamtion = { - repo: repositoryPath, - lastUpdate: checksumForString(themeCss), - }; - plugin.settings.themesList.unshift(newTheme); - void plugin.saveSettings(); + const newTheme: ThemeInforamtion = { + repo: repositoryPath, + lastUpdate: checksumForString(themeCss), + }; + plugin.settings.themesList.unshift(newTheme); + void plugin.saveSettings(); } /** @@ -119,13 +119,13 @@ export function addBetaThemeToList( * */ export function existBetaThemeinInList( - plugin: ThePlugin, - repositoryPath: string + plugin: BratPlugin, + repositoryPath: string, ): boolean { - const testIfThemExists = plugin.settings.themesList.find( - (t) => t.repo === repositoryPath - ); - return testIfThemExists ? true : false; + const testIfThemExists = plugin.settings.themesList.find( + (t) => t.repo === repositoryPath, + ); + return !!testIfThemExists; } /** @@ -137,14 +137,14 @@ export function existBetaThemeinInList( * */ export function updateBetaThemeLastUpdateChecksum( - plugin: ThePlugin, - repositoryPath: string, - checksum: string + plugin: BratPlugin, + repositoryPath: string, + checksum: string, ): void { - plugin.settings.themesList.forEach((t) => { - if (t.repo === repositoryPath) { - t.lastUpdate = checksum; - void plugin.saveSettings(); - } - }); + for (const t of plugin.settings.themesList) { + if (t.repo === repositoryPath) { + t.lastUpdate = checksum; + void plugin.saveSettings(); + } + } } diff --git a/src/types.d.ts b/src/types.d.ts index b758b25..3f56752 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,7 +1,7 @@ import type BratApi from "./utils/BratAPI"; declare global { - interface Window { - bratAPI?: BratApi; - } + interface Window { + bratAPI?: BratApi; + } } diff --git a/src/ui/AddNewPluginModal.ts b/src/ui/AddNewPluginModal.ts index 659291c..6dda1b1 100644 --- a/src/ui/AddNewPluginModal.ts +++ b/src/ui/AddNewPluginModal.ts @@ -1,172 +1,174 @@ -import type ThePlugin from "../main"; import { Modal, Setting } from "obsidian"; import type BetaPlugins from "../features/BetaPlugins"; +import type BratPlugin from "../main"; +import { existBetaPluginInList } from "../settings"; import { toastMessage } from "../utils/notifications"; import { promotionalLinks } from "./Promotional"; -import { existBetaPluginInList } from "../settings"; /** * Add a beta plugin to the list of plugins being tracked and updated */ export default class AddNewPluginModal extends Modal { - plugin: ThePlugin; - betaPlugins: BetaPlugins; - address: string; - openSettingsTabAfterwards: boolean; - readonly useFrozenVersion: boolean; - enableAfterInstall: boolean; - version: string; + plugin: BratPlugin; + betaPlugins: BetaPlugins; + address: string; + openSettingsTabAfterwards: boolean; + readonly useFrozenVersion: boolean; + enableAfterInstall: boolean; + version: string; - constructor( - plugin: ThePlugin, - betaPlugins: BetaPlugins, - openSettingsTabAfterwards = false, - useFrozenVersion = false - ) { - super(plugin.app); - this.plugin = plugin; - this.betaPlugins = betaPlugins; - this.address = ""; - this.openSettingsTabAfterwards = openSettingsTabAfterwards; - this.useFrozenVersion = useFrozenVersion; - this.enableAfterInstall = plugin.settings.enableAfterInstall; - this.version = ""; - } + constructor( + plugin: BratPlugin, + betaPlugins: BetaPlugins, + openSettingsTabAfterwards = false, + useFrozenVersion = false, + ) { + super(plugin.app); + this.plugin = plugin; + this.betaPlugins = betaPlugins; + this.address = ""; + this.openSettingsTabAfterwards = openSettingsTabAfterwards; + this.useFrozenVersion = useFrozenVersion; + this.enableAfterInstall = plugin.settings.enableAfterInstall; + this.version = ""; + } - async submitForm(): Promise { - if (this.address === "") return; - let scrubbedAddress = this.address.replace("https://github.com/", ""); - if (scrubbedAddress.endsWith(".git")) - scrubbedAddress = scrubbedAddress.slice(0, -4); - if (existBetaPluginInList(this.plugin, scrubbedAddress)) { - toastMessage( - this.plugin, - "This plugin is already in the list for beta testing", - 10 - ); - return; - } - const result = await this.betaPlugins.addPlugin( - scrubbedAddress, - false, - false, - false, - this.version, - false, - this.enableAfterInstall - ); - if (result) { - this.close(); - } - } + async submitForm(): Promise { + if (this.address === "") return; + let scrubbedAddress = this.address.replace("https://github.com/", ""); + if (scrubbedAddress.endsWith(".git")) + scrubbedAddress = scrubbedAddress.slice(0, -4); + if (existBetaPluginInList(this.plugin, scrubbedAddress)) { + toastMessage( + this.plugin, + "This plugin is already in the list for beta testing", + 10, + ); + return; + } + const result = await this.betaPlugins.addPlugin( + scrubbedAddress, + false, + false, + false, + this.version, + false, + this.enableAfterInstall, + ); + if (result) { + this.close(); + } + } - onOpen(): void { - this.contentEl.createEl("h4", { - text: "Github repository for beta plugin:", - }); - this.contentEl.createEl("form", {}, (formEl) => { - formEl.addClass("brat-modal"); - new Setting(formEl).addText((textEl) => { - textEl.setPlaceholder( - "Repository (example: https://github.com/GitubUserName/repository-name)" - ); - textEl.setValue(this.address); - textEl.onChange((value) => { - this.address = value.trim(); - }); - textEl.inputEl.addEventListener("keydown", (e: KeyboardEvent) => { - if (e.key === "Enter" && this.address !== " ") { - if ( - (this.useFrozenVersion && this.version !== "") || - !this.useFrozenVersion - ) { - e.preventDefault(); - void this.submitForm(); - } - } - }); - textEl.inputEl.style.width = "100%"; - }); + onOpen(): void { + this.contentEl.createEl("h4", { + text: "Github repository for beta plugin:", + }); + this.contentEl.createEl("form", {}, (formEl) => { + formEl.addClass("brat-modal"); + new Setting(formEl).addText((textEl) => { + textEl.setPlaceholder( + "Repository (example: https://github.com/GitubUserName/repository-name)", + ); + textEl.setValue(this.address); + textEl.onChange((value) => { + this.address = value.trim(); + }); + textEl.inputEl.addEventListener("keydown", (e: KeyboardEvent) => { + if (e.key === "Enter" && this.address !== " ") { + if ( + (this.useFrozenVersion && this.version !== "") || + !this.useFrozenVersion + ) { + e.preventDefault(); + void this.submitForm(); + } + } + }); + textEl.inputEl.style.width = "100%"; + }); - if (this.useFrozenVersion) { - new Setting(formEl).addText((textEl) => { - textEl.setPlaceholder( - "Specify the release version tag (example: 1.0.0)" - ); - textEl.onChange((value) => { - this.version = value.trim(); - }); - textEl.inputEl.style.width = "100%"; - }); - } + if (this.useFrozenVersion) { + new Setting(formEl).addText((textEl) => { + textEl.setPlaceholder( + "Specify the release version tag (example: 1.0.0)", + ); + textEl.onChange((value) => { + this.version = value.trim(); + }); + textEl.inputEl.style.width = "100%"; + }); + } - formEl.createDiv("modal-button-container", (buttonContainerEl) => { - buttonContainerEl.createEl( - "label", - { - cls: "mod-checkbox", - }, - (labelEl) => { - const checkboxEl = labelEl.createEl("input", { - attr: { tabindex: -1 }, - type: "checkbox", - }); - checkboxEl.checked = this.enableAfterInstall; - checkboxEl.addEventListener("click", () => { - this.enableAfterInstall = checkboxEl.checked; - }); - labelEl.appendText("Enable after installing the plugin"); - } - ); + formEl.createDiv("modal-button-container", (buttonContainerEl) => { + buttonContainerEl.createEl( + "label", + { + cls: "mod-checkbox", + }, + (labelEl) => { + const checkboxEl = labelEl.createEl("input", { + attr: { tabindex: -1 }, + type: "checkbox", + }); + checkboxEl.checked = this.enableAfterInstall; + checkboxEl.addEventListener("click", () => { + this.enableAfterInstall = checkboxEl.checked; + }); + labelEl.appendText("Enable after installing the plugin"); + }, + ); - buttonContainerEl - .createEl("button", { attr: { type: "button" }, text: "Never mind" }) - .addEventListener("click", () => { - this.close(); - }); - buttonContainerEl.createEl("button", { - attr: { type: "submit" }, - cls: "mod-cta", - text: "Add Plugin", - }); - }); + buttonContainerEl + .createEl("button", { attr: { type: "button" }, text: "Never mind" }) + .addEventListener("click", () => { + this.close(); + }); + buttonContainerEl.createEl("button", { + attr: { type: "submit" }, + cls: "mod-cta", + text: "Add Plugin", + }); + }); - const newDiv = formEl.createDiv(); - newDiv.style.borderTop = "1px solid #ccc"; - newDiv.style.marginTop = "30px"; - const byTfThacker = newDiv.createSpan(); - byTfThacker.innerHTML = - "BRAT by TFTHacker"; - byTfThacker.style.fontStyle = "italic"; - newDiv.appendChild(byTfThacker); - promotionalLinks(newDiv, false); + const newDiv = formEl.createDiv(); + newDiv.style.borderTop = "1px solid #ccc"; + newDiv.style.marginTop = "30px"; + const byTfThacker = newDiv.createSpan(); + byTfThacker.innerHTML = + "BRAT by TFTHacker"; + byTfThacker.style.fontStyle = "italic"; + newDiv.appendChild(byTfThacker); + promotionalLinks(newDiv, false); - window.setTimeout(() => { - const title = formEl.querySelectorAll(".brat-modal .setting-item-info"); - title.forEach((titleEl) => { - titleEl.remove(); - }); - }, 50); + window.setTimeout(() => { + const title = formEl.querySelectorAll(".brat-modal .setting-item-info"); + for (const titleEl of Array.from(title)) { + titleEl.remove(); + } + }, 50); - // invoked when button is clicked. - formEl.addEventListener("submit", (e: Event) => { - e.preventDefault(); - if (this.address !== "") { - if ( - (this.useFrozenVersion && this.version !== "") || - !this.useFrozenVersion - ) { - void this.submitForm(); - } - } - }); - }); - } + // invoked when button is clicked. + formEl.addEventListener("submit", (e: Event) => { + e.preventDefault(); + if (this.address !== "") { + if ( + (this.useFrozenVersion && this.version !== "") || + !this.useFrozenVersion + ) { + void this.submitForm(); + } + } + }); + }); + } - onClose(): void { - if (this.openSettingsTabAfterwards) { - this.plugin.app.setting.open(); - this.plugin.app.setting.openTabById(this.plugin.APP_ID); - } - } + onClose(): void { + if (this.openSettingsTabAfterwards) { + // @ts-ignore + this.plugin.app.setting.open(); + // @ts-ignore + this.plugin.app.setting.openTabById(this.plugin.APP_ID); + } + } } diff --git a/src/ui/AddNewTheme.ts b/src/ui/AddNewTheme.ts index d74d784..0de2ca8 100644 --- a/src/ui/AddNewTheme.ts +++ b/src/ui/AddNewTheme.ts @@ -1,112 +1,114 @@ -import type ThePlugin from "../main"; import { Modal, Setting } from "obsidian"; import { themeSave } from "../features/themes"; -import { toastMessage } from "../utils/notifications"; +import type BratPlugin from "../main"; import { existBetaThemeinInList } from "../settings"; +import { toastMessage } from "../utils/notifications"; import { promotionalLinks } from "./Promotional"; /** * Add a beta theme to the list of plugins being tracked and updated */ export default class AddNewTheme extends Modal { - plugin: ThePlugin; - address: string; - openSettingsTabAfterwards: boolean; + plugin: BratPlugin; + address: string; + openSettingsTabAfterwards: boolean; - constructor(plugin: ThePlugin, openSettingsTabAfterwards = false) { - super(plugin.app); - this.plugin = plugin; - this.address = ""; - this.openSettingsTabAfterwards = openSettingsTabAfterwards; - } + constructor(plugin: BratPlugin, openSettingsTabAfterwards = false) { + super(plugin.app); + this.plugin = plugin; + this.address = ""; + this.openSettingsTabAfterwards = openSettingsTabAfterwards; + } - async submitForm(): Promise { - if (this.address === "") return; - const scrubbedAddress = this.address.replace("https://github.com/", ""); - if (existBetaThemeinInList(this.plugin, scrubbedAddress)) { - toastMessage( - this.plugin, - "This theme is already in the list for beta testing", - 10 - ); - return; - } + async submitForm(): Promise { + if (this.address === "") return; + const scrubbedAddress = this.address.replace("https://github.com/", ""); + if (existBetaThemeinInList(this.plugin, scrubbedAddress)) { + toastMessage( + this.plugin, + "This theme is already in the list for beta testing", + 10, + ); + return; + } - if (await themeSave(this.plugin, scrubbedAddress, true)) { - this.close(); - } - } + if (await themeSave(this.plugin, scrubbedAddress, true)) { + this.close(); + } + } - onOpen(): void { - this.contentEl.createEl("h4", { - text: "Github repository for beta theme:", - }); - this.contentEl.createEl("form", {}, (formEl) => { - formEl.addClass("brat-modal"); - new Setting(formEl).addText((textEl) => { - textEl.setPlaceholder( - "Repository (example: https://github.com/GitubUserName/repository-name" - ); - textEl.setValue(this.address); - textEl.onChange((value) => { - this.address = value.trim(); - }); - textEl.inputEl.addEventListener("keydown", (e: KeyboardEvent) => { - if (e.key === "Enter" && this.address !== " ") { - e.preventDefault(); - void this.submitForm(); - } - }); - textEl.inputEl.style.width = "100%"; - window.setTimeout(() => { - const title = document.querySelector(".setting-item-info"); - if (title) title.remove(); - textEl.inputEl.focus(); - }, 10); - }); + onOpen(): void { + this.contentEl.createEl("h4", { + text: "Github repository for beta theme:", + }); + this.contentEl.createEl("form", {}, (formEl) => { + formEl.addClass("brat-modal"); + new Setting(formEl).addText((textEl) => { + textEl.setPlaceholder( + "Repository (example: https://github.com/GitubUserName/repository-name", + ); + textEl.setValue(this.address); + textEl.onChange((value) => { + this.address = value.trim(); + }); + textEl.inputEl.addEventListener("keydown", (e: KeyboardEvent) => { + if (e.key === "Enter" && this.address !== " ") { + e.preventDefault(); + void this.submitForm(); + } + }); + textEl.inputEl.style.width = "100%"; + window.setTimeout(() => { + const title = document.querySelector(".setting-item-info"); + if (title) title.remove(); + textEl.inputEl.focus(); + }, 10); + }); - formEl.createDiv("modal-button-container", (buttonContainerEl) => { - buttonContainerEl - .createEl("button", { attr: { type: "button" }, text: "Never mind" }) - .addEventListener("click", () => { - this.close(); - }); - buttonContainerEl.createEl("button", { - attr: { type: "submit" }, - cls: "mod-cta", - text: "Add Theme", - }); - }); + formEl.createDiv("modal-button-container", (buttonContainerEl) => { + buttonContainerEl + .createEl("button", { attr: { type: "button" }, text: "Never mind" }) + .addEventListener("click", () => { + this.close(); + }); + buttonContainerEl.createEl("button", { + attr: { type: "submit" }, + cls: "mod-cta", + text: "Add Theme", + }); + }); - const newDiv = formEl.createDiv(); - newDiv.style.borderTop = "1px solid #ccc"; - newDiv.style.marginTop = "30px"; - const byTfThacker = newDiv.createSpan(); - byTfThacker.innerHTML = - "BRAT by TFTHacker"; - byTfThacker.style.fontStyle = "italic"; - newDiv.appendChild(byTfThacker); - promotionalLinks(newDiv, false); + const newDiv = formEl.createDiv(); + newDiv.style.borderTop = "1px solid #ccc"; + newDiv.style.marginTop = "30px"; + const byTfThacker = newDiv.createSpan(); + byTfThacker.innerHTML = + "BRAT by TFTHacker"; + byTfThacker.style.fontStyle = "italic"; + newDiv.appendChild(byTfThacker); + promotionalLinks(newDiv, false); - window.setTimeout(() => { - const title = formEl.querySelectorAll(".brat-modal .setting-item-info"); - title.forEach((titleEl) => { - titleEl.remove(); - }); - }, 50); + window.setTimeout(() => { + const title = formEl.querySelectorAll(".brat-modal .setting-item-info"); + for (const titleEl of Array.from(title)) { + titleEl.remove(); + } + }, 50); - // invoked when button is clicked. - formEl.addEventListener("submit", (e: Event) => { - e.preventDefault(); - if (this.address !== "") void this.submitForm(); - }); - }); - } + // invoked when button is clicked. + formEl.addEventListener("submit", (e: Event) => { + e.preventDefault(); + if (this.address !== "") void this.submitForm(); + }); + }); + } - onClose(): void { - if (this.openSettingsTabAfterwards) { - this.plugin.app.setting.open(); - this.plugin.app.setting.openTabById(this.plugin.APP_ID); - } - } + onClose(): void { + if (this.openSettingsTabAfterwards) { + // @ts-ignore + this.plugin.app.setting.openTab(); + // @ts-ignore + this.plugin.app.setting.openTabById(this.plugin.APP_ID); + } + } } diff --git a/src/ui/GenericFuzzySuggester.ts b/src/ui/GenericFuzzySuggester.ts index 1885001..e91730c 100644 --- a/src/ui/GenericFuzzySuggester.ts +++ b/src/ui/GenericFuzzySuggester.ts @@ -1,90 +1,90 @@ -import type ThePlugin from "../main"; import { FuzzySuggestModal } from "obsidian"; import type { FuzzyMatch } from "obsidian"; +import type BratPlugin from "../main"; /** * Simple interface for what should be displayed and stored for suggester */ export interface SuggesterItem { - // displayed to user - display: string; - // supplmental info for the callback - info: (() => void) | string; + // displayed to user + display: string; + // supplmental info for the callback + info: (() => void) | string; } /** * Generic suggester for quick reuse */ export class GenericFuzzySuggester extends FuzzySuggestModal { - data: SuggesterItem[] = []; - callbackFunction!: ( - item: SuggesterItem, - evt: MouseEvent | KeyboardEvent - ) => void; + data: SuggesterItem[] = []; + callbackFunction!: ( + item: SuggesterItem, + evt: MouseEvent | KeyboardEvent, + ) => void; - constructor(plugin: ThePlugin) { - super(plugin.app); - this.scope.register(["Shift"], "Enter", (evt) => { - this.enterTrigger(evt); - }); - this.scope.register(["Ctrl"], "Enter", (evt) => { - this.enterTrigger(evt); - }); - } + constructor(plugin: BratPlugin) { + super(plugin.app); + this.scope.register(["Shift"], "Enter", (evt) => { + this.enterTrigger(evt); + }); + this.scope.register(["Ctrl"], "Enter", (evt) => { + this.enterTrigger(evt); + }); + } - setSuggesterData(suggesterData: SuggesterItem[]): void { - this.data = suggesterData; - } + setSuggesterData(suggesterData: SuggesterItem[]): void { + this.data = suggesterData; + } - display( - callBack: (item: SuggesterItem, evt: MouseEvent | KeyboardEvent) => void - ) { - this.callbackFunction = callBack; - this.open(); - } + display( + callBack: (item: SuggesterItem, evt: MouseEvent | KeyboardEvent) => void, + ) { + this.callbackFunction = callBack; + this.open(); + } - getItems(): SuggesterItem[] { - return this.data; - } + getItems(): SuggesterItem[] { + return this.data; + } - getItemText(item: SuggesterItem): string { - return item.display; - } + getItemText(item: SuggesterItem): string { + return item.display; + } - onChooseItem(): void { - return; - } + onChooseItem(): void { + return; + } - renderSuggestion(item: FuzzyMatch, el: HTMLElement): void { - el.createEl("div", { text: item.item.display }); - } + renderSuggestion(item: FuzzyMatch, el: HTMLElement): void { + el.createEl("div", { text: item.item.display }); + } - enterTrigger(evt: KeyboardEvent): void { - const selectedText = document.querySelector( - ".suggestion-item.is-selected div" - )?.textContent; - const item = this.data.find((i) => i.display === selectedText); - if (item) { - this.invokeCallback(item, evt); - this.close(); - } - } + enterTrigger(evt: KeyboardEvent): void { + const selectedText = document.querySelector( + ".suggestion-item.is-selected div", + )?.textContent; + const item = this.data.find((i) => i.display === selectedText); + if (item) { + this.invokeCallback(item, evt); + this.close(); + } + } - onChooseSuggestion( - item: FuzzyMatch, - evt: MouseEvent | KeyboardEvent - ): void { - this.invokeCallback(item.item, evt); - } + onChooseSuggestion( + item: FuzzyMatch, + evt: MouseEvent | KeyboardEvent, + ): void { + this.invokeCallback(item.item, evt); + } - invokeCallback(item: SuggesterItem, evt: MouseEvent | KeyboardEvent): void { - if (typeof this.callbackFunction === "function") { - ( - this.callbackFunction as ( - item: SuggesterItem, - evt: MouseEvent | KeyboardEvent - ) => void - )(item, evt); - } - } + invokeCallback(item: SuggesterItem, evt: MouseEvent | KeyboardEvent): void { + if (typeof this.callbackFunction === "function") { + ( + this.callbackFunction as ( + item: SuggesterItem, + evt: MouseEvent | KeyboardEvent, + ) => void + )(item, evt); + } + } } diff --git a/src/ui/PluginCommands.ts b/src/ui/PluginCommands.ts index 9a7ea62..0561a73 100644 --- a/src/ui/PluginCommands.ts +++ b/src/ui/PluginCommands.ts @@ -1,371 +1,385 @@ -import type ThePlugin from "../main"; -import type { SuggesterItem } from "./GenericFuzzySuggester"; -import { GenericFuzzySuggester } from "./GenericFuzzySuggester"; +import type { SettingTab } from "obsidian"; import type { CommunityPlugin, CommunityTheme } from "../features/githubUtils"; import { - grabCommmunityPluginList, - grabCommmunityThemesList, + grabCommmunityPluginList, + grabCommmunityThemesList, } from "../features/githubUtils"; import { themesCheckAndUpdates } from "../features/themes"; -import AddNewTheme from "./AddNewTheme"; +import type BratPlugin from "../main"; import { toastMessage } from "../utils/notifications"; -import type { SettingTab } from "obsidian"; +import AddNewTheme from "./AddNewTheme"; +import type { SuggesterItem } from "./GenericFuzzySuggester"; +import { GenericFuzzySuggester } from "./GenericFuzzySuggester"; export default class PluginCommands { - plugin: ThePlugin; - bratCommands = [ - { - id: "BRAT-AddBetaPlugin", - icon: "BratIcon", - name: "Plugins: Add a beta plugin for testing", - showInRibbon: true, - callback: () => { - this.plugin.betaPlugins.displayAddNewPluginModal(false, false); - }, - }, - { - id: "BRAT-AddBetaPluginWithFrozenVersion", - icon: "BratIcon", - name: "Plugins: Add a beta plugin with frozen version based on a release tag", - showInRibbon: true, - callback: () => { - this.plugin.betaPlugins.displayAddNewPluginModal(false, true); - }, - }, - { - id: "BRAT-checkForUpdatesAndUpdate", - icon: "BratIcon", - name: "Plugins: Check for updates to all beta plugins and UPDATE", - showInRibbon: true, - callback: async () => { - await this.plugin.betaPlugins.checkForPluginUpdatesAndInstallUpdates( - true, - false - ); - }, - }, - { - id: "BRAT-checkForUpdatesAndDontUpdate", - icon: "BratIcon", - name: "Plugins: Only check for updates to beta plugins, but don't Update", - showInRibbon: true, - callback: async () => { - await this.plugin.betaPlugins.checkForPluginUpdatesAndInstallUpdates( - true, - true - ); - }, - }, - { - id: "BRAT-updateOnePlugin", - icon: "BratIcon", - name: "Plugins: Choose a single plugin version to update", - showInRibbon: true, - callback: () => { - const pluginSubListFrozenVersionNames = new Set( - this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo) - ); - const pluginList: SuggesterItem[] = Object.values( - this.plugin.settings.pluginList - ) - .filter((f) => !pluginSubListFrozenVersionNames.has(f)) - .map((m) => { - return { display: m, info: m }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(pluginList); - gfs.display((results) => { - const msg = `Checking for updates for ${results.info as string}`; - void this.plugin.log(msg, true); - toastMessage(this.plugin, `\n${msg}`, 3); - void this.plugin.betaPlugins.updatePlugin( - results.info as string, - false, - true - ); - }); - }, - }, - { - id: "BRAT-reinstallOnePlugin", - icon: "BratIcon", - name: "Plugins: Choose a single plugin to reinstall", - showInRibbon: true, - callback: () => { - const pluginSubListFrozenVersionNames = new Set( - this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo) - ); - const pluginList: SuggesterItem[] = Object.values( - this.plugin.settings.pluginList - ) - .filter((f) => !pluginSubListFrozenVersionNames.has(f)) - .map((m) => { - return { display: m, info: m }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(pluginList); - gfs.display((results) => { - const msg = `Reinstalling ${results.info as string}`; - toastMessage(this.plugin, `\n${msg}`, 3); - void this.plugin.log(msg, true); - void this.plugin.betaPlugins.updatePlugin( - results.info as string, - false, - false, - true - ); - }); - }, - }, - { - id: "BRAT-restartPlugin", - icon: "BratIcon", - name: "Plugins: Restart a plugin that is already installed", - showInRibbon: true, - callback: () => { - const pluginList: SuggesterItem[] = Object.values( - this.plugin.app.plugins.manifests - ).map((m) => { - return { display: m.id, info: m.id }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(pluginList); - gfs.display((results) => { - toastMessage( - this.plugin, - `${results.info as string}\nPlugin reloading .....`, - 5 - ); - void this.plugin.betaPlugins.reloadPlugin(results.info as string); - }); - }, - }, - { - id: "BRAT-disablePlugin", - icon: "BratIcon", - name: "Plugins: Disable a plugin - toggle it off", - showInRibbon: true, - callback: () => { - const pluginList = this.plugin.betaPlugins - .getEnabledDisabledPlugins(true) - .map((manifest) => { - return { - display: `${manifest.name} (${manifest.id})`, - info: manifest.id, - }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(pluginList); - gfs.display((results) => { - void this.plugin.log(`${results.display} plugin disabled`, false); - if (this.plugin.settings.debuggingMode) console.log(results.info); - void this.plugin.app.plugins.disablePluginAndSave( - results.info as string - ); - }); - }, - }, - { - id: "BRAT-enablePlugin", - icon: "BratIcon", - name: "Plugins: Enable a plugin - toggle it on", - showInRibbon: true, - callback: () => { - const pluginList = this.plugin.betaPlugins - .getEnabledDisabledPlugins(false) - .map((manifest) => { - return { - display: `${manifest.name} (${manifest.id})`, - info: manifest.id, - }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(pluginList); - gfs.display((results) => { - void this.plugin.log(`${results.display} plugin enabled`, false); - void this.plugin.app.plugins.enablePluginAndSave( - results.info as string - ); - }); - }, - }, - { - id: "BRAT-openGitHubZRepository", - icon: "BratIcon", - name: "Plugins: Open the GitHub repository for a plugin", - showInRibbon: true, - callback: async () => { - const communityPlugins = await grabCommmunityPluginList( - this.plugin.settings.debuggingMode - ); - if (communityPlugins) { - const communityPluginList: SuggesterItem[] = Object.values( - communityPlugins - ).map((p: CommunityPlugin) => { - return { display: `Plugin: ${p.name} (${p.repo})`, info: p.repo }; - }); - const bratList: SuggesterItem[] = Object.values( - this.plugin.settings.pluginList - ).map((p) => { - return { display: `BRAT: ${p}`, info: p }; - }); - communityPluginList.forEach((si) => bratList.push(si)); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(bratList); - gfs.display((results) => { - if (results.info) - window.open(`https://github.com/${results.info as string}`); - }); - } - }, - }, - { - id: "BRAT-openGitHubRepoTheme", - icon: "BratIcon", - name: "Themes: Open the GitHub repository for a theme (appearance)", - showInRibbon: true, - callback: async () => { - const communityTheme = await grabCommmunityThemesList( - this.plugin.settings.debuggingMode - ); - if (communityTheme) { - const communityThemeList: SuggesterItem[] = Object.values( - communityTheme - ).map((p: CommunityTheme) => { - return { display: `Theme: ${p.name} (${p.repo})`, info: p.repo }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - gfs.setSuggesterData(communityThemeList); - gfs.display((results) => { - if (results.info) - window.open(`https://github.com/${results.info as string}`); - }); - } - }, - }, - { - id: "BRAT-opentPluginSettings", - icon: "BratIcon", - name: "Plugins: Open Plugin Settings Tab", - showInRibbon: true, - callback: () => { - const settings = this.plugin.app.setting; - const listOfPluginSettingsTabs: SuggesterItem[] = Object.values( - settings.pluginTabs - ).map((t) => { - return { display: `Plugin: ${t.name}`, info: t.id }; - }); - const gfs = new GenericFuzzySuggester(this.plugin); - const listOfCoreSettingsTabs: SuggesterItem[] = Object.values( - settings.settingTabs - ).map((t) => { - return { display: `Core: ${t.name}`, info: t.id }; - }); - listOfPluginSettingsTabs.forEach((si) => - listOfCoreSettingsTabs.push(si) - ); - gfs.setSuggesterData(listOfCoreSettingsTabs); - gfs.display((results) => { - settings.open(); - settings.openTabById(results.info as string); - }); - }, - }, - { - id: "BRAT-GrabBetaTheme", - icon: "BratIcon", - name: "Themes: Grab a beta theme for testing from a Github repository", - showInRibbon: true, - callback: () => { - new AddNewTheme(this.plugin).open(); - }, - }, - { - id: "BRAT-updateBetaThemes", - icon: "BratIcon", - name: "Themes: Update beta themes", - showInRibbon: true, - callback: async () => { - await themesCheckAndUpdates(this.plugin, true); - }, - }, - { - id: "BRAT-allCommands", - icon: "BratIcon", - name: "All Commands list", - showInRibbon: false, - callback: () => { - this.ribbonDisplayCommands(); - }, - }, - ]; + plugin: BratPlugin; + bratCommands = [ + { + id: "AddBetaPlugin", + icon: "BratIcon", + name: "Plugins: Add a beta plugin for testing", + showInRibbon: true, + callback: () => { + this.plugin.betaPlugins.displayAddNewPluginModal(false, false); + }, + }, + { + id: "AddBetaPluginWithFrozenVersion", + icon: "BratIcon", + name: "Plugins: Add a beta plugin with frozen version based on a release tag", + showInRibbon: true, + callback: () => { + this.plugin.betaPlugins.displayAddNewPluginModal(false, true); + }, + }, + { + id: "checkForUpdatesAndUpdate", + icon: "BratIcon", + name: "Plugins: Check for updates to all beta plugins and UPDATE", + showInRibbon: true, + callback: async () => { + await this.plugin.betaPlugins.checkForPluginUpdatesAndInstallUpdates( + true, + false, + ); + }, + }, + { + id: "checkForUpdatesAndDontUpdate", + icon: "BratIcon", + name: "Plugins: Only check for updates to beta plugins, but don't Update", + showInRibbon: true, + callback: async () => { + await this.plugin.betaPlugins.checkForPluginUpdatesAndInstallUpdates( + true, + true, + ); + }, + }, + { + id: "updateOnePlugin", + icon: "BratIcon", + name: "Plugins: Choose a single plugin version to update", + showInRibbon: true, + callback: () => { + const pluginSubListFrozenVersionNames = new Set( + this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo), + ); + const pluginList: SuggesterItem[] = Object.values( + this.plugin.settings.pluginList, + ) + .filter((f) => !pluginSubListFrozenVersionNames.has(f)) + .map((m) => { + return { display: m, info: m }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(pluginList); + gfs.display((results) => { + const msg = `Checking for updates for ${results.info as string}`; + void this.plugin.log(msg, true); + toastMessage(this.plugin, `\n${msg}`, 3); + void this.plugin.betaPlugins.updatePlugin( + results.info as string, + false, + true, + ); + }); + }, + }, + { + id: "reinstallOnePlugin", + icon: "BratIcon", + name: "Plugins: Choose a single plugin to reinstall", + showInRibbon: true, + callback: () => { + const pluginSubListFrozenVersionNames = new Set( + this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo), + ); + const pluginList: SuggesterItem[] = Object.values( + this.plugin.settings.pluginList, + ) + .filter((f) => !pluginSubListFrozenVersionNames.has(f)) + .map((m) => { + return { display: m, info: m }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(pluginList); + gfs.display((results) => { + const msg = `Reinstalling ${results.info as string}`; + toastMessage(this.plugin, `\n${msg}`, 3); + void this.plugin.log(msg, true); + void this.plugin.betaPlugins.updatePlugin( + results.info as string, + false, + false, + true, + ); + }); + }, + }, + { + id: "restartPlugin", + icon: "BratIcon", + name: "Plugins: Restart a plugin that is already installed", + showInRibbon: true, + callback: () => { + const pluginList: SuggesterItem[] = Object.values( + this.plugin.app.plugins.manifests, + ).map((m) => { + return { display: m.id, info: m.id }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(pluginList); + gfs.display((results) => { + toastMessage( + this.plugin, + `${results.info as string}\nPlugin reloading .....`, + 5, + ); + void this.plugin.betaPlugins.reloadPlugin(results.info as string); + }); + }, + }, + { + id: "disablePlugin", + icon: "BratIcon", + name: "Plugins: Disable a plugin - toggle it off", + showInRibbon: true, + callback: () => { + const pluginList = this.plugin.betaPlugins + .getEnabledDisabledPlugins(true) + .map((manifest) => { + return { + display: `${manifest.name} (${manifest.id})`, + info: manifest.id, + }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(pluginList); + gfs.display((results) => { + void this.plugin.log(`${results.display} plugin disabled`, false); + if (this.plugin.settings.debuggingMode) console.log(results.info); + void this.plugin.app.plugins.disablePluginAndSave( + results.info as string, + ); + }); + }, + }, + { + id: "enablePlugin", + icon: "BratIcon", + name: "Plugins: Enable a plugin - toggle it on", + showInRibbon: true, + callback: () => { + const pluginList = this.plugin.betaPlugins + .getEnabledDisabledPlugins(false) + .map((manifest) => { + return { + display: `${manifest.name} (${manifest.id})`, + info: manifest.id, + }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(pluginList); + gfs.display((results) => { + void this.plugin.log(`${results.display} plugin enabled`, false); + void this.plugin.app.plugins.enablePluginAndSave( + results.info as string, + ); + }); + }, + }, + { + id: "openGitHubZRepository", + icon: "BratIcon", + name: "Plugins: Open the GitHub repository for a plugin", + showInRibbon: true, + callback: async () => { + const communityPlugins = await grabCommmunityPluginList( + this.plugin.settings.debuggingMode, + ); + if (communityPlugins) { + const communityPluginList: SuggesterItem[] = Object.values( + communityPlugins, + ).map((p: CommunityPlugin) => { + return { display: `Plugin: ${p.name} (${p.repo})`, info: p.repo }; + }); + const bratList: SuggesterItem[] = Object.values( + this.plugin.settings.pluginList, + ).map((p) => { + return { display: `BRAT: ${p}`, info: p }; + }); + for (const si of communityPluginList) { + bratList.push(si); + } + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(bratList); + gfs.display((results) => { + if (results.info) + window.open(`https://github.com/${results.info as string}`); + }); + } + }, + }, + { + id: "openGitHubRepoTheme", + icon: "BratIcon", + name: "Themes: Open the GitHub repository for a theme (appearance)", + showInRibbon: true, + callback: async () => { + const communityTheme = await grabCommmunityThemesList( + this.plugin.settings.debuggingMode, + ); + if (communityTheme) { + const communityThemeList: SuggesterItem[] = Object.values( + communityTheme, + ).map((p: CommunityTheme) => { + return { display: `Theme: ${p.name} (${p.repo})`, info: p.repo }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + gfs.setSuggesterData(communityThemeList); + gfs.display((results) => { + if (results.info) + window.open(`https://github.com/${results.info as string}`); + }); + } + }, + }, + { + id: "opentPluginSettings", + icon: "BratIcon", + name: "Plugins: Open Plugin Settings Tab", + showInRibbon: true, + callback: () => { + const settings = this.plugin.app.setting; + const listOfPluginSettingsTabs: SuggesterItem[] = Object.values( + settings.pluginTabs, + ).map((t) => { + return { display: `Plugin: ${t.name}`, info: t.id }; + }); + const gfs = new GenericFuzzySuggester(this.plugin); + const listOfCoreSettingsTabs: SuggesterItem[] = Object.values( + settings.settingTabs, + ).map((t) => { + return { display: `Core: ${t.name}`, info: t.id }; + }); + for (const si of listOfPluginSettingsTabs) { + listOfCoreSettingsTabs.push(si); + } + gfs.setSuggesterData(listOfCoreSettingsTabs); + gfs.display((results) => { + settings.open(); + settings.openTabById(results.info as string); + }); + }, + }, + { + id: "GrabBetaTheme", + icon: "BratIcon", + name: "Themes: Grab a beta theme for testing from a Github repository", + showInRibbon: true, + callback: () => { + new AddNewTheme(this.plugin).open(); + }, + }, + { + id: "updateBetaThemes", + icon: "BratIcon", + name: "Themes: Update beta themes", + showInRibbon: true, + callback: async () => { + await themesCheckAndUpdates(this.plugin, true); + }, + }, + { + id: "allCommands", + icon: "BratIcon", + name: "All Commands list", + showInRibbon: false, + callback: () => { + this.ribbonDisplayCommands(); + }, + }, + ]; + + ribbonDisplayCommands(): void { + const bratCommandList: SuggesterItem[] = []; + for (const cmd of this.bratCommands) { + if (cmd.showInRibbon) + bratCommandList.push({ display: cmd.name, info: cmd.callback }); + } + const gfs = new GenericFuzzySuggester(this.plugin); + // @ts-ignore + const settings = this.plugin.app.setting; - ribbonDisplayCommands(): void { - const bratCommandList: SuggesterItem[] = []; - this.bratCommands.forEach((cmd) => { - if (cmd.showInRibbon) - bratCommandList.push({ display: cmd.name, info: cmd.callback }); - }); - const gfs = new GenericFuzzySuggester(this.plugin); - const settings = this.plugin.app.setting; - const listOfCoreSettingsTabs: SuggesterItem[] = Object.values( - settings.settingTabs - ).map((t: SettingTab) => { - return { - display: `Core: ${t.name}`, - info: () => { - settings.open(); - settings.openTabById(t.id); - }, - }; - }); - const listOfPluginSettingsTabs: SuggesterItem[] = Object.values( - settings.pluginTabs - ).map((t: SettingTab) => { - return { - display: "Plugin: " + t.name, - info: () => { - settings.open(); - settings.openTabById(t.id); - }, - }; - }); + const listOfCoreSettingsTabs: SuggesterItem[] = Object.values( + settings.settingTabs, + // @ts-ignore + ).map((t: SettingTab) => { + return { + // @ts-ignore + display: `Core: ${t.name}`, + info: () => { + settings.open(); + // @ts-ignore + settings.openTabById(t.id); + }, + }; + }); + const listOfPluginSettingsTabs: SuggesterItem[] = Object.values( + settings.pluginTabs, + // @ts-ignore + ).map((t: SettingTab) => { + return { + // @ts-ignore + display: `Plugin: ${t.name}`, + info: () => { + settings.open(); + // @ts-ignore + settings.openTabById(t.id); + }, + }; + }); - bratCommandList.push({ - display: "---- Core Plugin Settings ----", - info: () => { - this.ribbonDisplayCommands(); - }, - }); - listOfCoreSettingsTabs.forEach((si) => bratCommandList.push(si)); - bratCommandList.push({ - display: "---- Plugin Settings ----", - info: () => { - this.ribbonDisplayCommands(); - }, - }); - listOfPluginSettingsTabs.forEach((si) => bratCommandList.push(si)); + bratCommandList.push({ + display: "---- Core Plugin Settings ----", + info: () => { + this.ribbonDisplayCommands(); + }, + }); + for (const si of listOfCoreSettingsTabs) { + bratCommandList.push(si); + } + bratCommandList.push({ + display: "---- Plugin Settings ----", + info: () => { + this.ribbonDisplayCommands(); + }, + }); + for (const si of listOfPluginSettingsTabs) { + bratCommandList.push(si); + } - gfs.setSuggesterData(bratCommandList); - gfs.display((results) => { - if (typeof results.info === "function") { - results.info(); - } - }); - } + gfs.setSuggesterData(bratCommandList); + gfs.display((results) => { + if (typeof results.info === "function") { + results.info(); + } + }); + } - constructor(plugin: ThePlugin) { - this.plugin = plugin; + constructor(plugin: BratPlugin) { + this.plugin = plugin; - this.bratCommands.forEach((item) => { - this.plugin.addCommand({ - id: item.id, - name: item.name, - icon: item.icon, - callback: () => { - item.callback(); - }, - }); - }); - } + for (const item of this.bratCommands) { + this.plugin.addCommand({ + id: item.id, + name: item.name, + icon: item.icon, + callback: () => { + item.callback(); + }, + }); + } + } } diff --git a/src/ui/Promotional.ts b/src/ui/Promotional.ts index 08c0ced..c740d40 100644 --- a/src/ui/Promotional.ts +++ b/src/ui/Promotional.ts @@ -1,31 +1,31 @@ export const promotionalLinks = ( - containerEl: HTMLElement, - settingsTab = true + containerEl: HTMLElement, + settingsTab = true, ): HTMLElement => { - const linksDiv = containerEl.createEl("div"); - linksDiv.style.float = "right"; + const linksDiv = containerEl.createEl("div"); + linksDiv.style.float = "right"; - if (!settingsTab) { - linksDiv.style.padding = "10px"; - linksDiv.style.paddingLeft = "15px"; - linksDiv.style.paddingRight = "15px"; - } else { - linksDiv.style.padding = "15px"; - linksDiv.style.paddingLeft = "15px"; - linksDiv.style.paddingRight = "15px"; - linksDiv.style.marginLeft = "15px"; - } + if (!settingsTab) { + linksDiv.style.padding = "10px"; + linksDiv.style.paddingLeft = "15px"; + linksDiv.style.paddingRight = "15px"; + } else { + linksDiv.style.padding = "15px"; + linksDiv.style.paddingLeft = "15px"; + linksDiv.style.paddingRight = "15px"; + linksDiv.style.marginLeft = "15px"; + } - const twitterSpan = linksDiv.createDiv("coffee"); - twitterSpan.addClass("ex-twitter-span"); - twitterSpan.style.paddingLeft = "10px"; - const captionText = twitterSpan.createDiv(); - captionText.innerText = "Learn more about my work at:"; - twitterSpan.appendChild(captionText); - const twitterLink = twitterSpan.createEl("a", { - href: "https://tfthacker.com", - }); - twitterLink.innerText = "https://tfthacker.com"; + const twitterSpan = linksDiv.createDiv("coffee"); + twitterSpan.addClass("ex-twitter-span"); + twitterSpan.style.paddingLeft = "10px"; + const captionText = twitterSpan.createDiv(); + captionText.innerText = "Learn more about my work at:"; + twitterSpan.appendChild(captionText); + const twitterLink = twitterSpan.createEl("a", { + href: "https://tfthacker.com", + }); + twitterLink.innerText = "https://tfthacker.com"; - return linksDiv; + return linksDiv; }; diff --git a/src/ui/SettingsTab.ts b/src/ui/SettingsTab.ts index a0a009c..4e78262 100644 --- a/src/ui/SettingsTab.ts +++ b/src/ui/SettingsTab.ts @@ -1,264 +1,264 @@ -import type ThePlugin from "../main"; -import type { App, ToggleComponent, ButtonComponent } from "obsidian"; +import type { App, ButtonComponent, ToggleComponent } from "obsidian"; import { PluginSettingTab, Setting } from "obsidian"; import { themeDelete } from "../features/themes"; +import type BratPlugin from "../main"; import AddNewTheme from "./AddNewTheme"; import { promotionalLinks } from "./Promotional"; const createLink = ( - githubResource: string, - optionalText?: string + githubResource: string, + optionalText?: string, ): DocumentFragment => { - const newLink = new DocumentFragment(); - const linkElement = document.createElement("a"); - linkElement.textContent = githubResource; - linkElement.href = `https://github.com/${githubResource}`; - newLink.appendChild(linkElement); - if (optionalText) { - const textNode = document.createTextNode(optionalText); - newLink.appendChild(textNode); - } - return newLink; + const newLink = new DocumentFragment(); + const linkElement = document.createElement("a"); + linkElement.textContent = githubResource; + linkElement.href = `https://github.com/${githubResource}`; + newLink.appendChild(linkElement); + if (optionalText) { + const textNode = document.createTextNode(optionalText); + newLink.appendChild(textNode); + } + return newLink; }; export class BratSettingsTab extends PluginSettingTab { - plugin: ThePlugin; + plugin: BratPlugin; - constructor(app: App, plugin: ThePlugin) { - super(app, plugin); - this.plugin = plugin; - } + constructor(app: App, plugin: BratPlugin) { + super(app, plugin); + this.plugin = plugin; + } - display(): void { - const { containerEl } = this; - containerEl.empty(); + display(): void { + const { containerEl } = this; + containerEl.empty(); - new Setting(containerEl) - .setName("Auto-enable plugins after installation") - .setDesc( - 'If enabled beta plugins will be automatically enabled after installtion by default. Note: you can toggle this on and off for each plugin in the "Add Plugin" form.' - ) - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.enableAfterInstall); - cb.onChange(async (value: boolean) => { - this.plugin.settings.enableAfterInstall = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Auto-enable plugins after installation") + .setDesc( + 'If enabled beta plugins will be automatically enabled after installtion by default. Note: you can toggle this on and off for each plugin in the "Add Plugin" form.', + ) + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.enableAfterInstall); + cb.onChange(async (value: boolean) => { + this.plugin.settings.enableAfterInstall = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Auto-update plugins at startup") - .setDesc( - "If enabled all beta plugins will be checked for updates each time Obsidian starts. Note: this does not update frozen version plugins." - ) - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.updateAtStartup); - cb.onChange(async (value: boolean) => { - this.plugin.settings.updateAtStartup = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Auto-update plugins at startup") + .setDesc( + "If enabled all beta plugins will be checked for updates each time Obsidian starts. Note: this does not update frozen version plugins.", + ) + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.updateAtStartup); + cb.onChange(async (value: boolean) => { + this.plugin.settings.updateAtStartup = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Auto-update themes at startup") - .setDesc( - "If enabled all beta themes will be checked for updates each time Obsidian starts." - ) - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.updateThemesAtStartup); - cb.onChange(async (value: boolean) => { - this.plugin.settings.updateThemesAtStartup = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Auto-update themes at startup") + .setDesc( + "If enabled all beta themes will be checked for updates each time Obsidian starts.", + ) + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.updateThemesAtStartup); + cb.onChange(async (value: boolean) => { + this.plugin.settings.updateThemesAtStartup = value; + await this.plugin.saveSettings(); + }); + }); - promotionalLinks(containerEl, true); - containerEl.createEl("hr"); - containerEl.createEl("h2", { text: "Beta Plugin List" }); - containerEl.createEl("div", { - text: `The following is a list of beta plugins added via the command palette "Add a beta plugin for testing" or "Add a beta plugin with frozen version for testing". A frozen version is a specific release of a plugin based on its release tag. `, - }); - containerEl.createEl("p"); - containerEl.createEl("div", { - text: "Click the x button next to a plugin to remove it from the list.", - }); - containerEl.createEl("p"); - containerEl.createEl("span").createEl("b", { text: "Note: " }); - containerEl.createSpan({ - text: "This does not delete the plugin, this should be done from the Community Plugins tab in Settings.", - }); + promotionalLinks(containerEl, true); + containerEl.createEl("hr"); + new Setting(containerEl).setName("Beta plugin list").setHeading(); + containerEl.createEl("div", { + text: `The following is a list of beta plugins added via the command palette "Add a beta plugin for testing" or "Add a beta plugin with frozen version for testing". A frozen version is a specific release of a plugin based on its release tag. `, + }); + containerEl.createEl("p"); + containerEl.createEl("div", { + text: "Click the x button next to a plugin to remove it from the list.", + }); + containerEl.createEl("p"); + containerEl.createEl("span").createEl("b", { text: "Note: " }); + containerEl.createSpan({ + text: "This does not delete the plugin, this should be done from the Community Plugins tab in Settings.", + }); - new Setting(containerEl).addButton((cb: ButtonComponent) => { - cb.setButtonText("Add Beta plugin"); - cb.onClick(() => { - this.plugin.app.setting.close(); - this.plugin.betaPlugins.displayAddNewPluginModal(true, false); - }); - }); + new Setting(containerEl).addButton((cb: ButtonComponent) => { + cb.setButtonText("Add Beta plugin"); + cb.onClick(() => { + this.plugin.app.setting.close(); + this.plugin.betaPlugins.displayAddNewPluginModal(true, false); + }); + }); - const pluginSubListFrozenVersionNames = new Set( - this.plugin.settings.pluginSubListFrozenVersion.map((x) => x.repo) - ); - for (const bp of this.plugin.settings.pluginList) { - if (pluginSubListFrozenVersionNames.has(bp)) { - continue; - } - new Setting(containerEl) - .setName(createLink(bp)) - .addButton((btn: ButtonComponent) => { - btn.setIcon("cross"); - btn.setTooltip("Delete this beta plugin"); - btn.onClick(() => { - if (btn.buttonEl.textContent === "") - btn.setButtonText("Click once more to confirm removal"); - else { - const { buttonEl } = btn; - const { parentElement } = buttonEl; - if (parentElement?.parentElement) { - parentElement.parentElement.remove(); - this.plugin.betaPlugins.deletePlugin(bp); - } - } - }); - }); - } + const pluginSubListFrozenVersionNames = new Set( + this.plugin.settings.pluginSubListFrozenVersion.map((x) => x.repo), + ); + for (const bp of this.plugin.settings.pluginList) { + if (pluginSubListFrozenVersionNames.has(bp)) { + continue; + } + new Setting(containerEl) + .setName(createLink(bp)) + .addButton((btn: ButtonComponent) => { + btn.setIcon("cross"); + btn.setTooltip("Delete this beta plugin"); + btn.onClick(() => { + if (btn.buttonEl.textContent === "") + btn.setButtonText("Click once more to confirm removal"); + else { + const { buttonEl } = btn; + const { parentElement } = buttonEl; + if (parentElement?.parentElement) { + parentElement.parentElement.remove(); + this.plugin.betaPlugins.deletePlugin(bp); + } + } + }); + }); + } - new Setting(containerEl).addButton((cb: ButtonComponent) => { - cb.setButtonText("Add Beta plugin with frozen version"); - cb.onClick(() => { - this.plugin.app.setting.close(); - this.plugin.betaPlugins.displayAddNewPluginModal(true, true); - }); - }); - for (const bp of this.plugin.settings.pluginSubListFrozenVersion) { - new Setting(containerEl) - .setName(createLink(bp.repo, ` (version ${bp.version})`)) - .addButton((btn: ButtonComponent) => { - btn.setIcon("cross"); - btn.setTooltip("Delete this beta plugin"); - btn.onClick(() => { - if (btn.buttonEl.textContent === "") - btn.setButtonText("Click once more to confirm removal"); - else { - const { buttonEl } = btn; - const { parentElement } = buttonEl; - if (parentElement?.parentElement) { - parentElement.parentElement.remove(); - this.plugin.betaPlugins.deletePlugin(bp.repo); - } - } - }); - }); - } + new Setting(containerEl).addButton((cb: ButtonComponent) => { + cb.setButtonText("Add Beta plugin with frozen version"); + cb.onClick(() => { + this.plugin.app.setting.close(); + this.plugin.betaPlugins.displayAddNewPluginModal(true, true); + }); + }); + for (const bp of this.plugin.settings.pluginSubListFrozenVersion) { + new Setting(containerEl) + .setName(createLink(bp.repo, ` (version ${bp.version})`)) + .addButton((btn: ButtonComponent) => { + btn.setIcon("cross"); + btn.setTooltip("Delete this beta plugin"); + btn.onClick(() => { + if (btn.buttonEl.textContent === "") + btn.setButtonText("Click once more to confirm removal"); + else { + const { buttonEl } = btn; + const { parentElement } = buttonEl; + if (parentElement?.parentElement) { + parentElement.parentElement.remove(); + this.plugin.betaPlugins.deletePlugin(bp.repo); + } + } + }); + }); + } - containerEl.createEl("h2", { text: "Beta Themes List" }); + new Setting(containerEl).setName("Beta themes list").setHeading(); - new Setting(containerEl).addButton((cb: ButtonComponent) => { - cb.setButtonText("Add Beta Theme"); - cb.onClick(() => { - this.plugin.app.setting.close(); - new AddNewTheme(this.plugin).open(); - }); - }); + new Setting(containerEl).addButton((cb: ButtonComponent) => { + cb.setButtonText("Add Beta Theme"); + cb.onClick(() => { + this.plugin.app.setting.close(); + new AddNewTheme(this.plugin).open(); + }); + }); - for (const bp of this.plugin.settings.themesList) { - new Setting(containerEl) - .setName(createLink(bp.repo)) - .addButton((btn: ButtonComponent) => { - btn.setIcon("cross"); - btn.setTooltip("Delete this beta theme"); - btn.onClick(() => { - if (btn.buttonEl.textContent === "") - btn.setButtonText("Click once more to confirm removal"); - else { - const { buttonEl } = btn; - const { parentElement } = buttonEl; - if (parentElement?.parentElement) { - parentElement.parentElement.remove(); - themeDelete(this.plugin, bp.repo); - } - } - }); - }); - } + for (const bp of this.plugin.settings.themesList) { + new Setting(containerEl) + .setName(createLink(bp.repo)) + .addButton((btn: ButtonComponent) => { + btn.setIcon("cross"); + btn.setTooltip("Delete this beta theme"); + btn.onClick(() => { + if (btn.buttonEl.textContent === "") + btn.setButtonText("Click once more to confirm removal"); + else { + const { buttonEl } = btn; + const { parentElement } = buttonEl; + if (parentElement?.parentElement) { + parentElement.parentElement.remove(); + themeDelete(this.plugin, bp.repo); + } + } + }); + }); + } - containerEl.createEl("h2", { text: "Monitoring" }); + new Setting(containerEl).setName("Monitoring").setHeading(); - new Setting(containerEl) - .setName("Enable Notifications") - .setDesc( - "BRAT will provide popup notifications for its various activities. Turn this off means no notifications from BRAT." - ) - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.notificationsEnabled); - cb.onChange(async (value: boolean) => { - this.plugin.settings.notificationsEnabled = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Enable Notifications") + .setDesc( + "BRAT will provide popup notifications for its various activities. Turn this off means no notifications from BRAT.", + ) + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.notificationsEnabled); + cb.onChange(async (value: boolean) => { + this.plugin.settings.notificationsEnabled = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Enable Logging") - .setDesc("Plugin updates will be logged to a file in the log file.") - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.loggingEnabled); - cb.onChange(async (value: boolean) => { - this.plugin.settings.loggingEnabled = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Enable Logging") + .setDesc("Plugin updates will be logged to a file in the log file.") + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.loggingEnabled); + cb.onChange(async (value: boolean) => { + this.plugin.settings.loggingEnabled = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(this.containerEl) - .setName("BRAT Log File Location") - .setDesc( - "Logs will be saved to this file. Don't add .md to the file name." - ) - .addSearch((cb) => { - cb.setPlaceholder("Example: BRAT-log") - .setValue(this.plugin.settings.loggingPath) - .onChange(async (newFolder) => { - this.plugin.settings.loggingPath = newFolder; - await this.plugin.saveSettings(); - }); - }); + new Setting(this.containerEl) + .setName("BRAT Log File Location") + .setDesc( + "Logs will be saved to this file. Don't add .md to the file name.", + ) + .addSearch((cb) => { + cb.setPlaceholder("Example: BRAT-log") + .setValue(this.plugin.settings.loggingPath) + .onChange(async (newFolder) => { + this.plugin.settings.loggingPath = newFolder; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Enable Verbose Logging") - .setDesc("Get a lot more information in the log.") - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.loggingVerboseEnabled); - cb.onChange(async (value: boolean) => { - this.plugin.settings.loggingVerboseEnabled = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Enable Verbose Logging") + .setDesc("Get a lot more information in the log.") + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.loggingVerboseEnabled); + cb.onChange(async (value: boolean) => { + this.plugin.settings.loggingVerboseEnabled = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Debugging Mode") - .setDesc( - "Atomic Bomb level console logging. Can be used for troubleshoting and development." - ) - .addToggle((cb: ToggleComponent) => { - cb.setValue(this.plugin.settings.debuggingMode); - cb.onChange(async (value: boolean) => { - this.plugin.settings.debuggingMode = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Debugging Mode") + .setDesc( + "Atomic Bomb level console logging. Can be used for troubleshoting and development.", + ) + .addToggle((cb: ToggleComponent) => { + cb.setValue(this.plugin.settings.debuggingMode); + cb.onChange(async (value: boolean) => { + this.plugin.settings.debuggingMode = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Personal Access Token") - .setDesc( - "If you need to access private repositories, enter the personal access token here." - ) - .addText((text) => { - text - .setPlaceholder("Enter your personal access token") - .setValue(this.plugin.settings.personalAccessToken ?? "") - .onChange(async (value: string) => { - this.plugin.settings.personalAccessToken = value; - await this.plugin.saveSettings(); - }); - }); - } + new Setting(containerEl) + .setName("Personal Access Token") + .setDesc( + "If you need to access private repositories, enter the personal access token here.", + ) + .addText((text) => { + text + .setPlaceholder("Enter your personal access token") + .setValue(this.plugin.settings.personalAccessToken ?? "") + .onChange(async (value: string) => { + this.plugin.settings.personalAccessToken = value; + await this.plugin.saveSettings(); + }); + }); + } } diff --git a/src/ui/icons.ts b/src/ui/icons.ts index 0e59fff..cc60ebb 100644 --- a/src/ui/icons.ts +++ b/src/ui/icons.ts @@ -1,8 +1,8 @@ import { addIcon } from "obsidian"; export function addIcons(): void { - addIcon( - "BratIcon", - `` - ); + addIcon( + "BratIcon", + ``, + ); } diff --git a/src/utils/BratAPI.ts b/src/utils/BratAPI.ts index 609238c..3d9a0af 100644 --- a/src/utils/BratAPI.ts +++ b/src/utils/BratAPI.ts @@ -1,80 +1,80 @@ -import type ThePlugin from "../main"; import { - grabChecksumOfThemeCssFile, - grabCommmunityThemeCssFile, - grabLastCommitDateForFile, + grabChecksumOfThemeCssFile, + grabCommmunityThemeCssFile, + grabLastCommitDateForFile, } from "../features/githubUtils"; import { - themeSave, - themeDelete, - themesCheckAndUpdates, + themeDelete, + themeSave, + themesCheckAndUpdates, } from "../features/themes"; +import type BratPlugin from "../main"; // This module is for API access for use in debuging console export default class BratAPI { - plugin: ThePlugin; + plugin: BratPlugin; - constructor(plugin: ThePlugin) { - this.plugin = plugin; - } + constructor(plugin: BratPlugin) { + this.plugin = plugin; + } - console = ( - logDescription: string, - ...outputs: (string | number | boolean)[] - ): void => { - console.log(`BRAT: ${logDescription}`, ...outputs); - }; + console = ( + logDescription: string, + ...outputs: (string | number | boolean)[] + ): void => { + console.log(`BRAT: ${logDescription}`, ...outputs); + }; - themes = { - themeseCheckAndUpates: async (showInfo: boolean): Promise => { - await themesCheckAndUpdates(this.plugin, showInfo); - }, + themes = { + themeseCheckAndUpates: async (showInfo: boolean): Promise => { + await themesCheckAndUpdates(this.plugin, showInfo); + }, - themeInstallTheme: async (cssGithubRepository: string): Promise => { - const scrubbedAddress = cssGithubRepository.replace( - "https://github.com/", - "" - ); - await themeSave(this.plugin, scrubbedAddress, true); - }, + themeInstallTheme: async (cssGithubRepository: string): Promise => { + const scrubbedAddress = cssGithubRepository.replace( + "https://github.com/", + "", + ); + await themeSave(this.plugin, scrubbedAddress, true); + }, - themesDelete: (cssGithubRepository: string): void => { - const scrubbedAddress = cssGithubRepository.replace( - "https://github.com/", - "" - ); - themeDelete(this.plugin, scrubbedAddress); - }, + themesDelete: (cssGithubRepository: string): void => { + const scrubbedAddress = cssGithubRepository.replace( + "https://github.com/", + "", + ); + themeDelete(this.plugin, scrubbedAddress); + }, - grabCommmunityThemeCssFile: async ( - repositoryPath: string, - betaVersion = false - ): Promise => { - return await grabCommmunityThemeCssFile( - repositoryPath, - betaVersion, - this.plugin.settings.debuggingMode - ); - }, + grabCommmunityThemeCssFile: async ( + repositoryPath: string, + betaVersion = false, + ): Promise => { + return await grabCommmunityThemeCssFile( + repositoryPath, + betaVersion, + this.plugin.settings.debuggingMode, + ); + }, - grabChecksumOfThemeCssFile: async ( - repositoryPath: string, - betaVersion = false - ): Promise => { - return await grabChecksumOfThemeCssFile( - repositoryPath, - betaVersion, - this.plugin.settings.debuggingMode - ); - }, + grabChecksumOfThemeCssFile: async ( + repositoryPath: string, + betaVersion = false, + ): Promise => { + return await grabChecksumOfThemeCssFile( + repositoryPath, + betaVersion, + this.plugin.settings.debuggingMode, + ); + }, - grabLastCommitDateForFile: async ( - repositoryPath: string, - path: string - ): Promise => { - // example await grabLastCommitDateForAFile(t.repo, "theme-beta.css"); - return await grabLastCommitDateForFile(repositoryPath, path); - }, - }; + grabLastCommitDateForFile: async ( + repositoryPath: string, + path: string, + ): Promise => { + // example await grabLastCommitDateForAFile(t.repo, "theme-beta.css"); + return await grabLastCommitDateForFile(repositoryPath, path); + }, + }; } diff --git a/src/utils/internetconnection.ts b/src/utils/internetconnection.ts index 34733aa..c25f9de 100644 --- a/src/utils/internetconnection.ts +++ b/src/utils/internetconnection.ts @@ -3,10 +3,10 @@ * @returns true if connected, false if no internet */ export async function isConnectedToInternet(): Promise { - try { - const online = await fetch(`https://obsidian.md/?${Math.random()}`); - return online.status >= 200 && online.status < 300; - } catch (err) { - return false; - } + try { + const online = await fetch(`https://obsidian.md/?${Math.random()}`); + return online.status >= 200 && online.status < 300; + } catch (err) { + return false; + } } diff --git a/src/utils/logging.ts b/src/utils/logging.ts index 498d6a2..1936e37 100644 --- a/src/utils/logging.ts +++ b/src/utils/logging.ts @@ -1,7 +1,7 @@ -import type ThePlugin from "../main"; import type { TFile } from "obsidian"; -import { moment, Platform } from "obsidian"; +import { Platform, moment } from "obsidian"; import { getDailyNoteSettings } from "obsidian-daily-notes-interface"; +import type BratPlugin from "../main"; /** * Logs events to a log file @@ -12,37 +12,25 @@ import { getDailyNoteSettings } from "obsidian-daily-notes-interface"; * */ export async function logger( - plugin: ThePlugin, - textToLog: string, - verboseLoggingOn = false + plugin: BratPlugin, + textToLog: string, + verboseLoggingOn = false, ): Promise { - if (plugin.settings.debuggingMode) console.log(`BRAT: ${textToLog}`); - if (plugin.settings.loggingEnabled) { - if (!plugin.settings.loggingVerboseEnabled && verboseLoggingOn) { - return; - } else { - const fileName = plugin.settings.loggingPath + ".md"; - const dateOutput = - "[[" + - moment().format(getDailyNoteSettings().format).toString() + - "]] " + - moment().format("HH:mm"); - const os = window.require("os") as { hostname: () => string }; - const machineName = Platform.isDesktop ? os.hostname() : "MOBILE"; - let output = - dateOutput + - " " + - machineName + - " " + - textToLog.replace("\n", " ") + - "\n\n"; + if (plugin.settings.debuggingMode) console.log(`BRAT: ${textToLog}`); + if (plugin.settings.loggingEnabled) { + if (!plugin.settings.loggingVerboseEnabled && verboseLoggingOn) return; - if (await plugin.app.vault.adapter.exists(fileName)) { - const fileContents = await plugin.app.vault.adapter.read(fileName); - output = output + fileContents; - const file = plugin.app.vault.getAbstractFileByPath(fileName) as TFile; - await plugin.app.vault.modify(file, output); - } else await plugin.app.vault.create(fileName, output); - } - } + const fileName = `${plugin.settings.loggingPath}.md`; + const dateOutput = `[[${moment().format(getDailyNoteSettings().format).toString()}]] ${moment().format("HH:mm")}`; + const os = window.require("os") as { hostname: () => string }; + const machineName = Platform.isDesktop ? os.hostname() : "MOBILE"; + let output = `${dateOutput} ${machineName} ${textToLog.replace("\n", " ")}\n\n`; + + if (await plugin.app.vault.adapter.exists(fileName)) { + const fileContents = await plugin.app.vault.adapter.read(fileName); + output = output + fileContents; + const file = plugin.app.vault.getAbstractFileByPath(fileName) as TFile; + await plugin.app.vault.modify(file, output); + } else await plugin.app.vault.create(fileName, output); + } } diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts index 96253e4..af13e2a 100644 --- a/src/utils/notifications.ts +++ b/src/utils/notifications.ts @@ -1,5 +1,5 @@ -import type ThePlugin from "../main"; import { Notice, Platform } from "obsidian"; +import type BratPlugin from "../main"; /** * Displays a notice to the user @@ -10,23 +10,23 @@ import { Notice, Platform } from "obsidian"; * @param contextMenuCallback - function to call if right mouse clicked */ export function toastMessage( - plugin: ThePlugin, - msg: string, - timeoutInSeconds = 10, - contextMenuCallback?: () => void + plugin: BratPlugin, + msg: string, + timeoutInSeconds = 10, + contextMenuCallback?: () => void, ): void { - if (!plugin.settings.notificationsEnabled) return; - const additionalInfo = contextMenuCallback - ? Platform.isDesktop - ? "(click=dismiss, right-click=Info)" - : "(click=dismiss)" - : ""; - const newNotice: Notice = new Notice( - `BRAT\n${msg}\n${additionalInfo}`, - timeoutInSeconds * 1000 - ); - if (contextMenuCallback) - newNotice.noticeEl.oncontextmenu = () => { - contextMenuCallback(); - }; + if (!plugin.settings.notificationsEnabled) return; + const additionalInfo = contextMenuCallback + ? Platform.isDesktop + ? "(click=dismiss, right-click=Info)" + : "(click=dismiss)" + : ""; + const newNotice: Notice = new Notice( + `BRAT\n${msg}\n${additionalInfo}`, + timeoutInSeconds * 1000, + ); + if (contextMenuCallback) + newNotice.noticeEl.oncontextmenu = () => { + contextMenuCallback(); + }; } diff --git a/styles.css b/styles.css index c020b53..4541abb 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,3 @@ .brat-modal .modal-button-container { - margin-top: 5px !important; -} \ No newline at end of file + margin-top: 5px !important; +} diff --git a/version-bump.mjs b/version-bump.mjs index 3f6c905..498e8b1 100644 --- a/version-bump.mjs +++ b/version-bump.mjs @@ -1,14 +1,14 @@ -import { readFileSync, writeFileSync } from 'fs'; +import { readFileSync, writeFileSync } from 'node:fs'; const targetVersion = process.env.npm_package_version; // read minAppVersion from manifest.json and bump version to target version -let manifest = JSON.parse(readFileSync('manifest.json', 'utf8')); +const manifest = JSON.parse(readFileSync('manifest.json', 'utf8')); const { minAppVersion } = manifest; manifest.version = targetVersion; writeFileSync('manifest.json', JSON.stringify(manifest, null, '\t')); // update versions.json with target version and minAppVersion from manifest.json -let versions = JSON.parse(readFileSync('versions.json', 'utf8')); +const versions = JSON.parse(readFileSync('versions.json', 'utf8')); versions[targetVersion] = minAppVersion; writeFileSync('versions.json', JSON.stringify(versions, null, '\t'));