Commit graph

188 commits

Author SHA1 Message Date
985b8e0950 Refactor base types for entities and tombstones
Rename the base Entity type to ApiEntity, and the base EntityToombstone
to ApiTombstone to better reflect the reality that its only used in the
API interface and that the client and server types uses its own base if
any.

Remove EntityLiving and pull EntityTombstone out of of the base entity
type so that the types based on ApiEntity are always living entities and
if it's possible for it to contain tombstone this will be explicitly
told with the type including a union with ApiTombstone.

Refactor the types of the ClientEntity and ClientMap to better reflect
the types of the entities it stores and converts to/from.
2025-06-24 15:19:11 +02:00
e3ff872b5c Refactor ClientSchedule to mutable types
All checks were successful
/ build (push) Successful in 1m30s
/ deploy (push) Successful in 16s
Use a single mutable location, event, slot, etc, for each unique
resource that keeps track of the local editable client copy and
the server copy of the data contained in it.

This makes it much simpler to update these data structures as I can take
advantage of the v-model bindings in Vue.js and work with the system
instead of against it.
2025-06-24 00:07:18 +02:00
d48fb035b4 Remove type from Api serialisation of ClientMap
All checks were successful
/ build (push) Successful in 1m34s
/ deploy (push) Successful in 16s
Move the logic that converts the EntityClass of a map to a string and
then back into the class to the payload plugin in order to avoid a
circular dependency where the ClientMap needs to know the entity classes
and the entity classes needs to know the ClientMap.

The only place that doesn't know the type of the entities stored in the
client map is the payload reviver, so it makes sense to keep this logic
contained to the payload plugin.
2025-06-23 18:17:23 +02:00
930d93a95f Fix typo in deleteDatabase function 2025-06-23 12:55:06 +02:00
b1053a95ba Fix import statements
Remove unused or unneeded imports and change imports of luxon APIs to
use the wrapper.
2025-06-23 12:54:09 +02:00
87525a6ef5 Add admin page that can edit users
All checks were successful
/ build (push) Successful in 1m30s
/ deploy (push) Successful in 16s
Add admin page that's only accessible to admins with a listing of users
and the ability to edit the access types of those users.
2025-06-23 00:28:59 +02:00
3be7f8be05 Refactor user storage and update
Rename accounts to users to be consistent with the new naming scheme
where account only referes to the logged in user of the session and
implement live updates of users via a user store which listens for
updates from the event stream.
2025-06-23 00:28:58 +02:00
6336ccdb96 Implement mutable mapping for client entities
Create a simple Map like class for storing and keeping track of client
entities that are synced from the server and have local editable state.
This will form the basis for storing entities on the client and should
replace the immutable concept used be the ClientSchedule class.
2025-06-23 00:28:58 +02:00
5edea4dd72 Implement ClientUser based on a new concept
Create a new mutable ClientEntity type and implement ClientUser on top
of it. The mutable concept is intended to replace the immutable concept
used by the ClientSchedule entities as updating immutable types in a
deep interconnected structure is a lot of hassle for little benefit.
2025-06-23 00:28:58 +02:00
ebf7bdcc9c Add line indicating now to Timetable
All checks were successful
/ build (push) Successful in 1m33s
/ deploy (push) Successful in 16s
Add a red vertical line indicated the current time and date in the
timetable with the label "now" on top of it.
2025-06-18 18:17:03 +02:00
bea8e77742 Shift hour display to be on the lines
The hour headers indicate the time on the left line of the cell, this
makes them confusing to read. Shift the displayed hour to be in the
middle of the left line of the cell so that it is clear which line is
the start of which hour.
2025-06-18 15:13:18 +02:00
a087172d39 Add vue-tsc for running TypeScript typechecks
All checks were successful
/ build (push) Successful in 2m57s
/ deploy (push) Successful in 17s
The nuxi typecheck command requires vue-tsc to work.  Add it to the
project so the command doesn't ask to install it.
2025-06-18 01:02:58 +02:00
e821100987 Add back wrongly removed shiftSlotFilter 2025-06-18 01:00:51 +02:00
bfb9acaa78 Use a stable scroll gutter
All checks were successful
/ build (push) Successful in 1m32s
/ deploy (push) Successful in 16s
Prevent horizontal page shifts when switching tabs due to the scrollbar
changing visibility.
2025-06-18 00:24:51 +02:00
6ef3800a53 Organise edit page into tabs
Use tabs for the various sections on the edit page so that the schedule
timetable is more easily visible at the same time as the editable tables.
2025-06-18 00:24:45 +02:00
7a95d6c3c4 Use prefix notation for component names
Start component names with the kind of element it creates on the page
(button, input, table, card, etc), then follow it with an hierarchy like
set of parts describing what part of the system it operates on.

This makes related components stick together in the directory listing of
components and auto-complete work better.
2025-06-17 22:29:16 +02:00
f4f23e6c18 Validate timezone with normalizeZone
All checks were successful
/ build (push) Successful in 1m29s
/ deploy (push) Successful in 16s
Instead of constructing a new DateTime object and seeing if it
succeeded, validate the client's timezone selection using the
Info.normalizeZone utility function.  This prevents throwing an
unexpected error creating the DateTime object after the change
in e100555 to throw on invalid dates.
2025-06-14 19:26:58 +02:00
bb450fd583 Refactor to use ClientSchedule on client
Use the ClientSchedule data structure for deserialising and tracking
edit state on the client instead of trying to directly deal with the
ApiSchedule type which is not build for ease of edits or rendering.
2025-06-14 19:22:53 +02:00
ce9f758f84 Implement editing of slots in ClientSchedule
Implement tracking of time slots along with editing and restoration of
singularly edited time slots.  This provides a simpler interface to work
with when rendering tables of time slots that can be edited than
directly manipulating events and shifts containing an array of slots.
2025-06-14 19:12:31 +02:00
73bb12c104 Add payload plugin for ClientSchedule
All checks were successful
/ build (push) Successful in 1m29s
/ deploy (push) Successful in 16s
Add plugin to serialise ClientSchedule objects as JSON when it's passed
from the server to client on SSR requests.
2025-06-13 22:01:42 +02:00
fb7a60db28 Add per account locale setting
Add a per user account setting for the locale so that the server can
correctly render pages with localized time formatting.
2025-06-13 21:50:22 +02:00
fad1bb2482 Ignore updatedAt timestamp when comparing entities
All checks were successful
/ build (push) Successful in 1m28s
/ deploy (push) Successful in 16s
To determine if the entity received from the server is the same as the
entity the client has the equals method is use.  To avoid problems with
clients that have incorrect clocks the timestamp is overriden with the
server's time when the entities are saved on the server.

This means that the entities received back from the server when the
client saves will have different timestamps than what the client set.
Ignore the updatedAt timestamp when comparing entities for equality so
that the update logic correctly replaces entities that only differ by
the update timestamp.
2025-06-13 21:06:48 +02:00
8c63c1cfbb Fix sanity checks failing on deleted entities
If the event/shift that a location/role was referencing had been marked
for deletion the sanity check would incorrectly refuse to delete the
event/role.  Fix by ignoring deleted events/shifts.
2025-06-13 20:51:24 +02:00
61734d4152 Add editing of client schedule entities
Add utility methods to more easily edit the fields of a single entity in
the schedule, along with a modification flag and is modified utility to
check for changes having been made.
2025-06-13 20:49:04 +02:00
faffe48706 Use TypeScript private modifier for methods
The Vue Ref system and assiated proxies does not work with the native
EcmaScript private fields, replace them with the TypeScript access
modifiers which are regular fields under the hood.
2025-06-13 17:04:55 +02:00
e100555304 Implement ClientSchedule state tracking class
All checks were successful
/ build (push) Successful in 2m16s
/ deploy (push) Successful in 16s
Write the logic of keeping track of location modifications and applying
updates from the server into the ClientSchedule class.  This should
serve as the foundation for replacing the prototype in-component update
logic which have turned into an unmaintainable spagetti.
2025-06-12 21:48:50 +02:00
aa52a6c651 Setup vitest
Done according to https://nuxt.com/docs/getting-started/testing
2025-06-12 21:38:47 +02:00
75abd82f81 Workaround issue with VSCode Nuxtr
When the object passed to defineNuxtConfig contains logic for enable
devtools option the Nuxtr plugin annoyingly shows an endlessly spinning
orb on the statusline.
2025-06-12 14:01:50 +02:00
fe06d0d6bd Refactor API types and sync logic
All checks were successful
/ build (push) Successful in 2m5s
/ deploy (push) Successful in 16s
Rename and refactor the types passed over the API to be based on an
entity that's either living or a tombstone.  A living entity has a
deleted property that's either undefined or false, while a tombstone
has a deleted property set to true.  All entities have a numeric id
and an updatedAt timestamp.

To sync entities, an array of replacements are passed around. Living
entities are replaced with tombstones when they're deleted. And
tombstones are replaced with living entities when restored.
2025-06-11 21:05:17 +02:00
251e83f640 Rename AcountSession to ServerSession
All checks were successful
/ build (push) Successful in 1m12s
/ deploy (push) Successful in 16s
Start the work of clearly distingushing client side types, server side
types and types shared over the API by renaming "AccountSession" and
"Session" names used on the server to "ServerSession".
2025-06-09 16:51:05 +02:00
16191a8dd2 Add debug route to delete the database
All checks were successful
/ build (push) Successful in 1m15s
/ deploy (push) Successful in 16s
To simplify development add a debug route to delete the database content
so that it'll be re-generated to the demo schedule.
2025-05-31 23:10:25 +02:00
25793fecb8 Add DISABLE_DEV_TOOLS env to disable Nuxt dev tools
All checks were successful
/ build (push) Successful in 1m14s
/ deploy (push) Successful in 15s
The dev tools built into Nuxt take up way too much resources to run on
low end hardware.  Add config to disable it.
2025-05-31 22:14:06 +02:00
2cb56247be Fix interested state for anonymous accounts
The EventCard logic assume interestedIds not being present means the
account can't set events as interested.  Fix this logic by checking if
the account is valid instead and always have interestedIds present on
the account store.
2025-05-31 22:05:20 +02:00
04b9707272 Move /api/account to /api/auth/account
All checks were successful
/ build (push) Successful in 1m16s
/ deploy (push) Successful in 16s
An account refers to the user the active session is logged in as. As
such it doesn't make sense outside of the /auth API paths that deals
with the current authenticated user.  Move /api/account to
/api/auth/account to reflect this.
2025-05-31 21:44:19 +02:00
e7dc00db54 Remove old editing interface
All checks were successful
/ build (push) Successful in 1m13s
/ deploy (push) Successful in 15s
Remove broken placeholder event editing interface that did not take
account to access permissions or events having multiple solts.
2025-05-27 17:38:23 +02:00
8d0d2400d3 Include message and stack in error page if useful
Show the .message and .stack properties of the error object in the error
page if these contain any useful information.
2025-05-26 14:01:46 +02:00
e8ff87d507 Fetch session in authenticated middleware
All checks were successful
/ build (push) Successful in 1m19s
/ deploy (push) Successful in 16s
The authenticated middleware runs before the page content is rendered.
This means that it'll run before the session is fetched in app.vue on
pages that are protected by it on the first load.  Fetch the session in
the middleware so that it doesn't act before the session is initalized.
2025-05-26 13:58:47 +02:00
cf90de1aae Refactor event source and storage from useSchedule
Split up useSchedule into a useEventSource composable and a schedules
store for keeping track of the schedule updates.
2025-05-26 13:53:11 +02:00
68f731f094 Send keepalive as a comment
All checks were successful
/ build (push) Successful in 1m20s
/ deploy (push) Successful in 16s
Avoid invoking the event dispatching for keepalives.
2025-05-25 23:38:24 +02:00
ed67982ec0 Explicitly set locale to avoid hydration mismatch
Some functions in luxon default to the system's locale while other
functions default to "en-US".  Explicitly set the locale everywhere
the luxon objects are created to avoid possible mismatches and
unexpected behaviour should the system's locale be different.
2025-05-25 23:38:06 +02:00
e722876aae Use a pinia store to manage account state
All checks were successful
/ build (push) Successful in 3m29s
/ deploy (push) Successful in 47s
Refactor the existing scattered code dealing with the account state into
a pinia store.
2025-05-24 20:01:23 +02:00
fae8b4e2e4 Use a pinia store to manage session state
Replace the convoluted useAccountSession composable with a pinia store
that in addition allows for the consolidation of all session related
functions to grouped into one module.
2025-05-24 18:18:27 +02:00
c47452a8b4 Update secret name for deployment
All checks were successful
/ build (push) Successful in 1m13s
/ deploy (push) Successful in 16s
The service secret was renamed for consistency with the other secrets I
manage.
2025-05-23 21:56:56 +02:00
c7b4f5fa92 Render PushNotification on client only
All checks were successful
/ build (push) Successful in 1m52s
/ deploy (push) Successful in 15s
The push logic is only available on the client and causes hydration
mismatch when rendered on the server.
2025-05-23 21:35:19 +02:00
f2ab306338 Always await useAccountSession
If this is not done the session is not properly loaded during server
side rendering, making it possible for missmatch and bugs to happen.
2025-05-23 21:33:48 +02:00
7f3029aee8 Pass Set-Cookie header from session on page load
If a session is refreshed when accessed through /api/auth/session during
a SSR then the Set-Cookie header was lost.  Pass this along to the
client in this case to keep the session alive.
2025-05-23 21:32:20 +02:00
8329ff060b Update to nuxt 3.17.4 2025-05-23 21:28:58 +02:00
4444daaca9 Load secrets from files
All checks were successful
/ build (push) Successful in 1m8s
/ deploy (push) Successful in 16s
Putting secrets into environment variables is problematic due to them
being inherited by sub-processes, the ease as which these can be
leaked in logs, and the lack of support for loading secrets into
environment variables by systems such as systemd and docker.

Change the loading of secrets to be done by loading the content of a
file specified by an environment variable.
2025-05-20 00:43:29 +02:00
c9976af26b Include the name of the cookie in the signature
If a cookie is signed for one purpose, but the server also uses a
differently named signed cookie name for another purpose, then it's
possible for a malicious client to substitute the value of one signed
cookie with the value of another and have it pass the signature check.

Include the name of the cookie when computing the signature so that no
cookies signed for example for "user_session" can be used as a value for
a hypothetical "admin_session" cookie.
2025-05-20 00:36:10 +02:00
a16921f264 Read vapid subject from the environment
Load the contact details for push notifications from the
NUXT_VAPID_SUBJECT environment variable.
2025-05-20 00:25:28 +02:00