collapse PlayerLog entries

This commit is contained in:
Ilion Beyst 2022-11-12 12:51:58 +01:00
parent d140759ea5
commit b0530be501
6 changed files with 211 additions and 166 deletions

View file

@ -1,5 +1,5 @@
<script lang="ts">
import PlayerLog from "./PlayerLog.svelte";
import PlayerLog from "./log_viewer/PlayerLog.svelte";
export let matchLog: string;
</script>

View file

@ -1,153 +0,0 @@
<script lang="ts">
import { parsePlayerLog, PlayerLog } from "$lib/log_parser";
export let matchLog: string;
export let playerId: number;
export let showStdErr: boolean = true;
let playerLog: PlayerLog;
let showRawStderr = false;
const PLURAL_MAP = {
dispatch: "dispatches",
ship: "ships",
};
function pluralize(num: number, word: string): string {
if (num == 1) {
return `1 ${word}`;
} else {
return `${num} ${PLURAL_MAP[word]}`;
}
}
$: if (matchLog) {
playerLog = parsePlayerLog(playerId, matchLog);
} else {
playerLog = [];
}
</script>
<div class="output">
{#if showRawStderr}
<div class="output-text stderr-text">
{playerLog.flatMap((turn) => turn.stderr).join("\n")}
</div>
{:else}
<div class="output-text">
{#each playerLog as logTurn, i}
<div class="turn">
<div class="turn-header">
<span class="turn-header-text">Turn {i}</span>
{#if logTurn.action?.type === "dispatches"}
{pluralize(logTurn.action.dispatches.length, "dispatch")}
{:else if logTurn.action?.type === "timeout"}
<span class="turn-error">timeout</span>
{:else if logTurn.action?.type === "bad_command"}
<span class="turn-error">invalid command</span>
{/if}
</div>
{#if logTurn.action?.type === "dispatches"}
<div class="dispatches-container">
{#each logTurn.action.dispatches as dispatch}
<div class="dispatch">
<div class="dispatch-text">
{pluralize(dispatch.ship_count, "ship")} from {dispatch.origin} to {dispatch.destination}
</div>
{#if dispatch.error}
<span class="dispatch-error">{dispatch.error}</span>
{/if}
</div>
{/each}
</div>
{:else if logTurn.action?.type === "bad_command"}
<div class="bad-command-container">
<div class="bad-command-text">{logTurn.action.command}</div>
<div class="bad-command-error">Parse error: {logTurn.action.error}</div>
</div>
{/if}
{#if showStdErr && logTurn.stderr.length > 0}
<div class="stderr-header">stderr</div>
<div class="stderr-text-box">
{#each logTurn.stderr as stdErrMsg}
<div class="stderr-text">{stdErrMsg}</div>
{/each}
</div>
{/if}
</div>
{/each}
</div>
{/if}
</div>
<style lang="scss">
.output {
background-color: rgb(41, 41, 41);
}
.turn {
margin: 16px 4px;
}
.output-text {
color: #ccc;
}
.turn-header {
display: flex;
justify-content: space-between;
}
.turn-header-text {
color: #eee;
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
}
.turn-error {
color: red;
}
.dispatch {
display: flex;
justify-content: space-between;
}
.dispatch-error {
color: red;
}
.bad-command-container {
border-left: 1px solid red;
margin-left: 4px;
padding-left: 8px;
}
.bad-command-text {
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
padding-bottom: 4px;
}
.bad-command-error {
color: whitesmoke;
}
.stderr-text {
// font-family: monospace;
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
white-space: pre-wrap;
}
.stderr-header {
color: #eee;
padding-top: 4px;
}
.stderr-text-box {
border-left: 1px solid #ccc;
margin-left: 4px;
padding-left: 8px;
}
</style>

View file

@ -0,0 +1,160 @@
<script lang="ts">
import type { PlayerLogTurn } from "$lib/log_parser";
import Fa from "svelte-fa";
import { faAngleRight, faAngleDown } from "@fortawesome/free-solid-svg-icons";
export let turnNum: number;
export let logTurn: PlayerLogTurn;
let expanded = false;
const PLURAL_MAP = {
dispatch: "dispatches",
ship: "ships",
};
function pluralize(num: number, word: string): string {
if (num == 1) {
return `1 ${word}`;
} else {
return `${num} ${PLURAL_MAP[word]}`;
}
}
function toggleExpand() {
expanded = !expanded;
}
</script>
<div class="turn">
<div class="turn-header" on:click={toggleExpand}>
<span>
<span class="turn-header-icon">
{#if expanded}
<Fa icon={faAngleDown} />
{:else}
<Fa icon={faAngleRight} />
{/if}
</span>
<span class="turn-header-text">
Turn {turnNum}
</span>
</span>
{#if logTurn.action?.type === "dispatches"}
{pluralize(logTurn.action.dispatches.length, "dispatch")}
{:else if logTurn.action?.type === "timeout"}
<span class="turn-error">timeout</span>
{:else if logTurn.action?.type === "bad_command"}
<span class="turn-error">invalid command</span>
{/if}
</div>
{#if expanded}
<div class="turn-content">
{#if logTurn.action?.type === "dispatches"}
<div class="dispatches-container">
{#each logTurn.action.dispatches as dispatch}
<div class="dispatch">
<div class="dispatch-text">
{pluralize(dispatch.ship_count, "ship")} from {dispatch.origin} to {dispatch.destination}
</div>
{#if dispatch.error}
<span class="dispatch-error">{dispatch.error}</span>
{/if}
</div>
{/each}
</div>
{:else if logTurn.action?.type === "bad_command"}
<div class="bad-command-container">
<div class="bad-command-text">{logTurn.action.command}</div>
<div class="bad-command-error">Parse error: {logTurn.action.error}</div>
</div>
{/if}
{#if logTurn.stderr.length > 0}
<div class="stderr-header">stderr</div>
<div class="stderr-text-box">
{#each logTurn.stderr as stdErrMsg}
<div class="stderr-text">{stdErrMsg}</div>
{/each}
</div>
{/if}
</div>
{/if}
</div>
<style lang="scss">
.turn {
// padding: 4px 2px;
color: #ccc;
}
.turn-header-icon {
// padding-right: 0.2em;
display: inline-block;
width: 1em;
}
.turn-header {
display: flex;
justify-content: space-between;
}
.turn-header:hover {
cursor: pointer;
background-color: #333;
}
.turn-header-text {
color: #eee;
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
}
.turn-content {
margin-bottom: 12px;
}
.turn-error {
color: red;
}
.dispatch {
display: flex;
justify-content: space-between;
}
.dispatch-error {
color: red;
}
.bad-command-container {
border-left: 1px solid red;
margin-left: 4px;
padding-left: 8px;
}
.bad-command-text {
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
padding-bottom: 4px;
}
.bad-command-error {
color: whitesmoke;
}
.stderr-text {
// font-family: monospace;
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
white-space: pre-wrap;
}
.stderr-header {
color: #eee;
padding-top: 4px;
}
.stderr-text-box {
border-left: 1px solid #ccc;
margin-left: 4px;
padding-left: 8px;
}
</style>

View file

@ -0,0 +1,39 @@
<script lang="ts">
import { parsePlayerLog, PlayerLog } from "$lib/log_parser";
import LogTurn from "./LogTurn.svelte";
export let matchLog: string;
export let playerId: number;
let playerLog: PlayerLog;
let showRawStderr = false;
$: if (matchLog) {
playerLog = parsePlayerLog(playerId, matchLog);
} else {
playerLog = [];
}
</script>
<div class="output">
{#if showRawStderr}
<div class="output-text stderr-text">
{playerLog.flatMap((turn) => turn.stderr).join("\n")}
</div>
{:else}
<!-- The log should be rerendered when playerId changes -->
{#key playerId}
<div class="log-contents">
{#each playerLog as logTurn, turnNum}
<LogTurn {logTurn} {turnNum} />
{/each}
</div>
{/key}
{/if}
</div>
<style lang="scss">
.output {
background-color: rgb(41, 41, 41);
}
</style>

View file

@ -22,7 +22,7 @@
<script lang="ts">
import { onMount } from "svelte";
import Visualizer from "$lib/components/Visualizer.svelte";
import PlayerLog from "$lib/components/PlayerLog.svelte";
import PlayerLog from "$lib/components/log_viewer/PlayerLog.svelte";
import Select from "svelte-select";
import { PLAYER_COLORS } from "$lib/constants";
import { currentUser } from "$lib/stores/current_user";

View file

@ -51,6 +51,15 @@ export function set_loading(loading: boolean) {
}
}
// this function should be called after resizes happen
function do_resize() {
resizeCanvasToDisplaySize(CANVAS);
if (game_instance) {
game_instance.on_resize();
}
}
function clamp(min: number, max: number, value: number): number {
if (value < min) {
return min;
@ -103,17 +112,7 @@ export function init() {
GL.enable(GL.BLEND);
GL.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA);
window.addEventListener(
"resize",
function () {
resizeCanvasToDisplaySize(CANVAS);
if (game_instance) {
game_instance.on_resize();
}
},
{ capture: false, passive: true }
);
new ResizeObserver(do_resize).observe(ELEMENTS["canvas"]);
ELEMENTS["turnSlider"].oninput = function () {
if (game_instance) {