Refactor the database logic for the apps into it's own mixin for reuse
This commit is contained in:
parent
ffa2162fbd
commit
63f985aa0e
4 changed files with 125 additions and 75 deletions
|
|
@ -1,11 +1,16 @@
|
|||
import { __ID__, filePath } from "../consts.mjs";
|
||||
import { getFile, lastModifiedAt, uploadJson } from "../utils/fs.mjs";
|
||||
import { getFile, uploadJson } from "../utils/fs.mjs";
|
||||
import { promptViaTemplate } from "../utils/dialogs.mjs";
|
||||
import { DBConnectorMixin } from "./mixins/DBConnector.mjs";
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
const { randomID } = foundry.utils;
|
||||
|
||||
export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
export class ArtistApp extends
|
||||
DBConnectorMixin(
|
||||
HandlebarsApplicationMixin(
|
||||
ApplicationV2
|
||||
)) {
|
||||
|
||||
// #region Options
|
||||
static DEFAULT_OPTIONS = {
|
||||
|
|
@ -47,25 +52,19 @@ export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
// #endregion Options
|
||||
|
||||
// #region Instance Data
|
||||
/** @type { null | string } */
|
||||
#artistID = null;
|
||||
static dbType = `Artist`;
|
||||
static dbPath = `storage/db/artists.json`;
|
||||
|
||||
/** The artist that is being edited, or the default artist values */
|
||||
#artist = { name: ``, links: [] };
|
||||
|
||||
/** @type { null | string } */
|
||||
#lastModified = null;
|
||||
|
||||
constructor({ artistID = null, ...opts } = {}) {
|
||||
super(opts);
|
||||
this.#artistID = artistID;
|
||||
};
|
||||
/**
|
||||
* The existing artist data that is being edited, or the default values
|
||||
*/
|
||||
_doc = { name: ``, links: [] };
|
||||
|
||||
get title() {
|
||||
if (this.#artistID && this.#artist.name) {
|
||||
if (this._docID && this._doc.name) {
|
||||
return game.i18n.format(
|
||||
`TB.apps.ArtistApp.title.edit`,
|
||||
{ name: this.#artist.name },
|
||||
{ name: this._doc.name },
|
||||
);
|
||||
};
|
||||
return game.i18n.localize(`TB.apps.ArtistApp.title.create`);
|
||||
|
|
@ -73,50 +72,12 @@ export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
// #endregion Instance Data
|
||||
|
||||
// #region Lifecycle
|
||||
/** Whether or not the database values have been initialized */
|
||||
#connected = false;
|
||||
|
||||
/**
|
||||
* This fetches the DB data that we care about for the purposes of being able
|
||||
* to create/edit entries in the Artists DB
|
||||
*/
|
||||
async #connectToDB() {
|
||||
if (this.#connected) { return true };
|
||||
this.#lastModified ??= await lastModifiedAt(`storage/db/artists.json`);
|
||||
|
||||
if (this.#artistID) {
|
||||
const artists = await getFile(`storage/db/artists.json`);
|
||||
|
||||
if (artists[this.#artistID] == null) {
|
||||
ui.notifications.error(_loc(
|
||||
`TB.notifs.error.artist-ID-404`,
|
||||
{ id: this.#artistID },
|
||||
));
|
||||
return false;
|
||||
};
|
||||
|
||||
Object.assign(this.#artist, artists[this.#artistID]);
|
||||
};
|
||||
this.#connected = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures that the app is in a state where it is allowed to render
|
||||
* before actually letting it render at all.
|
||||
*/
|
||||
async render(options, ...args) {
|
||||
const allowed = await this.#connectToDB();
|
||||
if (!allowed) { return this };
|
||||
return super.render(options, ...args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes it so that we update the frame's title to include the Artist name if
|
||||
* we're editing an existing artist instead of creating a new one.
|
||||
*/
|
||||
_onFirstRender() {
|
||||
if (this.#artist.name) {
|
||||
if (this._doc.name) {
|
||||
this._updateFrame({ window: { title: this.title } });
|
||||
};
|
||||
};
|
||||
|
|
@ -126,27 +87,18 @@ export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
const artist = formData.object;
|
||||
|
||||
if (artist.name.length === 0) { return };
|
||||
artist.links = this.#artist.links;
|
||||
artist.links = this._doc.links;
|
||||
artist.links.forEach(link => {
|
||||
delete link.isNew;
|
||||
});
|
||||
|
||||
// Validate the DB hasn't been updated since
|
||||
if (this.#artistID) {
|
||||
const newLastModified = await lastModifiedAt(`storage/db/artists.json`);
|
||||
if (newLastModified !== this.#lastModified) {
|
||||
ui.notifications.error(
|
||||
`TB.notifs.error.db-out-of-date`,
|
||||
{ localize: true },
|
||||
);
|
||||
return;
|
||||
};
|
||||
};
|
||||
// Validate the DB hasn't been updated since opening
|
||||
if (!(await this.isAbleToSave())) { return };
|
||||
|
||||
const artists = getFile(`storage/db/artists.json`);
|
||||
const artists = await getFile(`storage/db/artists.json`);
|
||||
|
||||
let id = this.#artistID;
|
||||
if (!this.#artistID) {
|
||||
let id = this._docID;
|
||||
if (!this._docID) {
|
||||
do {
|
||||
id = randomID();
|
||||
} while (artists[id] != null);
|
||||
|
|
@ -163,7 +115,7 @@ export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
meta: {
|
||||
idp: this.id,
|
||||
},
|
||||
artist: this.#artist,
|
||||
artist: this._doc,
|
||||
};
|
||||
|
||||
return ctx;
|
||||
|
|
@ -178,7 +130,7 @@ export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
`templates/Dialogs/Link.hbs`,
|
||||
);
|
||||
link.isNew = true;
|
||||
this.#artist.links.push(link);
|
||||
this._doc.links.push(link);
|
||||
this.render({ parts: [ `linkList` ] });
|
||||
};
|
||||
|
||||
|
|
@ -186,7 +138,7 @@ export class ArtistApp extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
static async #deleteLink(event, element) {
|
||||
const index = element.closest(`[data-index]`)?.dataset.index;
|
||||
if (index == null) { return };
|
||||
this.#artist.links.splice(index, 1);
|
||||
this._doc.links.splice(index, 1);
|
||||
this.render({ parts: [ `linkList` ] });
|
||||
};
|
||||
// #endregion Actions
|
||||
|
|
|
|||
89
module/apps/mixins/DBConnector.mjs
Normal file
89
module/apps/mixins/DBConnector.mjs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import { getFile, lastModifiedAt } from "../../utils/fs.mjs";
|
||||
import { __ID__ } from "../../consts.mjs";
|
||||
|
||||
|
||||
export function DBConnectorMixin(HandlebarsApp) {
|
||||
class DBConnectorApp extends HandlebarsApp {
|
||||
// #region Instance Data
|
||||
#lastModified = null;
|
||||
|
||||
#connected = false;
|
||||
|
||||
_docID;
|
||||
_doc;
|
||||
|
||||
static dbType = `Unknown`;
|
||||
static dbPath;
|
||||
|
||||
constructor({ docID, ...opts } = {}) {
|
||||
super(opts);
|
||||
if (this.constructor.dbPath == null) {
|
||||
throw `dbPath must be defined on a DB-connected app`;
|
||||
};
|
||||
this._docID = docID;
|
||||
};
|
||||
|
||||
get dbPath() {
|
||||
return this.constructor.dbPath;
|
||||
};
|
||||
|
||||
get dbType() {
|
||||
return this.constructor.dbType;
|
||||
};
|
||||
// #endregion Instance Data
|
||||
|
||||
// #region Lifecycle
|
||||
/**
|
||||
* Ensures that the app is in a state where it is allowed to render
|
||||
* before actually letting it render at all.
|
||||
*/
|
||||
async render(options, ...args) {
|
||||
const allowed = await this.#connectToDB();
|
||||
if (!allowed) { return this };
|
||||
return super.render(options, ...args);
|
||||
};
|
||||
|
||||
/**
|
||||
* This fetches the DB data that we care about for the purposes of being able
|
||||
* to create/edit entries in the Artists DB
|
||||
*/
|
||||
async #connectToDB() {
|
||||
if (this.#connected) { return true };
|
||||
this.#lastModified ??= await lastModifiedAt(this.dbPath);
|
||||
|
||||
if (this._docID) {
|
||||
const documents = await getFile(this.dbPath);
|
||||
|
||||
if (documents[this._docID] == null) {
|
||||
ui.notifications.error(_loc(
|
||||
`TB.notifs.error.document-ID-404`,
|
||||
{ id: this._docID, dbType: this.dbType },
|
||||
));
|
||||
return false;
|
||||
};
|
||||
|
||||
Object.assign(this._doc, documents[this._docID]);
|
||||
};
|
||||
this.#connected = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
async isAbleToSave() {
|
||||
if (!this._docID) { return true };
|
||||
|
||||
const newLastModified = await lastModifiedAt(this.dbPath);
|
||||
if (newLastModified !== this.#lastModified) {
|
||||
ui.notifications.error(
|
||||
`TB.notifs.error.db-out-of-date`,
|
||||
{ localize: true },
|
||||
);
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
// #endregion Lifecycle
|
||||
};
|
||||
|
||||
return DBConnectorApp;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue