From d3a60fbef5d14c662c7b3010a5b98ce686305444 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:21:35 -0600 Subject: [PATCH 1/7] Remove noopener from the sidebar links --- templates/settings-sidebar-addition.hbs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/settings-sidebar-addition.hbs b/templates/settings-sidebar-addition.hbs index 71fed2b..aec6cfc 100644 --- a/templates/settings-sidebar-addition.hbs +++ b/templates/settings-sidebar-addition.hbs @@ -10,7 +10,7 @@ href="{{ system.url }}/releases/tag/v{{ system.version }}" class="whats-new" target="_blank" - rel="noopener noreferrer" + rel="noreferrer" style="font-size: smaller" > {{localize "taf.misc.whats-new"}} @@ -21,7 +21,7 @@ {{localize "taf.misc.releases"}} @@ -30,7 +30,7 @@ {{localize "taf.misc.wiki"}} @@ -39,7 +39,7 @@ {{localize "taf.misc.issues"}} From 09ac9624ede4c93072083973eb7f9a06924dbcf8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:23:09 -0600 Subject: [PATCH 2/7] Add an automatic version notification for new stable releases, and optionally beta releases --- module/hooks/init.mjs | 2 + module/hooks/ready.mjs | 2 + module/utils/ReleaseChannels.mjs | 75 +++++++++++++++++++++++++++++++ styles/main.css | 3 ++ styles/misc.css | 7 +++ templates/new-version-message.hbs | 17 +++++++ 6 files changed, 106 insertions(+) create mode 100644 module/utils/ReleaseChannels.mjs create mode 100644 styles/misc.css create mode 100644 templates/new-version-message.hbs diff --git a/module/hooks/init.mjs b/module/hooks/init.mjs index b06467e..60a12a5 100644 --- a/module/hooks/init.mjs +++ b/module/hooks/init.mjs @@ -18,6 +18,7 @@ import { TAFMacro } from "../documents/Macro.mjs"; import { TAFTokenDocument } from "../documents/Token.mjs"; // Settings +import { registerReleaseSettings } from "../utils/ReleaseChannels.mjs"; import { registerWorldSettings } from "../settings/world.mjs"; // Utils @@ -89,6 +90,7 @@ Hooks.on(`init`, () => { ); // #endregion Sheets + registerReleaseSettings(); registerWorldSettings(); registerSockets(); diff --git a/module/hooks/ready.mjs b/module/hooks/ready.mjs index 2a8bf39..6a5141d 100644 --- a/module/hooks/ready.mjs +++ b/module/hooks/ready.mjs @@ -1,3 +1,4 @@ +import { checkForNewReleases } from "../utils/ReleaseChannels.mjs"; import { checkMigrations } from "../migrations/checkMigrations.mjs"; Hooks.on(`ready`, () => { @@ -7,4 +8,5 @@ Hooks.on(`ready`, () => { }; checkMigrations(); + checkForNewReleases(); }); diff --git a/module/utils/ReleaseChannels.mjs b/module/utils/ReleaseChannels.mjs new file mode 100644 index 0000000..aa6588b --- /dev/null +++ b/module/utils/ReleaseChannels.mjs @@ -0,0 +1,75 @@ +import { __ID__, filePath } from "../consts.mjs"; +import { Logger } from "./Logger.mjs"; + +const { ChatMessage } = foundry.documents; +const { renderTemplate } = foundry.applications.handlebars; +const { fetchJsonWithTimeout, isNewerVersion } = foundry.utils; + +let newestVersion = null; + +async function fetchLatestVersion() { + const includeBetas = game.settings.get(__ID__, `betaChannel`); + try { + const releases = await fetchJsonWithTimeout(`https://git.varify.ca/api/v1/repos/Foundry/taf/releases?pre-release=${includeBetas}&limit=1`); + return releases.at(0); + } catch { + Logger.error(`Failed to fetch latest version from Forgejo, halting version checks`); + return; + }; +}; + +export async function getLatestVersion() { + if (!newestVersion) { + newestVersion = await fetchLatestVersion(); + }; + return newestVersion; +}; + +export async function checkForNewReleases() { + // Only perform the update check if the game is ready and the user is the active GM + if (!game.user.isActiveGM || !game.ready) { return }; + + // Don't do any version notifications if this is a fresh world + const lastNotifiedVersion = game.settings.get(__ID__, `lastUpdateNotified`); + if (!lastNotifiedVersion) { + game.settings.set(__ID__, `lastUpdateNotified`, game.system.version); + return; + }; + let latest = newestVersion = await getLatestVersion(); + + // Is the latest release newer than the previously notified release + const latestVersion = latest.tag_name.replace(/^v/, ``); + if (!isNewerVersion(latestVersion, lastNotifiedVersion)) { return }; + + const content = await renderTemplate( + filePath(`templates/new-version-message.hbs`), + { + release: latest, + system: game.system, + }, + ); + ChatMessage.implementation.create({ + whisper: [ game.user.id ], + content, + }); + + // Mark the new version as the + game.settings.set(__ID__, `lastUpdateNotified`, latestVersion); +}; + +export function registerReleaseSettings() { + game.settings.register(__ID__, `betaChannel`, { + name: `${__ID__}.settings.betaChannel.name`, + hint: `${__ID__}.settings.betaChannel.hint`, + config: true, + type: Boolean, + default: false, + scope: `world`, + }); + + game.settings.register(__ID__, `lastUpdateNotified`, { + config: false, + type: String, + scope: `world`, + }); +}; diff --git a/styles/main.css b/styles/main.css index 682b25d..e6ae9f9 100644 --- a/styles/main.css +++ b/styles/main.css @@ -23,6 +23,9 @@ @import url("./elements/span.css") layer(elements); @import url("./elements/table.css") layer(elements); +/* Partials */ +@import url("./misc.css") layer(partials); + /* Apps */ @import url("./Apps/common.css") layer(apps); @import url("./Apps/Ask.css") layer(apps); diff --git a/styles/misc.css b/styles/misc.css new file mode 100644 index 0000000..061bcf5 --- /dev/null +++ b/styles/misc.css @@ -0,0 +1,7 @@ +.taf-chat-version-notif { + h2 { + font-family: var(--font-body); + font-size: 1.5rem; + margin: 0; + } +} diff --git a/templates/new-version-message.hbs b/templates/new-version-message.hbs new file mode 100644 index 0000000..ff11bc0 --- /dev/null +++ b/templates/new-version-message.hbs @@ -0,0 +1,17 @@ +
+

+ {{ system.title }} + {{ release.tag_name }} +

+

+ A new {{ifThen release.prerelease "beta" ""}} version of {{ system.title }} has been released. +

+ + Release Notes + +
From e164e046a51eeb037ba932463a9b3d0cd111d7db Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:37:43 -0600 Subject: [PATCH 3/7] Update the settings sidebar to include a semi-persistent notification about new versions --- langs/en-ca.json | 1 + module/apps/overrides/TAFSettingsSidebar.mjs | 10 +++++++++- styles/Apps/TAFSettingsSidebar.css | 6 ++++++ templates/settings-sidebar-addition.hbs | 5 +++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/langs/en-ca.json b/langs/en-ca.json index 43dcbb0..3ba8289 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -72,6 +72,7 @@ "releases": "Releases", "wiki": "Wiki", "issues": "Issues", + "new-version-available": "{version} available now!", "item": { "weight": "Weight", "quantity": "Quantity", diff --git a/module/apps/overrides/TAFSettingsSidebar.mjs b/module/apps/overrides/TAFSettingsSidebar.mjs index b33bbb8..e82e64d 100644 --- a/module/apps/overrides/TAFSettingsSidebar.mjs +++ b/module/apps/overrides/TAFSettingsSidebar.mjs @@ -1,5 +1,7 @@ import { filePath } from "../../consts.mjs"; +import { getLatestVersion } from "../../utils/ReleaseChannels.mjs"; +const { isNewerVersion } = foundry.utils; const { renderTemplate } = foundry.applications.handlebars; const { Settings } = foundry.applications.sidebar.tabs; @@ -13,9 +15,15 @@ export class TAFSettingsSidebar extends Settings { // add the more customized system info into the sidebar const systemBlock = this.element.querySelector(`section.system`); if (!systemBlock) { + const latest = await getLatestVersion(); + const latestVersion = latest.tag_name.slice(1); const htmlString = await renderTemplate( filePath(`templates/settings-sidebar-addition.hbs`), - { system: game.system, }, + { + system: game.system, + hasNewVersion: isNewerVersion(latestVersion, game.system.version), + newVersion: latest.tag_name, + }, ); const temp = document.createElement(`div`); diff --git a/styles/Apps/TAFSettingsSidebar.css b/styles/Apps/TAFSettingsSidebar.css index 010d6b4..4e6d034 100644 --- a/styles/Apps/TAFSettingsSidebar.css +++ b/styles/Apps/TAFSettingsSidebar.css @@ -26,4 +26,10 @@ margin: 0; } } + + p { + text-align: center; + font-size: small; + margin: 0; + } } diff --git a/templates/settings-sidebar-addition.hbs b/templates/settings-sidebar-addition.hbs index aec6cfc..699bb67 100644 --- a/templates/settings-sidebar-addition.hbs +++ b/templates/settings-sidebar-addition.hbs @@ -45,4 +45,9 @@ + {{#if hasNewVersion}} +

+ {{localize "taf.misc.new-version-available" version=newVersion}} +

+ {{/if}} From 3875cbba4fe9c1103029b9130594896f6de23da3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:39:44 -0600 Subject: [PATCH 4/7] Add the localization strings for the betaChannel notifications --- langs/en-ca.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/langs/en-ca.json b/langs/en-ca.json index 3ba8289..4e43a1f 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -15,6 +15,10 @@ "hint": "This removes the default attributes that are applied when a new actor is created, making it so that no attributes get created alongside the actor.", "label": "Remove Attributes" }, + "betaChannel": { + "name": "Beta Release Notifications", + "hint": "Whether or not to receive notifications about new beta releases for the system. If left unchecked, you will still receive notifications about new versions, but only for stable versions." + }, "canPlayersManageAttributes": { "name": "Players Can Manage Attributes", "hint": "This allows players who have edit access to a document to be able to edit what attributes those characters have via the attribute editor" From 7603e79e4218e1b63784eb524aebc6b6fdc975cf Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:40:58 -0600 Subject: [PATCH 5/7] Remove extra arguments so eslint is happier --- dev/hooks/renderSettings.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/hooks/renderSettings.mjs b/dev/hooks/renderSettings.mjs index ad11762..2db8c21 100644 --- a/dev/hooks/renderSettings.mjs +++ b/dev/hooks/renderSettings.mjs @@ -1,4 +1,4 @@ -Hooks.on(`renderSettings`, (app, html, ctx, options) => { +Hooks.on(`renderSettings`, (app, html) => { /** @type {HTMLElement|undefined} */ const coreUpdateTooltip = html.querySelector(`.build .value a`); coreUpdateTooltip?.remove(); From d04985b5b722575407c29a978e04b2502a874c69 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:43:54 -0600 Subject: [PATCH 6/7] Remove the button from the settings config list when the default attributes have been successfully removed & send a notification (closes #92) --- langs/en-ca.json | 3 ++- module/hooks/renderSettingsConfig.mjs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/langs/en-ca.json b/langs/en-ca.json index 4e43a1f..908a714 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -160,7 +160,8 @@ "migration-in-progress": "Applying data migrations for version {version}. Please do NOT refresh the window while this warning is present." }, "success": { - "saved-default-attributes": "Successfully saved default Actor attributes", + "saved-default-attributes": "Successfully saved default Actor attributes.", + "removed-default-attributes": "The default attributes for Actors have been removed.", "migration-successful": "Data migrations for version {version} were successful." } } diff --git a/module/hooks/renderSettingsConfig.mjs b/module/hooks/renderSettingsConfig.mjs index a75c55c..d488af3 100644 --- a/module/hooks/renderSettingsConfig.mjs +++ b/module/hooks/renderSettingsConfig.mjs @@ -20,6 +20,8 @@ Hooks.on(`renderSettingsConfig`, (app, html) => { button.innerHTML = _loc(`taf.settings.actorDefaultAttributes.label`); button.addEventListener(`click`, () => { game.settings.set(__ID__, `actorDefaultAttributes`, undefined); + formGroup.remove(); + ui.notifications.success(_loc(`taf.notifs.success.removed-default-attributes`)); }); const hint = document.createElement(`p`); From d06e8c6850ef6385e6c348eb3f3e19f1c788a71d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 11 May 2026 22:49:01 -0600 Subject: [PATCH 7/7] Remove API URL from the manifest --- system.json | 1 - 1 file changed, 1 deletion(-) diff --git a/system.json b/system.json index 22a301f..041ee0a 100644 --- a/system.json +++ b/system.json @@ -55,7 +55,6 @@ }, "socket": true, "flags": { - "forgejo_api": "https://git.varify.ca/api/v1", "hotReload": { "extensions": ["css", "hbs", "json", "js", "mjs", "svg"], "paths": ["templates", "langs", "styles", "module", "assets"]