diff --git a/module/Apps/StatSidebar.mjs b/module/Apps/StatSidebar.mjs
index e6fbe05..4c8f9aa 100644
--- a/module/Apps/StatSidebar.mjs
+++ b/module/Apps/StatSidebar.mjs
@@ -35,7 +35,7 @@ export class StatSidebar extends HandlebarsApplicationMixin(AbstractSidebarTab)
const ctx = await super._prepareContext(options);
const db = CONFIG.stats.db;
- ctx.tableCount = db.getTables().length;
+ ctx.tableCount = (await db.getTables()).length;
const controls = {
openStats: { label: `View Stats`, action: `openStats` },
diff --git a/module/Apps/StatsViewer.mjs b/module/Apps/StatsViewer.mjs
index 5568d7f..2f96c0f 100644
--- a/module/Apps/StatsViewer.mjs
+++ b/module/Apps/StatsViewer.mjs
@@ -131,7 +131,7 @@ export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
const tables = new Set();
const subtables = {};
- for (const tableConfig of CONFIG.stats.db.getTables()) {
+ for (const tableConfig of await CONFIG.stats.db.getTables()) {
const [ table, subtable ] = tableConfig.name.split(`/`);
tables.add(table);
if (subtable?.length > 0) {
@@ -190,8 +190,8 @@ export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
_graphData = {};
_privacySetting = `my`;
async #prepareGraphContext(_ctx) {
- const table = CONFIG.stats.db.getTable(this.activeTableID);
- const userData = CONFIG.stats.db.getRows(
+ const table = await CONFIG.stats.db.getTable(this.activeTableID);
+ const userData = await CONFIG.stats.db.getRows(
this.activeTableID,
this._selectedUsers,
this._privacySetting,
diff --git a/module/Apps/TableCreator.mjs b/module/Apps/TableCreator.mjs
index 5be09e3..5d9f511 100644
--- a/module/Apps/TableCreator.mjs
+++ b/module/Apps/TableCreator.mjs
@@ -116,7 +116,7 @@ export class TableCreator extends HandlebarsApplicationMixin(ApplicationV2) {
ui.notifications.error(`Cannot create a table without a name`);
};
- const existing = CONFIG.stats.db.getTable(name);
+ const existing = await CONFIG.stats.db.getTable(name);
if (existing) {
ui.notifications.error(`A table with the name "${name}" already exists`);
return;
@@ -128,11 +128,11 @@ export class TableCreator extends HandlebarsApplicationMixin(ApplicationV2) {
return;
};
const size = Number(name.replace(`Dice/d`, ``));
- CONFIG.stats.db.createTable(createDiceTable(size));
+ await CONFIG.stats.db.createTable(createDiceTable(size));
return;
};
- CONFIG.stats.db.createTable({
+ await CONFIG.stats.db.createTable({
name,
buckets: {
type: this._type,
diff --git a/module/Apps/TableManager.mjs b/module/Apps/TableManager.mjs
index 9df5b90..75c4d00 100644
--- a/module/Apps/TableManager.mjs
+++ b/module/Apps/TableManager.mjs
@@ -1,3 +1,4 @@
+import { BucketTypes } from "../utils/buckets.mjs";
import { diceSizeSorter } from "../utils/sorters/diceSize.mjs";
import { filePath } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
@@ -42,23 +43,18 @@ export class TableManager extends HandlebarsApplicationMixin(ApplicationV2) {
template: filePath(`templates/Apps/common/tableSelect.hbs`),
},
buckets: {
- template: filePath(`templates/Apps/TableManager/buckets/empty.hbs`),
+ template: filePath(`templates/Apps/TableManager/buckets.hbs`),
+ templates: [
+ filePath(`templates/Apps/TableManager/buckets/empty.hbs`),
+ ...Object.values(BucketTypes).map(
+ (bucketType) => filePath(`templates/Apps/TableManager/buckets/${bucketType}.hbs`),
+ ),
+ ],
},
submit: {
template: filePath(`templates/Apps/TableManager/submit.hbs`),
},
};
-
- _configureRenderOptions(options) {
- const table = CONFIG.stats.db.getTable(this.activeTableID);
-
- let bucketType = table?.buckets?.type ?? `empty`;
- this.constructor.PARTS.buckets = {
- template: filePath(`templates/Apps/TableManager/buckets/${bucketType}.hbs`),
- };
-
- super._configureRenderOptions(options);
- };
// #endregion Options
// #region Selected Table
@@ -84,7 +80,7 @@ export class TableManager extends HandlebarsApplicationMixin(ApplicationV2) {
async render({ userUpdated, ...opts } = {}) {
if (userUpdated) {
return;
- }
+ };
await super.render(opts);
};
@@ -140,7 +136,7 @@ export class TableManager extends HandlebarsApplicationMixin(ApplicationV2) {
const tables = new Set();
const subtables = {};
- for (const tableConfig of CONFIG.stats.db.getTables()) {
+ for (const tableConfig of await CONFIG.stats.db.getTables()) {
const [ table, subtable ] = tableConfig.name.split(`/`);
tables.add(table);
if (subtable?.length > 0) {
@@ -167,35 +163,46 @@ export class TableManager extends HandlebarsApplicationMixin(ApplicationV2) {
};
async #prepareBucketContext(ctx) {
- const table = CONFIG.stats.db.getTable(this.activeTableID);
- if (!table) { return };
- const type = table.buckets.type;
+ const table = await CONFIG.stats.db.getTable(this.activeTableID);
+ const type = table?.buckets?.type ?? `empty`;
+
+ const template = filePath(`templates/Apps/TableManager/buckets/${type}.hbs`);
+ ctx.buckets = {
+ locked: false,
+ template,
+ classes: ``,
+ };
+
+ if (!table) {
+ ctx.buckets.classes = `alert-box warning center`;
+ return;
+ };
+
+ const locked = this._selectedTable === `Dice` || table.buckets.locked;
+ ctx.buckets.locked = locked;
+ if (locked) {
+ ctx.buckets.classes = `alert-box locked`;
+ };
+
const capitalizedType = type[0].toUpperCase() + type.slice(1);
if (!this[`_prepare${capitalizedType}Context`]) { return };
this[`_prepare${capitalizedType}Context`](ctx, table);
};
async _prepareNumberContext(ctx, table) {
- ctx.buckets = {
- min: table.buckets.min,
- max: table.buckets.max,
- step: table.buckets.step,
- };
+ ctx.buckets.min = table.buckets.min;
+ ctx.buckets.max = table.buckets.max;
+ ctx.buckets.step = table.buckets.step;
};
async _prepareRangeContext(ctx, table) {
- ctx.buckets = {
- locked: this._selectedTable === `Dice` || table.buckets.locked,
- min: table.buckets.min,
- max: table.buckets.max,
- step: table.buckets.step,
- };
+ ctx.buckets.min = table.buckets.min;
+ ctx.buckets.max = table.buckets.max;
+ ctx.buckets.step = table.buckets.step;
};
async _prepareStringContext(ctx, table) {
- ctx.buckets = {
- choices: [...table.buckets.choices],
- };
+ ctx.buckets.choices = [...table.buckets.choices];
};
// #endregion Data Prep
@@ -230,7 +237,7 @@ export class TableManager extends HandlebarsApplicationMixin(ApplicationV2) {
ui.notifications.info(`Nothing to save`);
return;
}
- CONFIG.stats.db.updateTable(this.activeTableID, formData.object);
+ await CONFIG.stats.db.updateTable(this.activeTableID, formData.object);
};
// #endregion Actions
};
diff --git a/module/utils/databases/Database.mjs b/module/utils/databases/Database.mjs
index 72f1ca1..5f32069 100644
--- a/module/utils/databases/Database.mjs
+++ b/module/utils/databases/Database.mjs
@@ -1,4 +1,5 @@
/* eslint-disable no-unused-vars */
+import { validateBucketConfig } from "../buckets.mjs";
/*
NOTE:
@@ -24,9 +25,11 @@ Default Subtables:
tables that are parents to other tables.
*/
+const { deleteProperty, diffObject, expandObject, mergeObject } = foundry.utils;
+
export class Database {
// MARK: Table Ops
- static createTable(tableConfig) {
+ static async createTable(tableConfig) {
if (!game.user.isGM) {
ui.notifications.error(`You do not have the required permission to create a new table`);
return false;
@@ -52,23 +55,61 @@ export class Database {
tables[name] = tableConfig;
game.settings.set(__ID__, `tables`, tables);
- this.render();
+ this.render({ tags: [`table`] });
return true;
};
/** @returns {Array
} */
- static getTables() {
+ static async getTables() {
const tables = game.settings.get(__ID__, `tables`);
return Object.values(tables) ?? [];
};
- static getTable(tableID) {
+ static async getTable(tableID) {
const tables = game.settings.get(__ID__, `tables`);
if (!tables[tableID]) { return };
return tables[tableID];
};
- static deleteTable(tableID) {
+ static async updateTable(tableID, changes) {
+ const table = this.getTable(tableID);
+ if (!tables[tableID]) {
+ ui.notifications.error(`Cannot update table that doesn't exist`);
+ return false;
+ };
+
+ // Bucket coercion in case called via the API
+ deleteProperty(changes, `name`);
+ deleteProperty(changes, `buckets.type`);
+
+ const diff = diffObject(
+ table,
+ expandObject(changes),
+ { inner: true, deletionKeys: true },
+ );
+ if (Object.keys(diff).length === 0) { return false };
+
+ const updated = mergeObject(
+ table,
+ diff,
+ { inplace: false, performDeletions: true },
+ );
+
+ try {
+ updated.buckets = validateBucketConfig(updated.buckets);
+ } catch (e) {
+ ui.notifications.error(e);
+ return false;
+ };
+
+ const tables = game.settings.get(__ID__, `tables`);
+ tables[tableID] = updated;
+ game.settings.set(__ID__, `tables`, tables);
+ this.render({ tags: [`table`] });
+ return true;
+ };
+
+ static async deleteTable(tableID) {
if (!game.user.isGM) {
ui.notifications.error(`You do not have the required permission to delete a table`);
return false;
@@ -86,23 +127,23 @@ export class Database {
};
// MARK: Row Ops
- static createRow(table, userID, row, opts) {
+ static async createRow(table, userID, row, opts) {
throw new Error(`createRow() must be implemented`);
};
- static createRows(table, userID, rows, opts) {
+ static async createRows(table, userID, rows, opts) {
throw new Error(`createRows() must be implemented`);
};
- static getRows(tableID, userIDs, privacy = `none`) {
+ static async getRows(tableID, userIDs, privacy = `none`) {
throw new Error(`getRows() must be implemented`);
};
- static updateRow(table, userID, rowID, changes) {
+ static async updateRow(table, userID, rowID, changes) {
throw new Error(`updateRow() must be implemented`);
};
- static deleteRow(table, userID, rowID) {
+ static async deleteRow(table, userID, rowID) {
throw new Error(`deleteRow() must be implemented`);
};
@@ -137,7 +178,7 @@ export class Database {
* Rerenders all of the applications that are displaying data from
* this database
*/
- static render(opts) {
+ static async render(opts) {
for (const app of this._apps.values()) {
app.render(opts);
};
@@ -148,9 +189,9 @@ export class Database {
* Used to listen for changes from other clients and rerender the apps
* as required in order to keep the data as up-to-date as possible.
*/
- static registerListeners() {};
+ static async registerListeners() {};
- static unregisterListeners() {};
+ static async unregisterListeners() {};
};
/* eslint-enable no-unused-vars */
diff --git a/module/utils/databases/Memory.mjs b/module/utils/databases/Memory.mjs
index 7ee598a..2987bab 100644
--- a/module/utils/databases/Memory.mjs
+++ b/module/utils/databases/Memory.mjs
@@ -1,3 +1,4 @@
+import { createDiceTable } from "./utils.mjs";
import { Database } from "./Database.mjs";
import { filterPrivateRows } from "../privacy.mjs";
import { Logger } from "../Logger.mjs";
@@ -7,48 +8,9 @@ const { deleteProperty, diffObject, expandObject, mergeObject, randomID } = foun
export class MemoryDatabase extends Database {
static #tables = {
- "Dice/d10": {
- name: `Dice/d10`,
- buckets: {
- type: `range`,
- locked: true,
- min: 1,
- max: 10,
- step: 1,
- },
- graph: {
- type: `bar`,
- stacked: true,
- },
- },
- "Dice/d20": {
- name: `Dice/d20`,
- buckets: {
- type: `range`,
- locked: true,
- min: 1,
- max: 20,
- step: 1,
- },
- graph: {
- type: `bar`,
- stacked: true,
- },
- },
- "Dice/d100": {
- name: `Dice/d100`,
- buckets: {
- type: `range`,
- locked: true,
- min: 1,
- max: 100,
- step: 1,
- },
- graph: {
- type: `bar`,
- stacked: true,
- },
- },
+ "Dice/d10": createDiceTable(10),
+ "Dice/d20": createDiceTable(20),
+ "Dice/d100": createDiceTable(100),
"Successes Number": {
name: `Successes Number`,
buckets: {
@@ -88,13 +50,13 @@ export class MemoryDatabase extends Database {
static #rows = {};
- static createTable(tableConfig) {
+ static async createTable(tableConfig) {
this.#tables[tableConfig.name] = tableConfig;
this.render();
return true;
};
- static getTableNames() {
+ static async getTableNames() {
const tables = new Set();
for (const tableID of Object.keys(this.#tables)) {
const [ targetTable ] = tableID.split(`/`, 2);
@@ -103,7 +65,7 @@ export class MemoryDatabase extends Database {
return Array.from(tables);
};
- static getSubtableNames(table) {
+ static async getSubtableNames(table) {
const subtables = new Set();
for (const tableID of Object.keys(this.#tables)) {
const [ targetTable, targetSubtable ] = tableID.split(`/`, 2);
@@ -115,16 +77,15 @@ export class MemoryDatabase extends Database {
};
/** @returns {Array} */
- static getTables() {
+ static async getTables() {
return Object.values(this.#tables);
};
- static getTable(tableID) {
+ static async getTable(tableID) {
return this.#tables[tableID];
};
static async updateTable(tableID, changes) {
- Logger.debug({tableID, changes});
const table = this.getTable(tableID);
if (!table) { return false };
@@ -156,7 +117,7 @@ export class MemoryDatabase extends Database {
return true;
};
- static createRow(table, userID, row, { rerender = true } = {}) {
+ static async createRow(table, userID, row, { rerender = true } = {}) {
if (!this.#tables[table]) { return };
this.#rows[userID] ??= {};
this.#rows[userID][table] ??= [];
@@ -172,7 +133,7 @@ export class MemoryDatabase extends Database {
};
};
- static createRows(table, userID, rows, { rerender = true } = {}) {
+ static async createRows(table, userID, rows, { rerender = true } = {}) {
if (!this.#tables[table]) { return };
this.#rows[userID] ??= {};
this.#rows[userID][table] ??= [];
@@ -187,7 +148,7 @@ export class MemoryDatabase extends Database {
};
};
- static getRows(tableID, userIDs, privacy = `none`) {
+ static async getRows(tableID, userIDs, privacy = `none`) {
if (userIDs.length === 0) {
return {};
};
@@ -207,7 +168,7 @@ export class MemoryDatabase extends Database {
return datasets;
};
- static updateRow(table, userID, rowID, changes) {
+ static async updateRow(table, userID, rowID, changes) {
if (!this.#tables[table] || !this.#rows[userID]?.[table]) { return };
let row = this.#rows[userID][table].find(row => row._id === rowID);
if (!row) { return };
@@ -215,7 +176,7 @@ export class MemoryDatabase extends Database {
this.render({ userUpdated: userID });
};
- static deleteRow(table, userID, rowID) {
+ static async deleteRow(table, userID, rowID) {
if (!this.#tables[table] || !this.#rows[userID]?.[table]) { return };
let rowIndex = this.#rows[userID][table].findIndex(row => row._id === rowID);
if (rowIndex === -1) { return };
@@ -227,7 +188,7 @@ export class MemoryDatabase extends Database {
* Used to listen for changes from other clients and refresh the local DB as
* required, so that the StatsTracker stays up to date.
*/
- static registerListeners() {};
+ static async registerListeners() {};
- static unregisterListeners() {};
+ static async unregisterListeners() {};
};
diff --git a/public/templates/Apps/TableManager/buckets.hbs b/public/templates/Apps/TableManager/buckets.hbs
new file mode 100644
index 0000000..38301a0
--- /dev/null
+++ b/public/templates/Apps/TableManager/buckets.hbs
@@ -0,0 +1,9 @@
+
+ {{#if buckets.locked}}
+
+ This bucket configuration has been locked, preventing editing
+ of the settings.
+
+ {{/if}}
+ {{> (lookup buckets "template") }}
+
diff --git a/public/templates/Apps/TableManager/buckets/empty.hbs b/public/templates/Apps/TableManager/buckets/empty.hbs
index e4819fd..af96295 100644
--- a/public/templates/Apps/TableManager/buckets/empty.hbs
+++ b/public/templates/Apps/TableManager/buckets/empty.hbs
@@ -1,7 +1,5 @@
-
- {{#if table}}
- Select a Subtable
- {{else}}
- Select a Table
- {{/if}}
-
+{{#if table}}
+ Select a Subtable
+{{else}}
+ Select a Table
+{{/if}}
diff --git a/public/templates/Apps/TableManager/buckets/number.hbs b/public/templates/Apps/TableManager/buckets/number.hbs
index 455595d..91ce2ec 100644
--- a/public/templates/Apps/TableManager/buckets/number.hbs
+++ b/public/templates/Apps/TableManager/buckets/number.hbs
@@ -1,4 +1,7 @@
-
+
{{#if buckets.locked}}
This bucket configuration has been locked, preventing editing
diff --git a/public/templates/Apps/TableManager/buckets/range.hbs b/public/templates/Apps/TableManager/buckets/range.hbs
index e54d552..0462a0e 100644
--- a/public/templates/Apps/TableManager/buckets/range.hbs
+++ b/public/templates/Apps/TableManager/buckets/range.hbs
@@ -1,50 +1,42 @@
-
- {{#if buckets.locked}}
-
- This bucket configuration has been locked, preventing editing
- of the settings.
-
- {{/if}}
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/public/templates/Apps/TableManager/buckets/string.hbs b/public/templates/Apps/TableManager/buckets/string.hbs
index 3f77240..866665e 100644
--- a/public/templates/Apps/TableManager/buckets/string.hbs
+++ b/public/templates/Apps/TableManager/buckets/string.hbs
@@ -1,4 +1,7 @@
-