diff --git a/generate_api_types.sh b/generate_api_types.sh new file mode 100755 index 0000000..79cf932 --- /dev/null +++ b/generate_api_types.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +npx openapi-typescript http://localhost:8000/api/openapi.json --output src/apiScheme.ts diff --git a/src/apiScheme.ts b/src/apiScheme.ts new file mode 100644 index 0000000..539ddef --- /dev/null +++ b/src/apiScheme.ts @@ -0,0 +1,516 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/user/": { + /** Returns an array of all users sorted by the given sort field and ordering */ + get: operations["get_all_users"]; + /** Returns the created user */ + post: operations["add_user"]; + }; + "/user/{id}": { + /** Returns a single user by id */ + get: operations["get_user"]; + delete: operations["delete_user"]; + }; + "/user/{id}/score": { + /** Returns the score of a single user by id */ + get: operations["get_score"]; + post: operations["set_score"]; + }; + "/event/": { + /** Returns all events */ + get: operations["get_all_events"]; + /** + * If an `id` is supplied, it will be replaced by a randomly generated one. + * + * Returns the created event. + */ + post: operations["create_event"]; + }; + "/event/{id}/stop": { + /** This will conclude the event, apply the outcome to the users and return the outcome. */ + post: operations["stop_event"]; + }; + "/event/{id}": { + /** Returns the event with the given id */ + get: operations["get_event"]; + /** Update the supplied values in the event with the given id. The `id` of an event cannot be changed and `concluded` will always be false. */ + post: operations["update_event"]; + }; + "/event/{id}/outcome": { + /** Returns the outcome of an event. */ + get: operations["event_outcome"]; + }; +} + +export interface components { + schemas: { + /** + * User + * @description A user that represents a person participating in the LAN party + */ + User: { + /** @description Name of the user */ + name: string; + /** + * Format: int64 + * @description Score of the user + */ + score: number; + /** @description Unique identifier of the user */ + id: string; + }; + /** + * UserSort + * @description Field used to sort users + * @enum {string} + */ + UserSort: "score" | "name" | "id"; + /** + * Ordering + * @description Ordering of data in an array, ascending or descending + * @enum {string} + */ + Ordering: "desc" | "asc"; + /** + * Event + * @description An event in which participants can win or lose points + */ + Event: { + /** + * @description Unique identifier of the event. This will be randomly generated and cannot be modified. + * @default 6dcf4a26-87fe-4a43-be93-f315527d104a + */ + id?: string; + /** + * @description Has this event concluded? + * @default false + */ + concluded?: boolean; + /** + * @description Name of the event + * @default + */ + name?: string; + /** + * @description Description of the event + * @default + */ + description?: string; + /** @description Event type */ + event_type: components["schemas"]["EventType"]; + }; + /** + * EventType + * @description An enumeration of event types + */ + EventType: + | { + Test: components["schemas"]["Test"]; + } + | { + TeamGame: components["schemas"]["TeamGame"]; + } + | { + FreeForAllGame: components["schemas"]["FreeForAllGame"]; + }; + Test: { + /** Format: int64 */ + num_players: number; + }; + TeamGame: { + /** @description Map of teams with a name as key and an array of players as value */ + teams: { [key: string]: string[] }; + /** @description Ranking of participants by user id or team name (first element is first place, second element is second place, etc.) */ + ranking?: components["schemas"]["FreeForAllGameRanking"] | null; + /** @description Array of user ids that participate in the game */ + participants: string[]; + /** + * @description Rewards for winning the game (first element for first place, second element for second place, etc.) + * @example [ + * 10, + * 7, + * 5, + * 3, + * 2, + * 1 + * ] + */ + win_rewards: number[]; + /** + * @description Rewards for losing the game (first element for last place, second element for second to last place, etc.) + * @example [ + * -3, + * -2, + * -1 + * ] + */ + lose_rewards: number[]; + }; + FreeForAllGameRanking: + | { + Ranking: string[]; + } + | { + Scores: { [key: string]: number }; + }; + FreeForAllGame: { + /** @description Ranking of participants by user id or team name (first element is first place, second element is second place, etc.) */ + ranking?: components["schemas"]["FreeForAllGameRanking"] | null; + /** @description Array of user ids that participate in the game */ + participants: string[]; + /** + * @description Rewards for winning the game (first element for first place, second element for second place, etc.) + * @example [ + * 10, + * 7, + * 5, + * 3, + * 2, + * 1 + * ] + */ + win_rewards: number[]; + /** + * @description Rewards for losing the game (first element for last place, second element for second to last place, etc.) + * @example [ + * -3, + * -2, + * -1 + * ] + */ + lose_rewards: number[]; + }; + /** + * EventSpec + * @description A specification of an event + */ + EventSpec: { + name: string; + description: string; + event_type: components["schemas"]["EventTypeSpec"]; + }; + /** + * EventTypeSpec + * @description A specification of an event type + */ + EventTypeSpec: + | { + Test: components["schemas"]["TestSpec"]; + } + | { + TeamGame: components["schemas"]["TeamGameSpec"]; + } + | { + FreeForAllGame: components["schemas"]["FreeForAllGameSpec"]; + }; + TestSpec: { + /** Format: int64 */ + num_players: number; + }; + TeamGameSpec: { + /** @description Map of teams with a name as key and an array of players as value */ + teams: { [key: string]: string[] }; + /** + * @description Rewards for winning the game (first element for first place, second element for second place, etc.) + * @example [ + * 10, + * 7, + * 5, + * 3, + * 2, + * 1 + * ] + */ + win_rewards: number[]; + /** + * @description Rewards for losing the game (first element for last place, second element for second to last place, etc.) + * @example [ + * -3, + * -2, + * -1 + * ] + */ + lose_rewards: number[]; + }; + FreeForAllGameSpec: { + /** @description Array of user ids that participate in the game */ + participants: string[]; + /** + * @description Rewards for winning the game (first element for first place, second element for second place, etc.) + * @example [ + * 10, + * 7, + * 5, + * 3, + * 2, + * 1 + * ] + */ + win_rewards: number[]; + /** + * @description Rewards for losing the game (first element for last place, second element for second to last place, etc.) + * @example [ + * -3, + * -2, + * -1 + * ] + */ + lose_rewards: number[]; + }; + EventOutcome: { + points: { [key: string]: number }; + }; + /** + * EventUpdate + * @description An update that can be applied to an event + */ + EventUpdate: + | { + Test: components["schemas"]["TestUpdate"]; + } + | { + TeamGame: components["schemas"]["TeamGameUpdate"]; + } + | { + FreeForAllGame: components["schemas"]["FreeForAllGameUpdate"]; + }; + TestUpdate: { + win_game: boolean; + }; + TeamGameUpdate: Partial & + Partial; + TeamGameUpdateInner: + | { + SetTeam: { + team: string; + members: string[]; + }; + } + | { + RemoveTeam: string; + }; + TeamGameFfaInheritedUpdate: Partial< + components["schemas"]["FreeForAllGameUpdateRanking"] + > & + Partial; + FreeForAllGameUpdateRanking: + | { + SetRanking: components["schemas"]["FreeForAllGameRanking"]; + } + | { + ScoreDelta: { [key: string]: number }; + }; + FreeForAllGameUpdateRewards: + | { + SetWinRewards: number[]; + } + | { + SetLoseRewards: number[]; + }; + FreeForAllGameUpdate: Partial< + components["schemas"]["FreeForAllGameUpdateRanking"] + > & + Partial & + Partial; + FreeForAllGameUpdateParticipants: + | { + SetParticipants: string[]; + } + | { + AddParticipant: string; + } + | { + RemoveParticipant: string; + }; + }; +} + +export interface operations { + /** Returns an array of all users sorted by the given sort field and ordering */ + get_all_users: { + parameters: { + query: { + sort?: components["schemas"]["UserSort"] | null; + order?: components["schemas"]["Ordering"] | null; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["User"][]; + }; + }; + }; + }; + /** Returns the created user */ + add_user: { + responses: { + 201: { + content: { + "application/json": components["schemas"]["User"]; + }; + }; + }; + requestBody: { + content: { + "application/json": string; + }; + }; + }; + /** Returns a single user by id */ + get_user: { + parameters: { + path: { + id: string; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["User"]; + }; + }; + }; + }; + delete_user: { + parameters: { + path: { + id: string; + }; + }; + responses: { + default: unknown; + }; + }; + /** Returns the score of a single user by id */ + get_score: { + parameters: { + path: { + id: string; + }; + }; + responses: { + 200: { + content: { + "application/json": number; + }; + }; + }; + }; + set_score: { + parameters: { + path: { + id: string; + }; + }; + responses: { + default: unknown; + }; + requestBody: { + content: { + "application/json": number; + }; + }; + }; + /** Returns all events */ + get_all_events: { + parameters: { + query: { + concluded?: boolean | null; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["Event"][]; + }; + }; + }; + }; + /** + * If an `id` is supplied, it will be replaced by a randomly generated one. + * + * Returns the created event. + */ + create_event: { + responses: { + 200: { + content: { + "application/json": components["schemas"]["Event"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["EventSpec"]; + }; + }; + }; + /** This will conclude the event, apply the outcome to the users and return the outcome. */ + stop_event: { + parameters: { + path: { + id: string; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["EventOutcome"]; + }; + }; + }; + }; + /** Returns the event with the given id */ + get_event: { + parameters: { + path: { + id: string; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["Event"]; + }; + }; + }; + }; + /** Update the supplied values in the event with the given id. The `id` of an event cannot be changed and `concluded` will always be false. */ + update_event: { + parameters: { + path: { + id: string; + }; + }; + responses: { + default: unknown; + }; + requestBody: { + content: { + "application/json": components["schemas"]["EventUpdate"]; + }; + }; + }; + /** Returns the outcome of an event. */ + event_outcome: { + parameters: { + path: { + id: string; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["EventOutcome"]; + }; + }; + }; + }; +} + +export interface external {} diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index f90dc54..f31c20f 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -1 +1,49 @@ -

Events

+ + + + + +
+ {#if loading === true} +
+ +
+ {/if} + {#each events as event, i} +
+ openedEvent = i} /> +
+ {/each} +
diff --git a/src/routes/events/AutoDisplay.svelte b/src/routes/events/AutoDisplay.svelte new file mode 100644 index 0000000..ea3978d --- /dev/null +++ b/src/routes/events/AutoDisplay.svelte @@ -0,0 +1,27 @@ + + + + {#each Object.entries(object) as [key, value]} + {#if value} +

{name(key)}

+ {#if typeof value === 'object'} + + {:else} + {value} + {/if} + {/if} + {/each} +
diff --git a/src/routes/events/Block.svelte b/src/routes/events/Block.svelte new file mode 100644 index 0000000..cb0deaa --- /dev/null +++ b/src/routes/events/Block.svelte @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/routes/events/Event.svelte b/src/routes/events/Event.svelte new file mode 100644 index 0000000..4d3eecd --- /dev/null +++ b/src/routes/events/Event.svelte @@ -0,0 +1,19 @@ + + + + + +

{event.name} ({event.id}): {event.description}

+ +{#if 'FreeForAllGame' in event.event_type} + {event.event_type['FreeForAllGame'].participants} +{/if} diff --git a/src/routes/events/EventCard.svelte b/src/routes/events/EventCard.svelte new file mode 100644 index 0000000..57f64d5 --- /dev/null +++ b/src/routes/events/EventCard.svelte @@ -0,0 +1,33 @@ + + + + + +
+

{event.name} [{Object.keys(event.event_type)[0]}]

+

{event.id}

+ +

{event.description}

+ + {#if open} +
+ {#if 'FreeForAllGame' in event.event_type} + {@const et = event.event_type['FreeForAllGame']} + + {:else if 'TeamGame' in event.event_type} + {@const et = event.event_type['TeamGame']} + + {/if} +
+ {/if} +
diff --git a/src/routes/events/FreeForAllGame.svelte b/src/routes/events/FreeForAllGame.svelte new file mode 100644 index 0000000..a2fc105 --- /dev/null +++ b/src/routes/events/FreeForAllGame.svelte @@ -0,0 +1,36 @@ + + + + + + + diff --git a/src/routes/events/TeamGame.svelte b/src/routes/events/TeamGame.svelte new file mode 100644 index 0000000..80962ec --- /dev/null +++ b/src/routes/events/TeamGame.svelte @@ -0,0 +1,11 @@ + + + + +{event.participants}