I hate frontend

This commit is contained in:
Daan Vanoverloop 2022-09-02 18:19:24 +02:00
parent 7e6daf94cc
commit 6ae3cfe0d8
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
9 changed files with 697 additions and 1 deletions

3
generate_api_types.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
npx openapi-typescript http://localhost:8000/api/openapi.json --output src/apiScheme.ts

516
src/apiScheme.ts Normal file
View File

@ -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<components["schemas"]["TeamGameUpdateInner"]> &
Partial<components["schemas"]["TeamGameFfaInheritedUpdate"]>;
TeamGameUpdateInner:
| {
SetTeam: {
team: string;
members: string[];
};
}
| {
RemoveTeam: string;
};
TeamGameFfaInheritedUpdate: Partial<
components["schemas"]["FreeForAllGameUpdateRanking"]
> &
Partial<components["schemas"]["FreeForAllGameUpdateRewards"]>;
FreeForAllGameUpdateRanking:
| {
SetRanking: components["schemas"]["FreeForAllGameRanking"];
}
| {
ScoreDelta: { [key: string]: number };
};
FreeForAllGameUpdateRewards:
| {
SetWinRewards: number[];
}
| {
SetLoseRewards: number[];
};
FreeForAllGameUpdate: Partial<
components["schemas"]["FreeForAllGameUpdateRanking"]
> &
Partial<components["schemas"]["FreeForAllGameUpdateRewards"]> &
Partial<components["schemas"]["FreeForAllGameUpdateParticipants"]>;
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 {}

View File

@ -1 +1,49 @@
<h1>Events</h1>
<script context="module" lang="ts">
import type { components } from "../../apiScheme";
type Event = components["schemas"]["Event"];
</script>
<script lang="ts">
import { onMount } from "svelte";
import Button from "../../Button.svelte";
import Loading from "../../Loading.svelte";
import { apiRequest } from "../../util";
import EventCard from "./EventCard.svelte";
let events: Event[] = [];
let loading: boolean = false;
let openedEvent: number | undefined;
const loadEvents = async () => {
loading = true;
let response = await apiRequest('GET', '/event');
if (response.status == 200) {
events = await response.json();
} else {
console.error(`Request failed: got code ${response.status}, expected 200`);
}
loading = false;
};
onMount(async () => {
await loadEvents();
});
</script>
<div class="max-w-7xl mx-auto">
{#if loading === true}
<div class="grid place-items-center">
<Loading />
</div>
{/if}
{#each events as event, i}
<div class="py-2">
<EventCard {event} open={openedEvent === i} on:click={() => openedEvent = i} />
</div>
{/each}
</div>

View File

@ -0,0 +1,27 @@
<script lang="ts">
import Block from "./Block.svelte";
import AutoDisplay from "./AutoDisplay.svelte";
export let object: Object;
const titleCase = (s: string) => s.replace(/^_*(.)|_+(.)/g, (_s, c, d) => c ? c.toUpperCase() : ' ' + d.toUpperCase())
const name = (key: string) => {
switch (key) {
default: return titleCase(key);
}
};
</script>
<Block>
{#each Object.entries(object) as [key, value]}
{#if value}
<p>{name(key)}</p>
{#if typeof value === 'object'}
<AutoDisplay object={value} />
{:else}
{value}
{/if}
{/if}
{/each}
</Block>

View File

@ -0,0 +1,3 @@
<div class="px-3 py-3 rounded-lg border-solid border-gray-800 border-2 my-3">
<slot />
</div>

View File

@ -0,0 +1,19 @@
<script context="module" lang="ts">
import type { components } from "../../apiScheme";
type Event = components["schemas"]["Event"];
</script>
<script lang="ts">
import Button from "../../Button.svelte";
import { apiRequest } from "../../util";
export let event: Event;
</script>
<p>{event.name} ({event.id}): {event.description}</p>
{#if 'FreeForAllGame' in event.event_type}
{event.event_type['FreeForAllGame'].participants}
{/if}

View File

@ -0,0 +1,33 @@
<script context="module" lang="ts">
import type { components } from "../../apiScheme";
type Event = components["schemas"]["Event"];
</script>
<script lang="ts">
import TeamGame from "./TeamGame.svelte";
import FreeForAllGame from "./FreeForAllGame.svelte";
export let event: Event;
export let open: boolean = false;
</script>
<div class="bg-gray-800 px-5 py-5 rounded-lg" on:click>
<p class="text-xl font-bold">{event.name} <span class="text-sm font-normal">[{Object.keys(event.event_type)[0]}]</span></p>
<p class="text-sm font-mono">{event.id}</p>
<p>{event.description}</p>
{#if open}
<div class="bg-gray-700 px-3 py-3 rounded-lg mt-5">
{#if 'FreeForAllGame' in event.event_type}
{@const et = event.event_type['FreeForAllGame']}
<FreeForAllGame event={et} />
{:else if 'TeamGame' in event.event_type}
{@const et = event.event_type['TeamGame']}
<TeamGame event={et} />
{/if}
</div>
{/if}
</div>

View File

@ -0,0 +1,36 @@
<script context="module" lang="ts">
import type { components } from "../../apiScheme";
type EventType = components["schemas"]["FreeForAllGame"];
</script>
<script lang="ts">
import AutoDisplay from "./AutoDisplay.svelte";
import Block from "./Block.svelte";
export let event: EventType;
</script>
<AutoDisplay object={event} />
<!--
<Block>
<p>Participants</p>
<Block>
{#each event.participants as participant}
<p>{participant}</p>
{/each}
</Block>
<p>Rewards</p>
<Block>
<p>Win</p>
<Block>
<p>{event.win_rewards}</p>
</Block>
<p>Lose</p>
<Block>
<p>{event.lose_rewards}</p>
</Block>
</Block>
</Block>
-->

View File

@ -0,0 +1,11 @@
<script context="module" lang="ts">
import type { components } from "../../apiScheme";
type TeamGame = components["schemas"]["TeamGame"];
</script>
<script lang="ts">
export let event: TeamGame;
</script>
{event.participants}