Compare commits

..

No commits in common. "85248e8c914d0ac8dc651fe2b9621d9b6125c870" and "8b5bb787641bdbf13e3692ea383ce3f5002984d6" have entirely different histories.

12 changed files with 60 additions and 263 deletions

15
.vscode/launch.json vendored
View File

@ -1,15 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Wails: Debug myproject",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/build/bin/vscode",
"preLaunchTask": "build",
"cwd": "${workspaceFolder}",
"env": {}
}
]
}

23
.vscode/tasks.json vendored
View File

@ -1,23 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"options": {
"cwd": "${workspaceFolder}"
},
"command": "go",
"args": [
"build",
"-tags",
"dev",
"-gcflags",
"all=-N -l",
"-o",
"build/bin/vscode"
],
}
]
}

107
app.go
View File

@ -2,11 +2,10 @@ package main
import ( import (
"context" "context"
"encoding/csv" "fmt"
"gegio-ue1/model" "gegio-ue1/model"
"os" "os"
"slices" "slices"
"strconv"
"github.com/wailsapp/wails/v2/pkg/runtime" "github.com/wailsapp/wails/v2/pkg/runtime"
"gorm.io/gorm" "gorm.io/gorm"
@ -38,7 +37,7 @@ func (a *App) GetGames() (gs []model.Game, err error) {
} }
func (a *App) GetTournaments() (ts []model.Tournament, err error) { func (a *App) GetTournaments() (ts []model.Tournament, err error) {
err = a.db.Preload("Game").Preload("WinnerParticipant").Find(&ts).Error err = a.db.Preload("Game").Find(&ts).Error
return return
} }
@ -93,39 +92,9 @@ func (a *App) ExportTournament(t model.Tournament) {
dirname, _ := os.UserHomeDir() dirname, _ := os.UserHomeDir()
str, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{DefaultDirectory: dirname, DefaultFilename: "tournament.csv"}) str, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{DefaultDirectory: dirname, DefaultFilename: "tournament.csv"})
if err != nil { if err != nil {
panic(err) fmt.Println(err)
}
file, err := os.Create(str)
if err != nil {
panic(err)
}
defer file.Close()
// Create a CSV writer
writer := csv.NewWriter(file)
defer writer.Flush()
var matches []model.Match
a.db.Where("tournament_id = ?", t.ID).Order("stage ASC").Order("`order` ASC").Preload("Participant1").Preload("Participant2").Preload("WinnerParticipant").Find(&matches)
// Write header
header := []string{"Stage", "Order", "Winner", "Looser"}
if err := writer.Write(header); err != nil {
panic(err)
}
for _, m := range matches {
record := []string{strconv.Itoa(m.Stage), strconv.Itoa(m.Order), m.WinnerParticipant.Name}
if m.WinnerParticipantID == m.Participant1ID {
record = append(record, m.Participant2.Name)
} else {
record = append(record, m.Participant1.Name)
}
if err := writer.Write(record); err != nil {
panic(err)
}
} }
println(str)
} }
@ -148,63 +117,15 @@ func (a *App) RemoveParticipantFromTournament(p model.Participant, t model.Tourn
} }
func (a *App) GetMatches(tID uint) [][]model.Match { func (a *App) GetMatches(tID uint) [][]model.Match {
rawMatches := make([]model.Match, 0) matches := make([][]model.Match, 0)
a.db.Preload("Participant1").Preload("Participant2").Preload("WinnerParticipant").Where("tournament_id = ?", tID).Find(&rawMatches) for {
slices.SortFunc(rawMatches, func(a model.Match, b model.Match) int { return a.Stage - b.Stage }) ms := make([]model.Match, 0)
if err := a.db.Where("tournament_id = ? AND stage = ?", tID, len(matches)).Find(&ms).Error; err != nil || len(ms) == 0 {
if len(rawMatches) < 1 { fmt.Println(ms)
return [][]model.Match{} fmt.Println(err)
return matches
}
slices.SortFunc(ms, func(a, b model.Match) int { return a.Order - b.Order })
matches = append(matches, ms)
} }
matches := make([][]model.Match, rawMatches[len(rawMatches)-1].Stage)
for _, match := range rawMatches {
matches[match.Stage-1] = append(matches[match.Stage-1], match)
}
return matches
}
func (a *App) CreateStage(tID uint) {
oldMatches := a.GetMatches(tID)
if len(oldMatches) < 1 {
return
}
participants := make([]model.Participant, 0, len(oldMatches[len(oldMatches)-1]))
for _, m := range oldMatches[len(oldMatches)-1] {
participants = append(participants, m.WinnerParticipant)
}
if len(participants) == 0 {
return
}
stage := oldMatches[len(oldMatches)-1][len(oldMatches[len(oldMatches)-1])-1].Stage + 1
matches := make([]model.Match, 0, len(participants)/2)
for i := range len(participants) / 2 {
matches = append(matches, model.Match{
TournamentID: tID,
Order: i,
Stage: stage,
Participant1ID: participants[i].ID,
Participant2ID: participants[i+len(participants)/2].ID,
})
}
if len(participants)%2 != 0 {
matches = append(matches, model.Match{
TournamentID: tID,
Order: len(participants)/2 + 1,
Stage: stage,
Participant1ID: participants[len(participants)-1].ID,
Participant2ID: participants[len(participants)-1].ID,
WinnerParticipantID: participants[len(participants)-1].ID,
})
}
a.db.Save(matches)
}
func (a *App) SaveMatch(m *model.Match) {
a.db.Save(m)
} }

View File

@ -13,7 +13,7 @@
Modal, Modal,
} from "flowbite-svelte"; } from "flowbite-svelte";
import TourCreator from "./TourCreator.svelte"; import TourCreator from "./TourCreator.svelte";
import { Link, navigate } from "svelte-routing"; import { Link } from "svelte-routing";
let thingsList: model.Tournament[] = $state([]); let thingsList: model.Tournament[] = $state([]);
let newThing: boolean = $state(false); let newThing: boolean = $state(false);
@ -43,15 +43,20 @@
<TableBodyCell> <TableBodyCell>
{t.Game.Name} {t.Game.Name}
</TableBodyCell> </TableBodyCell>
<TableBodyCell>{t.WinnerParticipant.Name}</TableBodyCell> <TableBodyCell>
{t.WinnierParticipant.Name}
</TableBodyCell>
<TableBodyCell> <TableBodyCell>
<Button onclick={() => navigate(`/tournament/${t.ID}`)}>View</Button> <Link class="text-primary-500 underline" to={`/tournament/${t.ID}`}
>Edit</Link
>
</TableBodyCell> </TableBodyCell>
</TableBodyRow> </TableBodyRow>
{/each} {/each}
</TableBody> </TableBody>
<div class="flex-row justify-evenly p-5"> <div class="flex-row justify-evenly p-5">
<Button>View</Button>
<Button on:click={(_) => (newThing = true)}>New Tournament</Button> <Button on:click={(_) => (newThing = true)}>New Tournament</Button>
</div> </div>
<Modal bind:open={newThing}> <Modal bind:open={newThing}>

View File

@ -1,49 +1,24 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { import {
CreateStage,
GetMatches, GetMatches,
GetTournament, GetTournament,
SaveMatch,
SaveTournament,
StartTournament, StartTournament,
} from "../../wailsjs/go/main/App"; } from "../../wailsjs/go/main/App";
import { model } from "../../wailsjs/go/models"; import { model } from "../../wailsjs/go/models";
import { import { Button, TabItem, Tabs } from "flowbite-svelte";
Button,
TabItem,
Table,
TableBody,
TableBodyCell,
TableBodyRow,
TableHead,
TableHeadCell,
Tabs,
Tooltip,
} from "flowbite-svelte";
let { tournamentID }: { tournamentID: number } = $props(); let { tournamentID }: { tournamentID: number } = $props();
let tournament: model.Tournament = $state(new model.Tournament()); let tournament: model.Tournament = $state(new model.Tournament());
let matches: model.Match[][] = $state([]); let matches: model.Match[][] = $state([]);
function saveMatch(m: model.Match): Promise<void> {
if (matches[matches.length - 1].length == 1) {
tournament.WinnerParticipant = m.WinnerParticipant;
SaveTournament(tournament).then(update);
}
return SaveMatch(m);
}
function update() { function update() {
GetTournament(tournamentID).then((t) => { GetTournament(tournamentID).then((t) => {
console.log(t);
tournament = t; tournament = t;
}); });
GetMatches(tournamentID).then((ms) => { GetMatches(tournamentID).then((ms) => (matches = ms));
console.log("ms:", ms);
matches = ms;
});
} }
$effect(update); $effect(update);
onMount(update); onMount(update);
@ -51,68 +26,14 @@
{#if tournament.TournamentState == 0} {#if tournament.TournamentState == 0}
<Button <Button
disabled={tournament.Participants.length < tournament.Size}
onclick={() => { onclick={() => {
StartTournament(tournament).then(update); StartTournament(tournament).then(update);
}}>Start</Button }}>Start</Button
> >
{#if tournament.Participants.length < tournament.Size}
<Tooltip>Tournament must be filled</Tooltip>
{/if}
{:else} {:else}
<Tabs> <Tabs>
{#each matches as ms, i} {#each matches as ms, i}
<TabItem open={i + 1 == matches.length} title={`Stage: ${i + 1}`}> <TabItem title={`Stage: ${i}`}></TabItem>
<Table>
<TableHead>
<TableHeadCell>Participant1</TableHeadCell>
<TableHeadCell>Participant2</TableHeadCell>
<TableHeadCell>Winner</TableHeadCell>
</TableHead>
<TableBody>
{#each ms as m}
<TableBodyRow class="h-20">
<TableBodyCell>
{m.Participant1.Name}
</TableBodyCell>
<TableBodyCell>
{m.Participant2.Name}
</TableBodyCell>
<TableBodyCell class="w-96">
{#if m.WinnerParticipant.Name == ""}
<div class="grid grid-cols-2 gap-5">
<Button
onclick={() => {
m.WinnerParticipant = m.Participant1;
saveMatch(m).then(update);
}}
>
{m.Participant1.Name}
</Button>
<Button
onclick={() => {
m.WinnerParticipant = m.Participant2;
saveMatch(m).then(update);
}}
>
{m.Participant2.Name}
</Button>
</div>
{:else}
{m.WinnerParticipant.Name}
{/if}
</TableBodyCell>
</TableBodyRow>
{/each}
</TableBody>
</Table>
</TabItem>
{/each} {/each}
{#if matches.length > 0 && matches[matches.length - 1].length > 1 && matches[matches.length - 1].reduce( (acc, m) => {
return acc && m.WinnerParticipant.Name != "";
}, )}
<Button onclick={() => CreateStage(tournamentID).then(update)}>new</Button
>
{/if}
</Tabs> </Tabs>
{/if} {/if}

View File

@ -67,6 +67,7 @@
<TableHeadCell>Name</TableHeadCell> <TableHeadCell>Name</TableHeadCell>
<TableHeadCell /> <TableHeadCell />
<TableHeadCell /> <TableHeadCell />
<TableHeadCell />
</TableHead> </TableHead>
<TableBody> <TableBody>
{#each participants as p} {#each participants as p}
@ -74,7 +75,7 @@
<TableBodyCell> <TableBodyCell>
{p.Name} {p.Name}
</TableBodyCell> </TableBodyCell>
<TableBodyCell class="w-6"> <TableBodyCell>
{#if tournament.Participants.find((pa) => pa.ID == p.ID)} {#if tournament.Participants.find((pa) => pa.ID == p.ID)}
<Button <Button
onclick={() => { onclick={() => {
@ -91,7 +92,7 @@
> >
{/if} {/if}
</TableBodyCell> </TableBodyCell>
<TableBodyCell class="w-6"> <TableBodyCell>
<Button onclick={() => DeleteParticipat(p).then(update)} <Button onclick={() => DeleteParticipat(p).then(update)}
>Delete</Button >Delete</Button
> >

View File

@ -26,11 +26,12 @@
</script> </script>
<form onsubmit={submit}> <form onsubmit={submit}>
<div class="m-5"> <div>
<Label>Title</Label> <Label>Title</Label>
<Input type="text" bind:value={tournament.Title} /> <Input type="text" bind:value={tournament.Title} />
</div> </div>
<div class="m-5"> <div>
e
<Label>Game</Label> <Label>Game</Label>
<Select <Select
items={games.map((g) => { items={games.map((g) => {
@ -39,11 +40,9 @@
bind:value={tournament.GameID} bind:value={tournament.GameID}
/> />
</div> </div>
<div class="m-5"> <div>
<Label>Size</Label> <Label>Size</Label>
<Input type="number" step="1" min="1" bind:value={tournament.Size} /> <Input type="number" step="1" min="1" bind:value={tournament.Size} />
</div> </div>
<div class="m-5"> <Button type="submit">Save</Button>
<Button type="submit">Save</Button>
</div>
</form> </form>

View File

@ -2,8 +2,6 @@
// This file is automatically generated. DO NOT EDIT // This file is automatically generated. DO NOT EDIT
import {model} from '../models'; import {model} from '../models';
export function CreateStage(arg1:number):Promise<void>;
export function DeleteParticipat(arg1:model.Participant):Promise<void>; export function DeleteParticipat(arg1:model.Participant):Promise<void>;
export function ExportTournament(arg1:model.Tournament):Promise<void>; export function ExportTournament(arg1:model.Tournament):Promise<void>;
@ -22,8 +20,6 @@ export function GetTournaments():Promise<Array<model.Tournament>>;
export function RemoveParticipantFromTournament(arg1:model.Participant,arg2:model.Tournament):Promise<void>; export function RemoveParticipantFromTournament(arg1:model.Participant,arg2:model.Tournament):Promise<void>;
export function SaveMatch(arg1:model.Match):Promise<void>;
export function SaveParticipant(arg1:model.Participant):Promise<void>; export function SaveParticipant(arg1:model.Participant):Promise<void>;
export function SaveTournament(arg1:model.Tournament):Promise<void>; export function SaveTournament(arg1:model.Tournament):Promise<void>;

View File

@ -2,10 +2,6 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT // This file is automatically generated. DO NOT EDIT
export function CreateStage(arg1) {
return window['go']['main']['App']['CreateStage'](arg1);
}
export function DeleteParticipat(arg1) { export function DeleteParticipat(arg1) {
return window['go']['main']['App']['DeleteParticipat'](arg1); return window['go']['main']['App']['DeleteParticipat'](arg1);
} }
@ -42,10 +38,6 @@ export function RemoveParticipantFromTournament(arg1, arg2) {
return window['go']['main']['App']['RemoveParticipantFromTournament'](arg1, arg2); return window['go']['main']['App']['RemoveParticipantFromTournament'](arg1, arg2);
} }
export function SaveMatch(arg1) {
return window['go']['main']['App']['SaveMatch'](arg1);
}
export function SaveParticipant(arg1) { export function SaveParticipant(arg1) {
return window['go']['main']['App']['SaveParticipant'](arg1); return window['go']['main']['App']['SaveParticipant'](arg1);
} }

View File

@ -54,8 +54,8 @@ export namespace model {
Game: Game; Game: Game;
Size: number; Size: number;
TournamentState: number; TournamentState: number;
WinnerParticipantID: number; WinnierParticipantID: number;
WinnerParticipant: Participant; WinnierParticipant: Participant;
Participants: Participant[]; Participants: Participant[];
Matches: Match[]; Matches: Match[];
@ -74,8 +74,8 @@ export namespace model {
this.Game = this.convertValues(source["Game"], Game); this.Game = this.convertValues(source["Game"], Game);
this.Size = source["Size"]; this.Size = source["Size"];
this.TournamentState = source["TournamentState"]; this.TournamentState = source["TournamentState"];
this.WinnerParticipantID = source["WinnerParticipantID"]; this.WinnierParticipantID = source["WinnierParticipantID"];
this.WinnerParticipant = this.convertValues(source["WinnerParticipant"], Participant); this.WinnierParticipant = this.convertValues(source["WinnierParticipant"], Participant);
this.Participants = this.convertValues(source["Participants"], Participant); this.Participants = this.convertValues(source["Participants"], Participant);
this.Matches = this.convertValues(source["Matches"], Match); this.Matches = this.convertValues(source["Matches"], Match);
} }
@ -160,8 +160,8 @@ export namespace model {
Participant1: Participant; Participant1: Participant;
Participant2ID: number; Participant2ID: number;
Participant2: Participant; Participant2: Participant;
WinnerParticipantID: number; WinnierParticipantID: number;
WinnerParticipant: Participant; WinnierParticipant: Participant;
static createFrom(source: any = {}) { static createFrom(source: any = {}) {
return new Match(source); return new Match(source);
@ -180,8 +180,8 @@ export namespace model {
this.Participant1 = this.convertValues(source["Participant1"], Participant); this.Participant1 = this.convertValues(source["Participant1"], Participant);
this.Participant2ID = source["Participant2ID"]; this.Participant2ID = source["Participant2ID"];
this.Participant2 = this.convertValues(source["Participant2"], Participant); this.Participant2 = this.convertValues(source["Participant2"], Participant);
this.WinnerParticipantID = source["WinnerParticipantID"]; this.WinnierParticipantID = source["WinnierParticipantID"];
this.WinnerParticipant = this.convertValues(source["WinnerParticipant"], Participant); this.WinnierParticipant = this.convertValues(source["WinnierParticipant"], Participant);
} }
convertValues(a: any, classs: any, asMap: boolean = false): any { convertValues(a: any, classs: any, asMap: boolean = false): any {

View File

@ -19,26 +19,26 @@ type Participant struct {
type Tournament struct { type Tournament struct {
gorm.Model gorm.Model
Title string Title string
GameID int GameID int
Game Game `gorm:"foreignKey:GameID"` Game Game `gorm:"foreignKey:GameID"`
Size int // number of prarticipants Size int // number of prarticipants
TournamentState int TournamentState int
WinnerParticipantID int WinnierParticipantID int
WinnerParticipant Participant `gorm:"foreignKey:WinnerParticipantID"` WinnierParticipant Participant `gorm:"foreignKey:WinnierParticipantID"`
Participants []*Participant `gorm:"many2many:partcipant_tournaments;"` Participants []*Participant `gorm:"many2many:partcipant_tournaments;"`
Matches []Match Matches []Match
} }
type Match struct { type Match struct {
gorm.Model gorm.Model
TournamentID uint TournamentID uint
Stage int Stage int
Order int Order int
Participant1ID uint Participant1ID uint
Participant1 Participant `gorm:"foreignKey:Participant1ID"` Participant1 Participant `gorm:"foreignKey:Participant1ID"`
Participant2ID uint Participant2ID uint
Participant2 Participant `gorm:"foreignKey:Participant2ID"` Participant2 Participant `gorm:"foreignKey:Participant2ID"`
WinnerParticipantID uint WinnierParticipantID uint
WinnerParticipant Participant `gorm:"foreignKey:WinnerParticipantID"` WinnierParticipant Participant `gorm:"foreignKey:WinnierParticipantID"`
} }

Binary file not shown.