Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monster archive #142

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open

Monster archive #142

wants to merge 28 commits into from

Conversation

pvbergen
Copy link

@pvbergen pvbergen commented Jan 6, 2025

I was using the builder for some of my custom One-Shots and soon struggled to organize my monsters. I work on different monsters on and off, so exporting and reimporting became a bit tedious.

So, I took some time over the weekend and added a monster archive. It allows to save and manage multiple monsters within the app itself.

This addition might also be helpful for #140.

Functionality:

  • New save button in header to save the active monster in the builder.
  • New page listing saved monsters (/#/monsterarchive) in the menu/drawer.
  • Load into builder, download as 5emm.json and delete single monsters.
  • Export all or selected monsters; import exported lists via dialog.
  • Delete multiple monsters from the archive.

Limitations:

  • Major: Monsters are saved by name, so only one monster with the same name possible in the archive.
    Changing the name creates a new entry in the archive. Other solutions would require a unique identifier per monster (e.g. on reset).
  • Medium: Localstorage will run out at about 200 monsters (depending on size)
  • Medium: Single export only supports 5emm.json, no markup.
    Might be helpful to download many markups quickly instead of loading each monster into the builder.
  • Minor: Confirmation dialogs are using default confirm() instead of quasar dialogs.
  • Minor: No details of monster shown in listing. Unsure what values would be helpful here.

Technical info:

  • The archive uses its own store (monster-archive-store) and two new interfaces (MonsterArchive, MonsterEntry).
  • The archive is totally independent of the builder / active monster (dereferenced objects).
  • The created_at and updated_at info is stored alongside the monster in the store (interface MonsterEntry).
  • Monster versions are automatically updated on import of an archive.
  • Adds three components: MonsterArchive.vue (listing page), LoadMonsterArchiveDialog.vue (import dialog), SaveButton.vue (button in main layout header).
  • New translations keyed by editor.monsterarchive.

Testing:
I did some manual testing so far but haven't used it "productively".

Happy to hear any feedback on the idea and the implementation :)

@ebshimizu
Copy link
Owner

thanks for the PR! I'll check it out when I have time.

Before I get some hands on time with this branch, couple things off the top of my head that are blockers for merge:

  • We should generate uuids for each saved monster. I don't think the uuids need to be saved with the monster file itself (which would require a schema update). When saving/loading a monster we should cache the uuid for the monster so we can default the save dialog to the last saved/loaded monster.
  • We should use IndexedDB instead of local storage for the long-term storage. IndexedDB doesn't have the storage limitations of localstorage but has a bit more setup. Use Dexie (https://dexie.org/), set up a simple DB keyed by unique ID for each monster. If you need help with getting typescript to cooperate there let me know.
  • confirm dialogs should use quasar dialogs for consistency
  • monster details in the listing should include name and last update date at minimum. these could be stored in the IndexedDB alongside the full monster json file

@pvbergen
Copy link
Author

pvbergen commented Jan 7, 2025

Thanks for your feedback.

  • The uuid would only work if we get rid of the moster store. Currently, the archive is fully independent of the normal store, so users can still rely on the existing workflow with export, import, reloading the page etc. I didn't want to meddle with it for the POC. We could also combine both stores, to have a central interface for monsters and an authority for uuid.
    There's also the issue of workflow, when people don't reset but start changing the monster without signaling that they are working on a new monster.
  • I can have a look at IndexedDB. I would then recommend we replace all saving with IndexedDB (spells, current monster, archive, etc) depending on browser support (and maybe user preference?).
  • Confirm dialogs I will adjust, was too lazy to do that for the POC ;)
  • I already save create and update timestamps along with each monster in the archive. Nothing to do here :)

@ebshimizu
Copy link
Owner

ebshimizu commented Jan 7, 2025

indexedDB is available on all relevant browsers so that shouldn't be a problem. thinking about this a bit, I think we should actually treat these as "files" and let users specify a unique name for each of their monsters (easier to track that vs uuid + non unique monster name).

As for what the UX of that would look like, I'm thinking there are basically two states we could be in:

  • monster is not saved to archive
    • archive does not have a cached key
    • If user clicks save, we prompt for name (default to current monster name, confirm on overwrite), write to database, then cache the "currently open file name"
    • after save, we're in the "saved to archive" state
  • monster is saved to archive
    • archive store has a cached key (i.e. open file)
    • If user clicks save again, we update the database entry.
    • If user clicks "Save As..." we open the dialog that lets them specify a new file name, confirming overwrite if they don't change the monster name. Unsure where to put "save as" but might need to refactor the top right controls in to an actual "file" menu.
  • app moves to "not saved to archive" state when a reset happens or a load from file happens
  • archive's cached uuid should persist (in local storage, easy with quasar persistence)

Implementing the above doesn't require any changes to the monster store, but will require some changes to the actions that happen on load and on reset (which is fine). If none of this makes sense let me know; I can find some time to implement directly in this branch or can set up a branch in this repo for us to collab on.

Leave the data models for the other areas alone for now, once we have indexedDB from this feature I'll work on moving the other data over as needed. spells and templates should live in there for sure, current monster probably lives in localStorage still. but all of that is out of scope for this PR

@pvbergen
Copy link
Author

pvbergen commented Jan 8, 2025

Thanks for the write-up of a concept. It turns out to be quite similar to my thoughts on how the storage should work. I was under the impression that we could just switch the storage backend to IndexedBD with pinia. Having looked at it I now understand why you proposed Dexie.

I will work on implementing IndexedDB for the archive using uuids for the entries. And fix the confirmation dialogs as well 👍

@ebshimizu
Copy link
Owner

awesome, thanks! We could switch the entire backend to indexedDB with a pinia plugin, but i'd prefer to do that gradually :)
Let me know if you need any help with the implementation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants