Compare commits

..

2 commits

Author SHA1 Message Date
a932cccfc0 Add hook to script edit schedules in the client
All checks were successful
/ build (push) Successful in 1m56s
/ deploy (push) Has been skipped
Expose the schedules in the schedules store as the window global
owltideSchedules so that mass changes can easily be scripted by a
programmer.
2025-09-12 19:34:34 +02:00
56791609f4 Add override for the event name in timetable
Add timetableName field to events that override which name is shown in
the timetable in order to allow using a custom condensed title in the
timetable for short events.
2025-09-12 19:23:34 +02:00
7 changed files with 43 additions and 4 deletions

View file

@ -11,6 +11,12 @@
:after="event.name" :after="event.name"
:state :state
/> />
<DiffFieldString
title="Timetable Name"
:before="event.serverTimetableName"
:after="event.timetableName"
:state
/>
<DiffFieldString <DiffFieldString
title="Host" title="Host"
:before="event.serverHost" :before="event.serverHost"

View file

@ -9,6 +9,7 @@
<tr> <tr>
<th>id</th> <th>id</th>
<th>name</th> <th>name</th>
<th>timetableName</th>
<th>host</th> <th>host</th>
<th>notice</th> <th>notice</th>
<th>description</th> <th>description</th>
@ -32,6 +33,13 @@
v-model="event.name" v-model="event.name"
> >
</td> </td>
<td>
<input
type="text"
:disabled="!canEdit(event)"
v-model="event.timetableName"
>
</td>
<td> <td>
<input <input
type="text" type="text"
@ -83,6 +91,12 @@
v-model="newEventName" v-model="newEventName"
> >
</td> </td>
<td>
<input
type="text"
v-model="newEventShortName"
>
</td>
<td> <td>
<input <input
type="text" type="text"
@ -129,6 +143,7 @@
> >
<td>{{ event.id }}</td> <td>{{ event.id }}</td>
<td>{{ event.name }}</td> <td>{{ event.name }}</td>
<td>{{ event.timetableName }}</td>
<td>{{ event.host }}</td> <td>{{ event.host }}</td>
<td class="preWrap">{{ event.notice }}</td> <td class="preWrap">{{ event.notice }}</td>
<td class="preWrap">{{ event.description }}</td> <td class="preWrap">{{ event.description }}</td>
@ -157,6 +172,7 @@ function canEdit(event: ClientScheduleEvent) {
} }
const newEventName = ref(""); const newEventName = ref("");
const newEventShortName = ref("");
const newEventHost = ref(""); const newEventHost = ref("");
const newEventNotice = ref(""); const newEventNotice = ref("");
const newEventDescription = ref(""); const newEventDescription = ref("");
@ -178,6 +194,7 @@ function newEvent() {
schedule.value, schedule.value,
schedule.value.nextClientId--, schedule.value.nextClientId--,
newEventName.value, newEventName.value,
newEventShortName.value,
!newEventPublic.value, !newEventPublic.value,
newEventHost.value, newEventHost.value,
false, false,
@ -189,6 +206,7 @@ function newEvent() {
); );
schedule.value.events.add(event); schedule.value.events.add(event);
newEventName.value = ""; newEventName.value = "";
newEventShortName.value = "";
newEventHost.value = ""; newEventHost.value = "";
newEventNotice.value = ""; newEventNotice.value = "";
newEventDescription.value = ""; newEventDescription.value = "";

View file

@ -106,7 +106,7 @@
:title="cell.event?.name" :title="cell.event?.name"
> >
{{ cell.event?.notice ? "⚠️" : undefined }} {{ cell.event?.notice ? "⚠️" : undefined }}
{{ cell.event?.name }} {{ cell.event?.timetableName || cell.event?.name }}
</td> </td>
</tr> </tr>
</template> </template>

View file

@ -89,6 +89,7 @@ export type ApiScheduleEventSlot = z.infer<typeof apiScheduleEventSlotSchema>;
export const apiScheduleEventSchema = defineApiEntity({ export const apiScheduleEventSchema = defineApiEntity({
name: z.string(), name: z.string(),
timetableName: z.optional(z.string()),
crew: z.optional(z.boolean()), crew: z.optional(z.boolean()),
host: z.optional(z.string()), host: z.optional(z.string()),
cancelled: z.optional(z.boolean()), cancelled: z.optional(z.boolean()),

View file

@ -19,6 +19,10 @@ export const useSchedulesStore = defineStore("schedules", () => {
pendingSyncs: ref<Map<number, SyncOperation>>(new Map()), pendingSyncs: ref<Map<number, SyncOperation>>(new Map()),
}; };
/* Expose schedules to the console on the client to make it easy to inspect and do scripted modifications. */
if (import.meta.client)
(window as any).owltideSchedules = state.schedules;
const getters = { const getters = {
activeSchedule: computed(() => { activeSchedule: computed(() => {
if (state.activeScheduleId.value === undefined) if (state.activeScheduleId.value === undefined)

View file

@ -21,10 +21,10 @@ function fixtureClientSchedule(multiSlot = false) {
const events = [ const events = [
new ClientScheduleEvent( new ClientScheduleEvent(
1, now, false, "Up", false, "", false, "", "What's Up?", 0, new Set(multiSlot ? [1, 2] : [1]), 1, now, false, "Up", "", false, "", false, "", "What's Up?", 0, new Set(multiSlot ? [1, 2] : [1]),
), ),
new ClientScheduleEvent( new ClientScheduleEvent(
2, now, false, "Down", false, "", false, "", "", 0, new Set(multiSlot ? [] : [2]), 2, now, false, "Down", "", false, "", false, "", "", 0, new Set(multiSlot ? [] : [2]),
), ),
]; ];
const eventSlots = idMap([ const eventSlots = idMap([
@ -174,7 +174,7 @@ describe("class ClientSchedule", () => {
], ],
[ [
"event", "event",
(schedule) => ClientScheduleEvent.create(schedule, 3, "New location", false, "", false, "", "", 0, new Set(), { zone, locale }) (schedule) => ClientScheduleEvent.create(schedule, 3, "New location", "", false, "", false, "", "", 0, new Set(), { zone, locale })
], ],
[ [
"role", "role",

View file

@ -133,6 +133,7 @@ export class ClientScheduleLocation extends ClientEntity<ApiScheduleLocation> {
export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> { export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
schedule!: ClientSchedule; schedule!: ClientSchedule;
serverName: string; serverName: string;
serverTimetableName: string;
serverCrew: boolean; serverCrew: boolean;
serverHost: string; serverHost: string;
serverCancelled: boolean; serverCancelled: boolean;
@ -146,6 +147,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
updatedAt: DateTime, updatedAt: DateTime,
deleted: boolean, deleted: boolean,
public name: string, public name: string,
public timetableName: string,
public crew: boolean, public crew: boolean,
public host: string, public host: string,
public cancelled: boolean, public cancelled: boolean,
@ -156,6 +158,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
) { ) {
super(id, updatedAt, deleted); super(id, updatedAt, deleted);
this.serverName = name; this.serverName = name;
this.serverTimetableName = timetableName;
this.serverCrew = crew; this.serverCrew = crew;
this.serverHost = host; this.serverHost = host;
this.serverCancelled = cancelled; this.serverCancelled = cancelled;
@ -173,6 +176,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
return ( return (
super.isModified() super.isModified()
|| this.name !== this.serverName || this.name !== this.serverName
|| this.timetableName !== this.serverTimetableName
|| this.crew !== this.serverCrew || this.crew !== this.serverCrew
|| this.host !== this.serverHost || this.host !== this.serverHost
|| this.cancelled !== this.serverCancelled || this.cancelled !== this.serverCancelled
@ -191,6 +195,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
this.updatedAt = this.serverUpdatedAt;; this.updatedAt = this.serverUpdatedAt;;
this.deleted = this.serverDeleted;; this.deleted = this.serverDeleted;;
this.name = this.serverName; this.name = this.serverName;
this.timetableName = this.serverTimetableName;
this.crew = this.serverCrew; this.crew = this.serverCrew;
this.host = this.serverHost; this.host = this.serverHost;
this.cancelled = this.serverCancelled; this.cancelled = this.serverCancelled;
@ -210,6 +215,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
schedule: ClientSchedule, schedule: ClientSchedule,
id: Id, id: Id,
name: string, name: string,
timetableName: string,
crew: boolean, crew: boolean,
host: string, host: string,
cancelled: boolean, cancelled: boolean,
@ -224,6 +230,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
DateTime.fromMillis(ClientEntity.newEntityMillis, opts), DateTime.fromMillis(ClientEntity.newEntityMillis, opts),
false, false,
name, name,
timetableName,
crew, crew,
host, host,
cancelled, cancelled,
@ -245,6 +252,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
DateTime.fromISO(api.updatedAt, opts), DateTime.fromISO(api.updatedAt, opts),
api.deleted ?? false, api.deleted ?? false,
api.name, api.name,
api.timetableName ?? "",
api.crew ?? false, api.crew ?? false,
api.host ?? "", api.host ?? "",
api.cancelled ?? false, api.cancelled ?? false,
@ -263,6 +271,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
this.serverUpdatedAt = DateTime.fromISO(api.updatedAt, opts); this.serverUpdatedAt = DateTime.fromISO(api.updatedAt, opts);
this.serverDeleted = false; this.serverDeleted = false;
this.serverName = api.name; this.serverName = api.name;
this.serverTimetableName = api.timetableName ?? "";
this.serverCrew = api.crew ?? false; this.serverCrew = api.crew ?? false;
this.serverHost = api.host ?? ""; this.serverHost = api.host ?? "";
this.serverCancelled = api.cancelled ?? false; this.serverCancelled = api.cancelled ?? false;
@ -287,6 +296,7 @@ export class ClientScheduleEvent extends ClientEntity<ApiScheduleEvent> {
id: this.id, id: this.id,
updatedAt: toIso(this.updatedAt), updatedAt: toIso(this.updatedAt),
name: this.name, name: this.name,
timetableName: this.timetableName || undefined,
crew: this.crew || undefined, crew: this.crew || undefined,
host: this.host || undefined, host: this.host || undefined,
cancelled: this.cancelled || undefined, cancelled: this.cancelled || undefined,