From 03623424196c7f9f4f24fb660db84d6814ee0bbe Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 12 Nov 2025 00:09:52 -0700 Subject: [PATCH] Get the QueryStatus application displaying the status more appropriately --- langs/en-ca.json | 3 ++ module/apps/QueryStatus.mjs | 20 +++++++++++--- module/hooks/userConnected.mjs | 5 ++++ module/main.mjs | 1 + module/utils/QueryManager.mjs | 44 ++++++++++++++++++++++++++++-- styles/Apps/QueryStatus.css | 20 ++++++++++++++ styles/elements/span.css | 7 +++-- styles/elements/utils.css | 3 ++ styles/main.css | 2 ++ templates/QueryStatus/controls.hbs | 8 ++++++ templates/QueryStatus/users.hbs | 18 +++++++++--- 11 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 module/hooks/userConnected.mjs create mode 100644 styles/Apps/QueryStatus.css create mode 100644 styles/elements/utils.css create mode 100644 templates/QueryStatus/controls.hbs diff --git a/langs/en-ca.json b/langs/en-ca.json index 1854bf9..24dc2cb 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -15,6 +15,9 @@ "PlayerSheet": "Player Sheet" }, "Apps": { + "QueryStatus": { + "user-disconnected-tooltip": "This user is not logged in to Foundry" + }, "TAFDocumentSheetConfig": { "Sizing": "Sizing", "Width": { diff --git a/module/apps/QueryStatus.mjs b/module/apps/QueryStatus.mjs index bcae4ce..e5ce09b 100644 --- a/module/apps/QueryStatus.mjs +++ b/module/apps/QueryStatus.mjs @@ -1,4 +1,5 @@ import { __ID__, filePath } from "../consts.mjs"; +import { Logger } from "../utils/Logger.mjs"; import { QueryManager } from "../utils/QueryManager.mjs"; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -10,15 +11,22 @@ export class QueryStatus extends HandlebarsApplicationMixin(ApplicationV2) { __ID__, `QueryStatus`, ], + position: { + width: 300, + height: `auto`, + }, + window: { + resizable: true, + }, }; static PARTS = { users: { template: filePath(`templates/QueryStatus/users.hbs`), }, - // controls: { - // template: filePath(`templates/QueryStatus/controls.hbs`), - // }, + controls: { + template: filePath(`templates/QueryStatus/controls.hbs`), + }, }; // #endregion Options @@ -27,6 +35,10 @@ export class QueryStatus extends HandlebarsApplicationMixin(ApplicationV2) { requestID, ...opts }) { + if (!requestID) { + Logger.error(`A requestID must be provided for QueryStatus applications`); + return null; + }; super(opts); this.requestID = requestID; }; @@ -60,7 +72,7 @@ export class QueryStatus extends HandlebarsApplicationMixin(ApplicationV2) { users.push({ id: userID, name: user.name, - colour: user.color, + active: user.active, answers: query.responses[userID] ?? null, }); }; diff --git a/module/hooks/userConnected.mjs b/module/hooks/userConnected.mjs new file mode 100644 index 0000000..750417e --- /dev/null +++ b/module/hooks/userConnected.mjs @@ -0,0 +1,5 @@ +import { QueryManager } from "../utils/QueryManager.mjs"; + +Hooks.on(`userConnected`, (user) => { + QueryManager.userActivity(user.id); +}); diff --git a/module/main.mjs b/module/main.mjs index abde62f..05cf7d9 100644 --- a/module/main.mjs +++ b/module/main.mjs @@ -1,2 +1,3 @@ import "./api.mjs"; import "./hooks/init.mjs"; +import "./hooks/userConnected.mjs"; diff --git a/module/utils/QueryManager.mjs b/module/utils/QueryManager.mjs index 35ece0a..9adce82 100644 --- a/module/utils/QueryManager.mjs +++ b/module/utils/QueryManager.mjs @@ -4,9 +4,12 @@ * @property {Function} resolve * @property {Record} responses * @property {(() => Promise)|null} onSubmit + * @property {QueryStatus|null} app */ import { filePath } from "../consts.mjs"; +import { Logger } from "./Logger.mjs"; +import { QueryStatus } from "../apps/QueryStatus.mjs"; async function sendBasicNotification(userID, answers) { const content = await foundry.applications.handlebars.renderTemplate( @@ -34,7 +37,7 @@ export class QueryManager { delete cloned.onSubmit; delete cloned.resolve; - return cloned; + return foundry.utils.deepFreeze(cloned); }; static async query( @@ -42,7 +45,8 @@ export class QueryManager { { onSubmit = sendBasicNotification, users = null, - config = undefined, + showStatusApp = true, + ...config } = {}, ) { if (!request.id) { @@ -68,13 +72,21 @@ export class QueryManager { this.#queries.set( request.id, { - users: users ?? game.users.filter(u => u.id !== game.user.id), + users: users ?? game.users.filter(u => u.id !== game.user.id).map(u => u.id), resolve, responses: {}, onSubmit, + app: null, }, ); }); + + if (showStatusApp) { + const app = new QueryStatus({ requestID: request.id }); + app.render({ force: true }); + this.#queries.get(request.id).app = app; + }; + return promise; }; @@ -86,7 +98,10 @@ export class QueryManager { // Validate for responses from everyone if (data.users.length === Object.keys(data.responses).length) { + data.app.close(); data.resolve(data.responses); + } else { + data.app?.render({ parts: [ `users` ] }); }; }; @@ -110,4 +125,27 @@ export class QueryManager { payload: { id: requestID }, }); }; + + static async setApplication(requestID, app) { + if (!this.#queries.has(requestID)) { return }; + if (!(app instanceof QueryStatus)) { return }; + const query = this.#queries.get(requestID); + if (query.app) { + Logger.error(`Cannot set an application for a query that has one already`); + return; + }; + query.app = app; + }; + + static async userActivity(userID) { + for (const query of this.#queries.values()) { + if (query.users.includes(userID)) { + query.app.render({ parts: [ `users` ] }); + + // TODO: if the user is connecting, we want to open + // the ask modal on their browser so that they can + // actually fill in the data + }; + }; + }; }; diff --git a/styles/Apps/QueryStatus.css b/styles/Apps/QueryStatus.css new file mode 100644 index 0000000..fbbc60e --- /dev/null +++ b/styles/Apps/QueryStatus.css @@ -0,0 +1,20 @@ +.taf.QueryStatus { + .user-list { + display: flex; + flex-direction: column; + gap: 4px; + list-style-type: none; + margin: 0; + padding: 0; + + li { + display: flex; + flex-direction: row; + align-items: center; + margin: 0; + border: 1px solid yellowgreen; + border-radius: 4px; + padding: 4px 8px; + } + } +} diff --git a/styles/elements/span.css b/styles/elements/span.css index da5c58a..1ce99fe 100644 --- a/styles/elements/span.css +++ b/styles/elements/span.css @@ -18,8 +18,9 @@ .taf > .window-content span { &.loader { - width: 48px; - height: 48px; + --size: 40px; + width: var(--size); + height: var(--size); border-radius: 50%; position: relative; animation: rotate 2s linear infinite; @@ -38,7 +39,7 @@ &::after{ inset: 8px; transform: rotate3d(90, 90, 0, 180deg ); - border-color: #FF3D00; /* This can be the user colour */ + border-color: var(--spinner-inner-colour, #FF3D00); } } } diff --git a/styles/elements/utils.css b/styles/elements/utils.css new file mode 100644 index 0000000..f99356f --- /dev/null +++ b/styles/elements/utils.css @@ -0,0 +1,3 @@ +.taf > .window-content { + .grow { flex-grow: 1; } +} \ No newline at end of file diff --git a/styles/main.css b/styles/main.css index 28a27a4..6994e85 100644 --- a/styles/main.css +++ b/styles/main.css @@ -9,6 +9,7 @@ @import url("./themes/light.css") layer(themes); /* Elements */ +@import url("./elements/utils.css") layer(elements); @import url("./elements/headers.css") layer(elements); @import url("./elements/hr.css") layer(elements); @import url("./elements/input.css") layer(elements); @@ -22,4 +23,5 @@ @import url("./Apps/Ask.css") layer(apps); @import url("./Apps/AttributeManager.css") layer(apps); @import url("./Apps/PlayerSheet.css") layer(apps); +@import url("./Apps/QueryStatus.css") layer(apps); @import url("./Apps/TAFDocumentSheetConfig.css") layer(apps); diff --git a/templates/QueryStatus/controls.hbs b/templates/QueryStatus/controls.hbs new file mode 100644 index 0000000..363c828 --- /dev/null +++ b/templates/QueryStatus/controls.hbs @@ -0,0 +1,8 @@ +
+ + +
diff --git a/templates/QueryStatus/users.hbs b/templates/QueryStatus/users.hbs index ca9049f..640bfdd 100644 --- a/templates/QueryStatus/users.hbs +++ b/templates/QueryStatus/users.hbs @@ -1,7 +1,9 @@ -
    +
      {{#each users as | user |}} -
    • - {{ user.name }} +
    • +
      + {{ user.name }} +
      {{#if user.answers}}
      {{#each user.answers as | answer |}} @@ -13,8 +15,16 @@ {{/each}}
      - {{else}} + {{else if user.active}} + {{else}} + {{/if}}
    • {{/each}}