From f3b5be675ac0f4ca8a2774f38a99a77a95acfa28 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Mon, 1 Jan 2001 00:00:00 +0000 Subject: [PATCH 1/8] Updated neujahr2026.md --- src/content/events/neujahr2026.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/events/neujahr2026.md b/src/content/events/neujahr2026.md index 354918c..e49f2d4 100644 --- a/src/content/events/neujahr2026.md +++ b/src/content/events/neujahr2026.md @@ -21,7 +21,7 @@ es ist wieder Zeit, das Jahr neigt sich dem Ende und damit ist es wieder Zeit f - Maße: **13x13x13** - Freiluftbrücken erlaubt -- Version 1.20 +- Version 1.21 - Jedes Team darf nur eine schematic einsenden. - Alle Eventschematics werden nach dem Event zu MiniWarGears From d1e889e2ff0302a99b4bf5b61bbe6dd2e6b6ccd8 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 2 Dec 2025 18:04:11 +0100 Subject: [PATCH 2/8] Add quickgear.md and megawargear.md translations for English --- src/content/rules/en/megawargear.md | 11 ++++++++++ src/content/rules/en/quickgear.md | 31 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/content/rules/en/megawargear.md create mode 100644 src/content/rules/en/quickgear.md diff --git a/src/content/rules/en/megawargear.md b/src/content/rules/en/megawargear.md new file mode 100644 index 0000000..c4d51e8 --- /dev/null +++ b/src/content/rules/en/megawargear.md @@ -0,0 +1,11 @@ +--- +translationKey: megawg +--- + +# MegaWarGear Ruleset + +For technical reasons MegaWarGear-Fights are held in version 1.12.2. +MegaWarGears provide the opportunity to build without limitations. +An elaborate design with defined shape is mandatory though (you may not just build some cube). +Besides the lack of limitations regarding dimensions and amounts, MegaWarGears are supposed to be similar to regular WarGears, in that endstone is the most resistant armoring block, dispensers should not contain TNT, etc. +Since this game-mode is not meant for serious competition, an approved MegaWarGear should be fine to release as a public. \ No newline at end of file diff --git a/src/content/rules/en/quickgear.md b/src/content/rules/en/quickgear.md new file mode 100644 index 0000000..3972ead --- /dev/null +++ b/src/content/rules/en/quickgear.md @@ -0,0 +1,31 @@ +--- +translationKey: qg +--- + +# QuickGear-Ruleset + +QuickGears are constructed in version 1.20. + +## Dimensions + +Max. 20 blocks deep (+ 1 block for design on each side) (22) +Max. 35 blocks wide (+ 1 block for design on each side) (37) +Max. 26 blocks high + +No block may leave a QuickGear. + +## Materials + +All blocks in a QuickGear must by destructible by TNT explosions (except for water). +There must not be any pre-installed TNT blocks in a QuickGear. +Blocks with inventories may only contain flowers, honey bottles and horse armor. +Dispensers may only individually contain one stack of fire charges or one stack of arrows (without effects). + +## Design + +A design is very welcome, but not required. + +## Bug-Using + +Primed TNT may only be created from TNT blocks that players have placed. +The duplication of TNT is prohibited. \ No newline at end of file From 2a2ee6701e483fa3ddf203a7f6f4ecfd4ec5fc05 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Thu, 4 Dec 2025 09:37:16 +0100 Subject: [PATCH 3/8] Add microwargear.md and miniwargear.md translations for English --- src/content/rules/en/microwargear.md | 135 +++++++++++++++++++++++ src/content/rules/en/miniwargear.md | 158 +++++++++++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 src/content/rules/en/microwargear.md create mode 100644 src/content/rules/en/miniwargear.md diff --git a/src/content/rules/en/microwargear.md b/src/content/rules/en/microwargear.md new file mode 100644 index 0000000..a3cd287 --- /dev/null +++ b/src/content/rules/en/microwargear.md @@ -0,0 +1,135 @@ +--- +translationKey: microwg +--- + +# MicroWarGear Ruleset + +MicroWargears are constructed in version 1.20. + +## Dimensions + +Max. 7 blocks deep +Max. 7 blocks wide +Max. 7 block high + +A MicroWarGear may extend at most 7 blocks into every direction. +Shield related technology may be activated from any place within the MicroWarGear. + +## Materials + +Blocks used in MicroWarGear construction must not exceed a blast resistance of 9. +Inventory blocks must not contain items other than flowers, honey bottles and horse armor. +Chests, shulker boxes and barrels may contain TNT. +Dispensers may only individually contain either one stack of fire charges or one stack of basic arrows. +No more than 8 dispensers may be installed. + +The following materials may not be used for construction: all saplings, minecraft:ice, nether portals, lava, waterlogged leaves and roots, TNT (pre-installed), any non-block entities. +Water may only be used within cannons and only to prevent damaging your gear. + +## Cannons + +Every MicroWarGear must have at least one functioning cannon. +A cannon is a continuous redstone contraption which is able to damage the opponent using primed TNT. +A TNT-cannon is the only place within a MicroWarGear where water may be placed and only if it does not leave the cannon or form water-shields. +Furthermore a cannon may not intentionally damage itself. +A cannon may at most shoot 8 projectiles at once. +Additionally, a single main-cannon can be installed, which may shoot up to 12 projectiles. + +## Command Bridge + +A MicroWarGear must contain a command bridge, either in the form of a clearly distinguishable room, open air command bridge or crawlspace command bridge. +The command bridge must be separated from the rest of the MicroWarGear by doors, fence gates, trapdoors or pistons. + +A command bridge must adhere to the following conditions: +- At least 25 m² (1 block = 1 meter) +- A window through which the opponent is visible directly (not required for open air command bridges) +- Controls for at least 2 headlights that are visible from the opponent's position +- These controls must save their state until manually activated again +- The command bridge must be the only place where dispensers may be activated, which aim at the opponent + +## Design + +MicroWarGears must have a visual design. +The outermost layer of a MicroWarGear must have a blast resistance of at most 6. +It is expected that there is a continuous design structure across the entire front of the MicroWarGear. +At least 2 different kinds of blocks must be used in a design (not counting redstone components). +A "continuous design structure" means, that no substantial surface areas have too little or no depth to them. +Depth variation may also be achieved using walls or stairs. + +## Bug-Using + +The duplication of any blocks or entities is forbidden. +Excessive use of blocks that are replaced by the tech hider is also forbidden. + +## Definitions + +### Projectile + +A projectile is any primed TNT entity, which leaves the extension limits of a MicroWarGear (7 blocks) towards the opponent. + +### Propellant + +A propellant is any primed TNT entity, which by exploding accellerates projectiles towards the opponent. +The propellant of any one cannon must only affect projectiles of that same cannon. + +## Hidden Blocks (Replaced with Endstone) + +- WATER +- NOTE_BLOCK +- POWERED_RAIL +- DETECTOR_RAIL +- PISTON +- PISTON_HEAD +- STICKY_PISTON +- TNT +- CHEST +- TRAPPED_CHEST +- REDSTONE_WIRE +- STONE_PRESSURE_PLATE +- IRON_DOOR +- OAK_PRESSURE_PLATE +- SPRUCE_PRESSURE_PLATE +- BIRCH_PRESSURE_PLATE +- JUNGLE_PRESSURE_PLATE +- ACACIA_PRESSURE_PLATE +- DARK_OAK_PRESSURE_PLATE +- REDSTONE_TORCH +- REDSTONE_WALL_TORCH +- REPEATER +- BREWING_STAND +- TRIPWIRE_HOOK +- TRIPWIRE +- HEAVY_WEIGHTED_PRESSURE_PLATE +- LIGHT_WEIGHTED_PRESSURE_PLATE +- COMPARATOR +- REDSTONE_BLOCK +- HOPPER +- ACTIVATOR_RAIL +- DROPPER +- SLIME_BLOCK +- OBSERVER +- HONEY_BLOCK +- LEVER +- SCULK_SENSOR +- POLISHED_BLACKSTONE_PRESSURE_PLATE +- MANGROVE_PRESSURE_PLATE +- CRIMSON_PRESSURE_PLATE +- WARPED_PRESSURE_PLATE + +## The Contents of the Following Blocks Are Also Hidden + +- SIGN +- DISPENSER +- CHEST +- TRAPPED_CHEST +- FURNACE +- BREWING_STAND +- HOPPER +- DROPPER +- SHULKER_BOX +- JUKEBOX +- COMPARATOR + +
+ +Whether or not a MicroWarGear is rules compliant is up to the examiners. diff --git a/src/content/rules/en/miniwargear.md b/src/content/rules/en/miniwargear.md new file mode 100644 index 0000000..63379fe --- /dev/null +++ b/src/content/rules/en/miniwargear.md @@ -0,0 +1,158 @@ +--- +translationKey: mwg +mode: MiniWarGear +--- + +# MiniWarGear-Ruleset + +MiniWarGears are constructed in version 1.20. + +## Dimensions + +- Max. 20 blocks deep (+ 1 block for design on each side) (22) +- Max. 35 blocks wide (+ 1 block for design on each side) (37) +- Max. 26 blocks high + +A MiniWarGear may extend at most 7 blocks into every direction. +All shield related technology may only be activated from within the command bridge. + +## Materials + +Blocks used for the construction of a MiniWarGear must not exceed a blast resistance of 9. +A maximum of 120 TNT may be pre-installed. +Inventory blocks must not contain items other than flowers, honey bottles or horse armor. +Dispensers may only individually contain either one stack of fire charges or one stack of basic arrows. +No more than 16 dispensers may be installed. + +The following materials may not be used for construction: all saplings, minecraft:ice, nether portals, lava, waterlogged leaves and roots, TNT (pre-installed), any non-block entities. +Water may only be used within cannons and only to prevent damaging your gear. + +## Cannons + +A cannon is a continuous redstone contraption which is able to damage the opponent using primed TNT. +A TNT-cannon is the only place within a MiniWarGear where water may be placed and only if it does not leave the cannon or form water-shields. +Furthermore a cannon may not intentionally damage itself. +A cannon may at most shoot 8 projectiles at once. +Additionally, a single main-cannon can be installed, which may shoot up to 12 projectiles. +The main-cannon must be a manual cannon. + +A MiniWarGear may be equipped with up to 9 cannons. +It is forbidden to try to pass off multiple cannons as a single one. +It is also forbidden to try to pass off a single cannon as multiple. +Whether or not this is the case is up to the examiners and fight-judges. + +Manual cannons are TNT-cannons, which require manual loading. +They may not be pre-loaded at the time of construction. +Furthermore manual cannons may fire up to three individual times after being loaded once. +All projectils of a manual cannon which is able to fire multiple times like this must be launched from the exact same launch-point. +That launch-point is defined by the first shot of a salve the cannon performs. + +Automatic cannons are TNT-cannons which can fire at least 5 individual times, without being manually loaded. +They must be pre-loaded at the time of construction. +To qualify for being allowed to be pre-loaded the cannon must fire at least 5 times. +All projectils of an automatic cannon must be launched from the exact same launch-point. +The first 5 shots of an automatic cannon must have the exact same number of projectiles. +After the 6th shot the amount of projectiles may decrease, and must not increase. +Between individual shots of an automatic cannon must be at least 4 seconds of delay (40 redstone ticks, 80 game ticks). +A MiniWarGear may be equipped with up to two automatic cannons. + +## Brücke + +A MiniWarGear must feature a command bridge in the form of a clearly distinguishable room. +The command bridge must be separated from the rest of the MiniWarGear by doors, fence gates, trapdoors or pistons. + +A command bridge must adhere to the following conditions: + +- At least 25 m² (1 block = 1 meter) +- A periodic, acoustic (note block / bell) and optical damage sensor +- A window through which the opponent is visible directly +- Controls for at least 4 headlights that are visible from the opposing position +- Controls for automatic cannons (if any are installed) +- Controls for shield technology (if there is any) +- The command bridge is the only place where dispensers which aim at the opponent may be controlled + +## Design + +MiniWarGears must (besides at least one cannon) feature a visual design. +The outermost layer of a MiniWarGear must only have a blast resistance of at most 6. +It is expected that there is a continuous design structure across the entire front of a MiniWarGear. +At least 2 different kinds of blocks must be used in a design (not counting redstone components). +A "continuous design structure" means, that no substantial surface areas have little to no depth. +Depth variation may also in part be achieved using walls or stairs, but this should not be overused. +Whether or not this is the case is up to the examiner. + +## Bug-Using + +The creation of TNT in a MiniWarGear is forbidden. + +Excessive use of blocks which are hidden by the tech-hider is also forbidden. + +## Definitions + +### Projectile + +A Projectile is any primed TNT entity, which is accelerated by propellant. +Furthermore a projectile is any primed TNT entity, which leaves the extension limits of a MiniWarGear (7 blocks) towards the opponent. + +### Propellant + +A propellant is any primed TNT entity, which by exploding accellerates projectiles towards the opposing half of the arena. +The propellant of any one cannon must only affect projectiles of that same cannon. + +## Hidden Blocks (Replaced with Endstone) + +- WATER +- NOTE_BLOCK +- POWERED_RAIL +- DETECTOR_RAIL +- PISTON +- PISTON_HEAD +- STICKY_PISTON +- TNT +- CHEST +- TRAPPED_CHEST +- REDSTONE_WIRE +- STONE_PRESSURE_PLATE +- IRON_DOOR +- OAK_PRESSURE_PLATE +- SPRUCE_PRESSURE_PLATE +- BIRCH_PRESSURE_PLATE +- JUNGLE_PRESSURE_PLATE +- ACACIA_PRESSURE_PLATE +- DARK_OAK_PRESSURE_PLATE +- REDSTONE_TORCH +- REDSTONE_WALL_TORCH +- REPEATER +- BREWING_STAND +- TRIPWIRE_HOOK +- TRIPWIRE +- HEAVY_WEIGHTED_PRESSURE_PLATE +- LIGHT_WEIGHTED_PRESSURE_PLATE +- COMPARATOR +- REDSTONE_BLOCK +- HOPPER +- ACTIVATOR_RAIL +- DROPPER +- SLIME_BLOCK +- OBSERVER +- HONEY_BLOCK +- LEVER +- SCULK_SENSOR +- POLISHED_BLACKSTONE_PRESSURE_PLATE +- MANGROVE_PRESSURE_PLATE +- CRIMSON_PRESSURE_PLATE +- WARPED_PRESSURE_PLATE + +## The Contents of the Following Blocks Are Also Hidden: + +- SIGN +- DISPENSER +- CHEST +- TRAPPED_CHEST +- FURNACE +- BREWING_STAND +- HOPPER +- DROPPER +- SHULKER_BOX +- JUKEBOX +- COMPARATOR From 7ea7536367f299a598be8139f480544d89f880a2 Mon Sep 17 00:00:00 2001 From: AdmiralSeekrank Date: Mon, 1 Jan 2001 00:00:00 +0000 Subject: [PATCH 4/8] Updated neujahr2026.md --- src/content/events/neujahr2026.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/events/neujahr2026.md b/src/content/events/neujahr2026.md index e49f2d4..997e3c6 100644 --- a/src/content/events/neujahr2026.md +++ b/src/content/events/neujahr2026.md @@ -29,7 +29,7 @@ es ist wieder Zeit, das Jahr neigt sich dem Ende und damit ist es wieder Zeit f - Techhider wird aktiv sein - Kampfleiter darf zum Schuss auffordern - Auto Tech KO wird deaktiviert -- Es wir ein eigenen Schemtypen geben +- Es wird ein eigenen Schemtypen geben - Turniersystem: All vs All **Eventleiter:** AdmiralSeekrank From 7ec678ae7d410bcd5b7e2cb2e5e60c898a870ad9 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Mon, 1 Dec 2025 18:38:06 +0100 Subject: [PATCH 5/8] Add AuditLog --- src/components/moderator/App.svelte | 2 + .../moderator/layout/NavLinks.svelte | 1 + .../moderator/pages/logs/AuditLog.svelte | 235 ++++++++++++++++++ .../moderator/pages/logs/columns.ts | 35 +++ src/components/repo/auditlog.ts | 40 +++ src/components/types/auditlog.ts | 19 ++ 6 files changed, 332 insertions(+) create mode 100644 src/components/moderator/pages/logs/AuditLog.svelte create mode 100644 src/components/moderator/pages/logs/columns.ts create mode 100644 src/components/repo/auditlog.ts create mode 100644 src/components/types/auditlog.ts diff --git a/src/components/moderator/App.svelte b/src/components/moderator/App.svelte index cb0dc13..0d12441 100644 --- a/src/components/moderator/App.svelte +++ b/src/components/moderator/App.svelte @@ -27,6 +27,7 @@ import Event from "@components/moderator/pages/event/Event.svelte"; import Pages from "@components/moderator/pages/pages/Pages.svelte"; import Generator from "@components/moderator/pages/generators/Generator.svelte"; + import AuditLog from "@components/moderator/pages/logs/AuditLog.svelte"; import { Tooltip } from "bits-ui"; const routes: RouteDefinition = { @@ -36,6 +37,7 @@ "/event/:id": Event, "/event/:id/generate": Generator, "/pages": Pages, + "/logs": AuditLog, }; diff --git a/src/components/moderator/layout/NavLinks.svelte b/src/components/moderator/layout/NavLinks.svelte index 1b540e7..f058c3d 100644 --- a/src/components/moderator/layout/NavLinks.svelte +++ b/src/components/moderator/layout/NavLinks.svelte @@ -27,4 +27,5 @@ Players Pages Schematics + Logs diff --git a/src/components/moderator/pages/logs/AuditLog.svelte b/src/components/moderator/pages/logs/AuditLog.svelte new file mode 100644 index 0000000..b436f0a --- /dev/null +++ b/src/components/moderator/pages/logs/AuditLog.svelte @@ -0,0 +1,235 @@ + + +
+
+ + debounce(e.currentTarget.value, (v) => { + fullText = v; + })} + oninput={(e) => + debounce(e.currentTarget.value, (v) => { + fullText = v; + })} + /> + + + + + + + + + + + No Players found :( + + {#each $players.filter((v) => v.name.toLowerCase().includes(playerSearch.toLowerCase())).filter((v, i) => i < 50) as player (player.uuid)} + (actors = actors.includes(player.uuid) ? actors.filter((v) => v !== player.uuid) : [...actors, player.uuid])} + keywords={[player.uuid]} + > + + {player.name} + + {/each} + + + + + + + + + + + + + + No Players found :( + + {#each $players.filter((v) => v.name.toLowerCase().includes(ownerSearch.toLowerCase())).filter((v, i) => i < 50) as player (player.uuid)} + (serverOwner = serverOwner.includes(player.uuid) ? serverOwner.filter((v) => v !== player.uuid) : [...serverOwner, player.uuid])} + keywords={[player.uuid]} + > + + {player.name} + + {/each} + + + + + +
+ +
+
+ +
+ +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + Keine Einträge gefunden. + + {/each} + +
+
+ +
+
+ +
+ + +
+
diff --git a/src/components/moderator/pages/logs/columns.ts b/src/components/moderator/pages/logs/columns.ts new file mode 100644 index 0000000..805cb9e --- /dev/null +++ b/src/components/moderator/pages/logs/columns.ts @@ -0,0 +1,35 @@ +import type { AuditLogEntry } from "@components/types/auditlog"; +import type { ColumnDef } from "@tanstack/table-core"; + +export const columns: ColumnDef[] = [ + { + accessorKey: "id", + header: "ID", + }, + { + accessorKey: "time", + header: "Time", + cell: (info) => new Date(info.getValue()).toLocaleString(), + }, + { + accessorKey: "server", + header: "Server", + }, + { + accessorKey: "serverOwner", + header: "Server Owner", + cell: (info) => info.getValue() || "N/A", + }, + { + accessorKey: "actor", + header: "Spieler", + }, + { + accessorKey: "actionType", + header: "Action Type", + }, + { + accessorKey: "actionText", + header: "Action Text", + }, +]; diff --git a/src/components/repo/auditlog.ts b/src/components/repo/auditlog.ts new file mode 100644 index 0000000..ee2609b --- /dev/null +++ b/src/components/repo/auditlog.ts @@ -0,0 +1,40 @@ +import { derived } from "svelte/store"; +import { fetchWithToken, tokenStore } from "./repo"; +import { PagedAutidLogSchema } from "@components/types/auditlog"; + +export class AuditLogRepo { + async get( + actionText: string | undefined, + serverText: string | undefined, + fullText: string | undefined, + actor: string[] | undefined, + actionType: string[] | undefined, + timeFrom: number | undefined, + timeTo: number | undefined, + serverOwner: string[] | undefined, + velocity: boolean | undefined, + page: number, + pageSize: number, + sorting: string | undefined + ) { + const params = new URLSearchParams(); + if (actionText) params.append("actionText", actionText); + if (serverText) params.append("serverText", serverText); + if (fullText) params.append("fullText", fullText); + if (actor) actor.forEach((a) => params.append("actor", a.toString())); + if (actionType) actionType.forEach((a) => params.append("actionType", a)); + if (timeFrom) params.append("timeGreater", timeFrom.toString()); + if (timeTo) params.append("timeLess", timeTo.toString()); + if (serverOwner) serverOwner.forEach((s) => params.append("serverOwner", s.toString())); + if (velocity !== undefined) params.append("velocity", velocity.toString()); + params.append("page", page.toString()); + params.append("limit", pageSize.toString()); + if (sorting) params.append("sorting", sorting); + + return await fetchWithToken("", `/auditlog?${params.toString()}`) + .then((value) => value.json()) + .then((data) => PagedAutidLogSchema.parse(data)); + } +} + +export const auditLog = derived(tokenStore, ($token) => new AuditLogRepo()); diff --git a/src/components/types/auditlog.ts b/src/components/types/auditlog.ts new file mode 100644 index 0000000..d956980 --- /dev/null +++ b/src/components/types/auditlog.ts @@ -0,0 +1,19 @@ +import { z } from "zod"; + +export const AuditLogEntrySchema = z.object({ + id: z.number(), + time: z.number(), + server: z.string(), + serverOwner: z.string().nullable(), + actor: z.string(), + actionType: z.enum(["JOIN", "LEAVE", "COMMAND", "SENSITIVE_COMMAND", "CHAT", "GUI_OPEN", "GUI_CLOSE", "GUI_CLICK"]), + actionText: z.string(), +}); + +export const PagedAutidLogSchema = z.object({ + entries: z.array(AuditLogEntrySchema), + rows: z.number(), +}); + +export type AuditLogEntry = z.infer; +export type PagedAuditLog = z.infer; From 5f5988e2707b202a5b35eb5bafd1ab4551c89986 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Tue, 2 Dec 2025 22:23:55 +0100 Subject: [PATCH 6/8] Refactor player handling: replace player arrays with IDs, implement PlayerSelector component --- .../admin/components/FightEditPart.svelte | 2 +- src/components/admin/pages/Perms.svelte | 33 +++- .../admin/pages/event/FightList.svelte | 21 +-- .../admin/pages/event/RefereesList.svelte | 6 +- .../moderator/pages/event/RefereesList.svelte | 32 +--- .../moderator/pages/logs/AuditLog.svelte | 62 +------ .../pages/players/PermissionsDropdown.svelte | 2 +- .../moderator/pages/players/Players.svelte | 134 +++++++++++++- .../moderator/pages/players/Table.svelte | 174 ------------------ src/components/repo/auditlog.ts | 4 +- src/components/repo/data.ts | 28 ++- src/components/stores/stores.ts | 4 - src/components/types/data.ts | 12 +- src/components/ui/PlayerSelector.svelte | 122 ++++++++++++ 14 files changed, 332 insertions(+), 304 deletions(-) delete mode 100644 src/components/moderator/pages/players/Table.svelte create mode 100644 src/components/ui/PlayerSelector.svelte diff --git a/src/components/admin/components/FightEditPart.svelte b/src/components/admin/components/FightEditPart.svelte index 6565924..04c77b9 100644 --- a/src/components/admin/components/FightEditPart.svelte +++ b/src/components/admin/components/FightEditPart.svelte @@ -20,7 +20,7 @@ @@ -60,27 +56,7 @@ {/each} - - - - - - - - - - - No Players found :( - - {#each $players - .filter((v) => v.name.toLowerCase().includes(playerSearch.toLowerCase())) - .filter((v, i) => i < 50) - .filter((v) => !referees.some((k) => k.uuid === v.uuid)) as player (player.uuid)} - addReferee(player.uuid)} keywords={[player.uuid]}>{player.name} - {/each} - - - - - + + addReferee(player.uuid)} /> +
diff --git a/src/components/moderator/pages/logs/AuditLog.svelte b/src/components/moderator/pages/logs/AuditLog.svelte index b436f0a..73b1975 100644 --- a/src/components/moderator/pages/logs/AuditLog.svelte +++ b/src/components/moderator/pages/logs/AuditLog.svelte @@ -11,10 +11,10 @@ import { Input } from "@components/ui/input"; import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command"; - import { players } from "@components/stores/stores"; import { Check } from "lucide-svelte"; import { cn } from "@components/utils"; import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte"; + import PlayerSelector from "@components/ui/PlayerSelector.svelte"; let debounceTimer: NodeJS.Timeout; const debounce = (value: T, func: (value: T) => void) => { @@ -27,11 +27,11 @@ let actionText = $state(""); let serverText = $state(""); let fullText = $state(""); - let actors = $state([]); + let actors = $state([]); let actionTypes = $state([]); let timeGreater = $state(now("Europe/Berlin").subtract({ months: 1 })); let timeLess = $state(now("Europe/Berlin")); - let serverOwner = $state([]); + let serverOwner = $state([]); let velocity = $state(false); let sorting = $state("DESC"); @@ -118,56 +118,12 @@ - - - - - - - - - No Players found :( - - {#each $players.filter((v) => v.name.toLowerCase().includes(playerSearch.toLowerCase())).filter((v, i) => i < 50) as player (player.uuid)} - (actors = actors.includes(player.uuid) ? actors.filter((v) => v !== player.uuid) : [...actors, player.uuid])} - keywords={[player.uuid]} - > - - {player.name} - - {/each} - - - - - - - - - - - - - - No Players found :( - - {#each $players.filter((v) => v.name.toLowerCase().includes(ownerSearch.toLowerCase())).filter((v, i) => i < 50) as player (player.uuid)} - (serverOwner = serverOwner.includes(player.uuid) ? serverOwner.filter((v) => v !== player.uuid) : [...serverOwner, player.uuid])} - keywords={[player.uuid]} - > - - {player.name} - - {/each} - - - - - +
+ +
+
+ +
diff --git a/src/components/moderator/pages/players/PermissionsDropdown.svelte b/src/components/moderator/pages/players/PermissionsDropdown.svelte index a58141d..9e6ff20 100644 --- a/src/components/moderator/pages/players/PermissionsDropdown.svelte +++ b/src/components/moderator/pages/players/PermissionsDropdown.svelte @@ -18,7 +18,7 @@ --> -{#await playersFuture} -

Loading...

-{:then players} - -{/await} \ No newline at end of file +
+
+ + debounce(e.currentTarget.value, (v) => { + search = v; + })} + oninput={(e) => + debounce(e.currentTarget.value, (v) => { + search = v; + })} + /> +
+
+
+ + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + No players found. + + {/each} + +
+ + +
+
+ +
+ + +
+ diff --git a/src/components/moderator/pages/players/Table.svelte b/src/components/moderator/pages/players/Table.svelte deleted file mode 100644 index 1d8dc68..0000000 --- a/src/components/moderator/pages/players/Table.svelte +++ /dev/null @@ -1,174 +0,0 @@ - - - - -
-
- { - table.getColumn("name")?.setFilterValue(e.currentTarget.value); - }} - oninput={(e) => { - table.getColumn("name")?.setFilterValue(e.currentTarget.value); - }} - class="max-w-sm" - /> -
- -
-
- - - {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - - {#each headerGroup.headers as header (header.id)} - - {#if !header.isPlaceholder} - - {/if} - - {/each} - - {/each} - - - {#each table.getRowModel().rows as row (row.id)} - - {#each row.getVisibleCells() as cell (cell.id)} - - - - {/each} - - {:else} - - - No results. - - - {/each} - -
-
- - {pagination.pageIndex + 1}/{table.getPageCount()} - -
-
\ No newline at end of file diff --git a/src/components/repo/auditlog.ts b/src/components/repo/auditlog.ts index ee2609b..2499585 100644 --- a/src/components/repo/auditlog.ts +++ b/src/components/repo/auditlog.ts @@ -7,11 +7,11 @@ export class AuditLogRepo { actionText: string | undefined, serverText: string | undefined, fullText: string | undefined, - actor: string[] | undefined, + actor: number[] | undefined, actionType: string[] | undefined, timeFrom: number | undefined, timeTo: number | undefined, - serverOwner: string[] | undefined, + serverOwner: number[] | undefined, velocity: boolean | undefined, page: number, pageSize: number, diff --git a/src/components/repo/data.ts b/src/components/repo/data.ts index b6a87db..44cf672 100644 --- a/src/components/repo/data.ts +++ b/src/components/repo/data.ts @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -import type { Player, Server } from "@type/data.ts"; -import { PlayerSchema, ServerSchema } from "@type/data.ts"; +import type { Player, PlayerList, Server } from "@type/data.ts"; +import { PlayerListSchema, PlayerSchema, ServerSchema } from "@type/data.ts"; import { fetchWithToken, tokenStore } from "./repo.ts"; import { derived, get } from "svelte/store"; import { TeamSchema, type Team } from "@components/types/team.ts"; @@ -38,10 +38,28 @@ export class DataRepo { .then(PlayerSchema.parse); } - public async getPlayers(): Promise { - return await fetchWithToken(get(tokenStore), "/data/admin/users") + public async queryPlayers( + name: string | undefined, + uuid: string | undefined, + team: number[] | undefined, + limit: number | undefined, + page: number | undefined, + includePerms: boolean | undefined, + includeId: boolean | undefined + ): Promise { + let query = new URLSearchParams(); + + if (name) query.append("name", name); + if (uuid) query.append("uuid", uuid); + if (team) team.forEach((t) => query.append("team", t.toString())); + if (limit) query.append("limit", limit.toString()); + if (page) query.append("page", page.toString()); + if (includePerms !== undefined) query.append("includePerms", includePerms.toString()); + if (includeId !== undefined) query.append("includeId", includeId.toString()); + + return await fetchWithToken(this.token, "/data/admin/users?" + query.toString()) .then((value) => value.json()) - .then(PlayerSchema.array().parse); + .then(PlayerListSchema.parse); } public async getTeams(): Promise { diff --git a/src/components/stores/stores.ts b/src/components/stores/stores.ts index 0afaf52..0ca1faf 100644 --- a/src/components/stores/stores.ts +++ b/src/components/stores/stores.ts @@ -31,10 +31,6 @@ import { permsRepo } from "@repo/perms.ts"; export const schemTypes = cached([], () => fetchWithToken(get(tokenStore), "/data/admin/schematicTypes").then((res) => res.json())); -export const players = cached([], async () => { - return get(dataRepo).getPlayers(); -}); - export const teams = cached([], async () => { return get(dataRepo).getTeams(); }); diff --git a/src/components/types/data.ts b/src/components/types/data.ts index 2098b68..3eee428 100644 --- a/src/components/types/data.ts +++ b/src/components/types/data.ts @@ -29,12 +29,20 @@ export type SchematicType = z.infer; export const PlayerSchema = z.object({ name: z.string(), uuid: z.string(), - prefix: z.string(), - perms: z.array(z.string()), + prefix: z.string().nullable(), + perms: z.array(z.string()).nullable(), + id: z.number().nullable(), }); export type Player = z.infer; +export const PlayerListSchema = z.object({ + entries: z.array(PlayerSchema), + rows: z.number(), +}); + +export type PlayerList = z.infer; + export const ServerSchema = z.object({ description: z.any(), players: z.object({ diff --git a/src/components/ui/PlayerSelector.svelte b/src/components/ui/PlayerSelector.svelte new file mode 100644 index 0000000..e47db2b --- /dev/null +++ b/src/components/ui/PlayerSelector.svelte @@ -0,0 +1,122 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + + + + No players found. + + {#each players as player (player.uuid)} + handleSelect(player)}> + + {player.name} + + {/each} + + + + + From 3bde299ea5878af2adef6a30a3410aaeadc1f3f2 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Tue, 2 Dec 2025 22:24:09 +0100 Subject: [PATCH 7/8] Refactor code for consistency: standardize formatting and improve readability across multiple Svelte components --- .../admin/components/FightEditPart.svelte | 163 ++++++++++-------- src/components/admin/pages/Perms.svelte | 82 ++++----- .../admin/pages/event/RefereesList.svelte | 84 ++++----- .../pages/players/PermissionsDropdown.svelte | 20 +-- 4 files changed, 177 insertions(+), 172 deletions(-) diff --git a/src/components/admin/components/FightEditPart.svelte b/src/components/admin/components/FightEditPart.svelte index 04c77b9..4d9d529 100644 --- a/src/components/admin/components/FightEditPart.svelte +++ b/src/components/admin/components/FightEditPart.svelte @@ -18,83 +18,103 @@ -->
@@ -107,32 +127,29 @@
- + {#snippet children({ props })} - - {/snippet} + + {/snippet}
- +
- +
- + {#snippet children({ props })} - - {/snippet} + + {/snippet}
- +
diff --git a/src/components/admin/pages/Perms.svelte b/src/components/admin/pages/Perms.svelte index f195df4..6ff4812 100644 --- a/src/components/admin/pages/Perms.svelte +++ b/src/components/admin/pages/Perms.svelte @@ -18,18 +18,18 @@ -->
- + {#snippet children({ hidden, toggle })} - - - - Permissions - - - {/snippet} + + + Permissions + + {/snippet}
@@ -138,17 +136,19 @@
- +
{#if playersList.length < 100}
    {#each playersList as player (player.uuid)} -
  • { selectedPlayer = player.uuid; selectedPlayerName = player.name; - })}> + })} + > {player.name}
  • {/each} @@ -166,39 +166,27 @@ {:then player}

    Prefix

    {#each Object.entries(perms.prefixes) as [key, prefix]} - {capitalize(prefix.name.substring(7).toLowerCase())} + {capitalize(prefix.name.substring(7).toLowerCase())} {/each}

    Permissions

    {#each perms.perms as perm} - {capitalize(perm.toLowerCase())} + {capitalize(perm.toLowerCase())} {/each}
    - + {#if $me != null && $me.perms.includes("ADMINISTRATION")} - + - + - + {#snippet footer()} - - - - - {/snippet} + + + {/snippet} {/if}
    diff --git a/src/components/admin/pages/event/RefereesList.svelte b/src/components/admin/pages/event/RefereesList.svelte index 35c4cc1..0efa88a 100644 --- a/src/components/admin/pages/event/RefereesList.svelte +++ b/src/components/admin/pages/event/RefereesList.svelte @@ -18,19 +18,19 @@ -->