Update.
This commit is contained in:
parent
eb64edb22f
commit
bbb6ca629c
@ -1,6 +1,6 @@
|
|||||||
FROM python:3.12-alpine
|
FROM python:3.12-slim
|
||||||
|
|
||||||
RUN apk add git
|
RUN apt update && apt install --no-install-recommends -y git gifsicle libgl1
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
RUN git clone https://gitea.typename.fr/mikael.capelle/advent-of-code .
|
RUN git clone https://gitea.typename.fr/mikael.capelle/advent-of-code .
|
||||||
RUN pip install -e .
|
RUN pip install -e .
|
||||||
|
@ -67,13 +67,21 @@ async def file(name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.post("/submit-sse")
|
@app.post("/submit-sse")
|
||||||
async def submit_sse(year: int = Form(), day: int = Form(), input: str = Form()):
|
async def submit_sse(
|
||||||
|
year: int = Form(), day: int = Form(), input: str = Form(), verbose: bool = Form()
|
||||||
|
):
|
||||||
data = input.rstrip().replace("\r\n", "\n")
|
data = input.rstrip().replace("\r\n", "\n")
|
||||||
|
|
||||||
process = await asyncio.create_subprocess_exec(
|
args = [
|
||||||
"holt59-aoc",
|
"holt59-aoc",
|
||||||
"--stdin",
|
"--stdin",
|
||||||
"--api",
|
"--api",
|
||||||
|
]
|
||||||
|
if verbose:
|
||||||
|
args.append("--verbose")
|
||||||
|
|
||||||
|
process = await asyncio.create_subprocess_exec(
|
||||||
|
*args,
|
||||||
"--output",
|
"--output",
|
||||||
AOC_FILES_PATH,
|
AOC_FILES_PATH,
|
||||||
"--year",
|
"--year",
|
||||||
@ -97,6 +105,10 @@ async def submit_sse(year: int = Form(), day: int = Form(), input: str = Form())
|
|||||||
output = await fp.readline()
|
output = await fp.readline()
|
||||||
if output == b"":
|
if output == b"":
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if stream == "stderr" and output.startswith(b"OpenCV: FFMPEG"):
|
||||||
|
continue
|
||||||
|
|
||||||
await message_queue.put(
|
await message_queue.put(
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "stream",
|
||||||
|
@ -21,8 +21,10 @@
|
|||||||
"luxon": "^3.5.0",
|
"luxon": "^3.5.0",
|
||||||
"pinia": "^2.2.6",
|
"pinia": "^2.2.6",
|
||||||
"sse.js": "^2.5.0",
|
"sse.js": "^2.5.0",
|
||||||
|
"svg-pan-zoom": "^3.6.2",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "4"
|
"vue-router": "4",
|
||||||
|
"vue3-toastify": "^0.2.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node22": "^22.0.0",
|
"@tsconfig/node22": "^22.0.0",
|
||||||
|
@ -18,11 +18,12 @@ export const loadData = async (year: number, day: number, mode: "holt59" | "test
|
|||||||
}).then(r => r.json()).then(r => r["content"]).catch(() => "");
|
}).then(r => r.json()).then(r => r["content"]).catch(() => "");
|
||||||
};
|
};
|
||||||
|
|
||||||
export const submit = async (year: number, day: number, input: string, startCallback: (time: DateTime, commit: string) => void, streamCallback: (message: StreamMessage) => void) => {
|
export const submit = async (year: number, day: number, input: string, verbose: boolean, startCallback: (time: DateTime, commit: string) => void, streamCallback: (message: StreamMessage) => void) => {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append("year", year.toString());
|
data.append("year", year.toString());
|
||||||
data.append("day", day.toString());
|
data.append("day", day.toString());
|
||||||
data.append("input", input.toString());
|
data.append("input", input.toString());
|
||||||
|
data.append("verbose", verbose.toString());
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const eventSource = new SSE(urlFor("submit-sse"), {
|
const eventSource = new SSE(urlFor("submit-sse"), {
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
/* color palette from <https://github.com/vuejs/theme> */
|
|
||||||
:root {
|
|
||||||
--vt-c-white: #ffffff;
|
|
||||||
--vt-c-white-soft: #f8f8f8;
|
|
||||||
--vt-c-white-mute: #f2f2f2;
|
|
||||||
|
|
||||||
--vt-c-black: #181818;
|
|
||||||
--vt-c-black-soft: #222222;
|
|
||||||
--vt-c-black-mute: #282828;
|
|
||||||
|
|
||||||
--vt-c-indigo: #2c3e50;
|
|
||||||
|
|
||||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
|
||||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
|
||||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
|
||||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
|
||||||
|
|
||||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
|
||||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
|
||||||
--vt-c-text-dark-1: var(--vt-c-white);
|
|
||||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* semantic color variables for this project */
|
|
||||||
:root {
|
|
||||||
--color-background: var(--vt-c-white);
|
|
||||||
--color-background-soft: var(--vt-c-white-soft);
|
|
||||||
--color-background-mute: var(--vt-c-white-mute);
|
|
||||||
|
|
||||||
--color-border: var(--vt-c-divider-light-2);
|
|
||||||
--color-border-hover: var(--vt-c-divider-light-1);
|
|
||||||
|
|
||||||
--color-heading: var(--vt-c-text-light-1);
|
|
||||||
--color-text: var(--vt-c-text-light-1);
|
|
||||||
|
|
||||||
--section-gap: 160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--color-background: var(--vt-c-black);
|
|
||||||
--color-background-soft: var(--vt-c-black-soft);
|
|
||||||
--color-background-mute: var(--vt-c-black-mute);
|
|
||||||
|
|
||||||
--color-border: var(--vt-c-divider-dark-2);
|
|
||||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
|
||||||
|
|
||||||
--color-heading: var(--vt-c-text-dark-1);
|
|
||||||
--color-text: var(--vt-c-text-dark-2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
min-height: 100vh;
|
|
||||||
color: var(--color-text);
|
|
||||||
background: var(--color-background);
|
|
||||||
transition:
|
|
||||||
color 0.5s,
|
|
||||||
background-color 0.5s;
|
|
||||||
line-height: 1.6;
|
|
||||||
font-family:
|
|
||||||
Inter,
|
|
||||||
-apple-system,
|
|
||||||
BlinkMacSystemFont,
|
|
||||||
'Segoe UI',
|
|
||||||
Roboto,
|
|
||||||
Oxygen,
|
|
||||||
Ubuntu,
|
|
||||||
Cantarell,
|
|
||||||
'Fira Sans',
|
|
||||||
'Droid Sans',
|
|
||||||
'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
font-size: 15px;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
@ -3,6 +3,11 @@
|
|||||||
@import '../../node_modules/bootstrap/scss/functions';
|
@import '../../node_modules/bootstrap/scss/functions';
|
||||||
@import '../../node_modules/bootstrap/scss/variables';
|
@import '../../node_modules/bootstrap/scss/variables';
|
||||||
@import '../../node_modules/bootstrap/scss/mixins';
|
@import '../../node_modules/bootstrap/scss/mixins';
|
||||||
|
@import "../../node_modules/vue3-toastify/dist/index.css";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--toastify-color-progress-dark: var(--bs-primary);
|
||||||
|
}
|
||||||
|
|
||||||
#content-div {
|
#content-div {
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
@ -13,3 +18,9 @@
|
|||||||
#content-div>.progress {
|
#content-div>.progress {
|
||||||
margin-bottom: .3rem;
|
margin-bottom: .3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.modal-xxl {
|
||||||
|
--bs-modal-width: 1320px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ const inAocPeriod = (date: DateTime) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currentInput = ref("");
|
const currentInput = ref("");
|
||||||
const showLogs = ref(false);
|
const currentVerbose = ref(false);
|
||||||
|
|
||||||
const today = DateTime.now();
|
const today = DateTime.now();
|
||||||
const maxYear = today.month == 12 ? today.year : today.year - 1;
|
const maxYear = today.month == 12 ? today.year : today.year - 1;
|
||||||
@ -55,6 +55,8 @@ onMounted(() => {
|
|||||||
currentLoadMode.value = mode as "tests" | "holt59";
|
currentLoadMode.value = mode as "tests" | "holt59";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentVerbose.value = query.verbose == 'true'
|
||||||
|
|
||||||
currentDay.value = initialDay.value;
|
currentDay.value = initialDay.value;
|
||||||
currentYear.value = initialYear.value;
|
currentYear.value = initialYear.value;
|
||||||
});
|
});
|
||||||
@ -92,12 +94,15 @@ watch([currentDay, currentYear], () => {
|
|||||||
loadDataClicked();
|
loadDataClicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value } });
|
router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value, "verbose": currentVerbose.value.toString() } });
|
||||||
});
|
});
|
||||||
watch([currentLoadMode], () => {
|
watch([currentLoadMode], () => {
|
||||||
loadDataClicked();
|
loadDataClicked();
|
||||||
router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value } });
|
router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value, "verbose": currentVerbose.value.toString() } });
|
||||||
});
|
});
|
||||||
|
watch([currentVerbose], () => {
|
||||||
|
router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value, "verbose": currentVerbose.value.toString() } });
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// handle submit
|
// handle submit
|
||||||
@ -106,18 +111,45 @@ const submitRunning = ref(false);
|
|||||||
|
|
||||||
const submitClicked = async () => {
|
const submitClicked = async () => {
|
||||||
submitRunning.value = true;
|
submitRunning.value = true;
|
||||||
await resultComponent.value!.submit(currentYear.value, currentDay.value, currentInput.value, () => { });
|
await resultComponent.value!.submit(currentYear.value, currentDay.value, currentInput.value, currentVerbose.value);
|
||||||
submitRunning.value = false;
|
submitRunning.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
|
||||||
|
const today = DateTime.now();
|
||||||
|
const maxYear = today.month == 12 ? today.year : today.year - 1;
|
||||||
|
|
||||||
|
const day = today.day as number;
|
||||||
|
if (day && day >= 1 && day <= 25) {
|
||||||
|
initialDay.value = day;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
initialDay.value = inAocPeriod(today) ? today.day as number : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = maxYear;
|
||||||
|
if (year && year >= 2015 && year <= maxYear) {
|
||||||
|
initialYear.value = year;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
initialYear.value = maxYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDay.value = initialDay.value;
|
||||||
|
currentYear.value = initialYear.value;
|
||||||
|
|
||||||
|
resultComponent.value!.clear();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav class="container mt-3">
|
<nav class="container mt-3 title-block">
|
||||||
<h1>Advent-Of-Code — Holt59</h1>
|
<h1><a href="#" @click.prevent="reset()">Advent-Of-Code — Holt59</a></h1>
|
||||||
<hr />
|
<hr />
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<ResultVue ref="resultComponent" :show-logs="showLogs" />
|
<ResultVue ref="resultComponent" />
|
||||||
<section class="container d-flex flex-column flex-grow-1 position-relative">
|
<section class="container d-flex flex-column flex-grow-1 position-relative">
|
||||||
<form method="POST" class="d-flex flex-column flex-grow-1">
|
<form method="POST" class="d-flex flex-column flex-grow-1">
|
||||||
<div class="row mb-2 align-items-center">
|
<div class="row mb-2 align-items-center">
|
||||||
@ -160,9 +192,9 @@ const submitClicked = async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="showLogs" v-model="showLogs">
|
<input class="form-check-input" type="checkbox" id="verbose" v-model="currentVerbose">
|
||||||
<label class="form-check-label" for="showLogs">
|
<label class="form-check-label" for="verbose">
|
||||||
Show Logs
|
Verbose
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -180,6 +212,15 @@ const submitClicked = async () => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.title-block a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-block a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.area-input {
|
.area-input {
|
||||||
resize: none;
|
resize: none;
|
||||||
font-family: var(--bs-font-monospace);
|
font-family: var(--bs-font-monospace);
|
||||||
|
@ -8,19 +8,14 @@ import { AnsiUp } from 'ansi-up';
|
|||||||
import ResultProgressLine from './ResultProgressLine.vue';
|
import ResultProgressLine from './ResultProgressLine.vue';
|
||||||
import * as boostrap from 'bootstrap';
|
import * as boostrap from 'bootstrap';
|
||||||
import { instance } from "@viz-js/viz";
|
import { instance } from "@viz-js/viz";
|
||||||
|
import * as svgPanZoom from 'svg-pan-zoom'
|
||||||
const props = defineProps<{
|
import { countBy, throttle } from 'lodash';
|
||||||
showLogs: boolean
|
import { toast } from "vue3-toastify";
|
||||||
}>();
|
|
||||||
|
|
||||||
const hasResult = ref(false);
|
const hasResult = ref(false);
|
||||||
const isRunning = ref(false);
|
const isRunning = ref(false);
|
||||||
|
|
||||||
const commitValue = ref("");
|
const commitValue = ref("");
|
||||||
// const progressValue = ref(-1);
|
|
||||||
|
|
||||||
const answer1Value = ref<string | null>(null);
|
|
||||||
const answer2Value = ref<string | null>(null);
|
|
||||||
|
|
||||||
const contentDiv = ref<HTMLDivElement>();
|
const contentDiv = ref<HTMLDivElement>();
|
||||||
const contentRows = ref<Array<() => VNode>>([]);
|
const contentRows = ref<Array<() => VNode>>([]);
|
||||||
@ -48,27 +43,73 @@ const startCallback = (time: DateTime, commit: string) => {
|
|||||||
addRow(() => h("p", {}, ["Computing part 1... "]));
|
addRow(() => h("p", {}, ["Computing part 1... "]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileBuilders: { [extension: string]: (content: string) => Promise<Element> } = {
|
const imageBuilder = async (content: Blob) => {
|
||||||
txt: async (content: string) => {
|
const element = document.createElement("img");
|
||||||
|
element.src = URL.createObjectURL(content);
|
||||||
|
element.style.minWidth = "40%"
|
||||||
|
element.style.imageRendering = "pixelated"
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoBuilder = async (content: Blob) => {
|
||||||
|
const element = document.createElement("video");
|
||||||
|
element.autoplay = true
|
||||||
|
element.controls = true
|
||||||
|
element.style.minWidth = "40%"
|
||||||
|
element.style.imageRendering = "pixelated"
|
||||||
|
|
||||||
|
const source = document.createElement("source")
|
||||||
|
source.src = URL.createObjectURL(content);
|
||||||
|
|
||||||
|
element.appendChild(source)
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileBuilders: { [extension: string]: (content: Blob) => Promise<Element> } = {
|
||||||
|
txt: async (content: Blob) => {
|
||||||
const ansiUp = new AnsiUp();
|
const ansiUp = new AnsiUp();
|
||||||
ansiUp.escapeForHtml = false;
|
const nLines = countBy(content)["\n"];
|
||||||
const ansiHtml = ansiUp.ansi_to_html(content.replaceAll("\n", "<br/>"));
|
const ansiHtml = ansiUp.ansi_to_html(await content.text()).replaceAll("\n", "<br/>");
|
||||||
|
|
||||||
const codeElement = document.createElement("code")
|
const codeElement = document.createElement("code")
|
||||||
codeElement.classList.add("d-block")
|
codeElement.classList.add("d-block")
|
||||||
codeElement.style.fontSize = ".84em"
|
// codeElement.style.fontSize = ".84em"
|
||||||
codeElement.innerHTML = ansiHtml
|
codeElement.innerHTML = ansiHtml
|
||||||
|
|
||||||
|
const nChars = codeElement.textContent?.length || 0
|
||||||
|
const charsPerLine = Math.round(nChars / nLines)
|
||||||
|
|
||||||
|
// 80 -> 14
|
||||||
|
// 340 -> 6.4
|
||||||
|
codeElement.style.fontSize = Math.min(Math.floor(2176 / charsPerLine), 14) + "px";
|
||||||
|
|
||||||
return codeElement
|
return codeElement
|
||||||
},
|
},
|
||||||
dot: async (content: string) => {
|
dot: async (content: Blob) => {
|
||||||
return instance().then(viz => {
|
return instance().then(async viz => {
|
||||||
const e = viz.renderSVGElement(content)
|
const e = viz.renderSVGElement(await content.text())
|
||||||
e.style.maxWidth = "100%";
|
e.style.maxWidth = "100%";
|
||||||
e.style.height = "auto";
|
e.style.height = "auto";
|
||||||
|
setTimeout(() => {
|
||||||
|
const svg = document.querySelector("#file-content-body svg") as SVGElement;
|
||||||
|
svgPanZoom.default(svg, {
|
||||||
|
panEnabled: true,
|
||||||
|
zoomEnabled: true,
|
||||||
|
controlIconsEnabled: true
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
return e;
|
return e;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
png: imageBuilder,
|
||||||
|
jpeg: imageBuilder,
|
||||||
|
jpg: imageBuilder,
|
||||||
|
gif: imageBuilder,
|
||||||
|
mp4: videoBuilder,
|
||||||
|
avi: videoBuilder,
|
||||||
|
webm: videoBuilder
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxLogs = 100;
|
const maxLogs = 100;
|
||||||
@ -90,10 +131,10 @@ const streamCallback = (message: StreamMessage) => {
|
|||||||
case "log":
|
case "log":
|
||||||
logCounter.value += 1;
|
logCounter.value += 1;
|
||||||
if (logCounter.value < maxLogs) {
|
if (logCounter.value < maxLogs) {
|
||||||
addRow(() => h("p", { "class": { "log": true, "d-none": !props.showLogs } }, [`[${message.content.level}] ${message.time}: ${message.content.message}`]))
|
addRow(() => h("p", { "class": { "log": true } }, [`[${message.content.level}] ${message.time}: ${message.content.message}`]))
|
||||||
}
|
}
|
||||||
else if (logCounter.value == maxLogs) {
|
else if (logCounter.value == maxLogs) {
|
||||||
addRow(() => h("p", { "class": { "log": true, "d-none": !props.showLogs } }, [`[${message.content.level}] ${message.time}: Too many logs, capturing stopped.`]))
|
addRow(() => h("p", { "class": { "log": true } }, [`[${message.content.level}] ${message.time}: Too many logs, capturing stopped.`]))
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -117,7 +158,7 @@ const streamCallback = (message: StreamMessage) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
currentFilename.value = href.split("=")[1];
|
currentFilename.value = href.split("=")[1];
|
||||||
currentFilecontent.value = await fetch(href).then(r => r.text()).then(fileBuilders[extension])
|
currentFilecontent.value = await fetch(href).then(r => r.blob()).then(fileBuilders[extension])
|
||||||
|
|
||||||
bootstrapFileModal.value!.show();
|
bootstrapFileModal.value!.show();
|
||||||
}
|
}
|
||||||
@ -135,7 +176,20 @@ const streamCallback = (message: StreamMessage) => {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addRow(() => h(
|
addRow(() => h(
|
||||||
"p", {}, [`Answer ${message.content.answer} is '${message.content.value}', found in ${message.content.answerTime_s} s.`]
|
"p", {}, [`Answer ${message.content.answer} is `,
|
||||||
|
h("span", {
|
||||||
|
"class": ["answer"], onClick: throttle(() => {
|
||||||
|
navigator.clipboard.writeText(message.content.value)
|
||||||
|
toast(`Answer ${message.content.value} copied to clipboard.`, {
|
||||||
|
"theme": "auto",
|
||||||
|
"type": "default",
|
||||||
|
"autoClose": 1500,
|
||||||
|
"position": "bottom-right",
|
||||||
|
})
|
||||||
|
}, 500, { "leading": true })
|
||||||
|
},
|
||||||
|
message.content.value
|
||||||
|
), ` found in ${message.content.answerTime_s} s.`]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,27 +201,28 @@ const streamCallback = (message: StreamMessage) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const submit = async (year: number, day: number, input: string) => {
|
const submit = async (year: number, day: number, input: string, verbose: boolean) => {
|
||||||
logCounter.value = 0;
|
logCounter.value = 0;
|
||||||
answer1Value.value = null;
|
|
||||||
answer2Value.value = null;
|
|
||||||
contentErrors.value = "";
|
contentErrors.value = "";
|
||||||
hasResult.value = false;
|
hasResult.value = false;
|
||||||
isRunning.value = true;
|
isRunning.value = true;
|
||||||
contentRows.value = [];
|
contentRows.value = [];
|
||||||
await Api.submit(year, day, input, startCallback, streamCallback);
|
await Api.submit(year, day, input, verbose, startCallback, streamCallback);
|
||||||
isRunning.value = false;
|
isRunning.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ submit });
|
const clear = () => {
|
||||||
|
hasResult.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ submit, clear });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="container d-flex flex-column position-relative" :class="{ 'd-none': !hasResult }">
|
<section class="container d-flex flex-column position-relative" :class="{ 'd-none': !hasResult }">
|
||||||
<div>
|
<div>
|
||||||
<div class="position-absolute" style="top: 0px; right: 12px;">
|
<div class="position-absolute" style="top: 0px; right: 12px;">
|
||||||
<button class="btn btn-info" type="button" id="btn-clear-output"
|
<button class="btn btn-info" type="button" id="btn-clear-output" @click.prevent="clear">
|
||||||
@click.prevent="() => { hasResult = false }">
|
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -183,13 +238,13 @@ defineExpose({ submit });
|
|||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="modal fade" id="logsModal" tabindex="-1" aria-labelledby="logsModalLabel" aria-hidden="true"
|
<div class="modal fade" id="logsModal" tabindex="-1" aria-labelledby="logsModalLabel" aria-hidden="true"
|
||||||
ref="fileModal">
|
ref="fileModal">
|
||||||
<div class="modal-dialog modal-xl">
|
<div class="modal-dialog modal-xxl">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h1 class="modal-title fs-5" id="logsModalLabel">{{ currentFilename }}</h1>
|
<h1 class="modal-title fs-5" id="logsModalLabel">{{ currentFilename }}</h1>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body text-center" v-html="currentFilecontent?.outerHTML">
|
<div class="modal-body text-center" id="file-content-body" v-html="currentFilecontent?.outerHTML">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -197,3 +252,11 @@ defineExpose({ submit });
|
|||||||
</Teleport>
|
</Teleport>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.answer {
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--bs-primary); // todo use variable from main somehow
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -2256,6 +2256,11 @@ supports-color@^7.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
|
svg-pan-zoom@^3.6.2:
|
||||||
|
version "3.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/svg-pan-zoom/-/svg-pan-zoom-3.6.2.tgz#be136506211b242627a234a9656f8128fcbbabed"
|
||||||
|
integrity sha512-JwnvRWfVKw/Xzfe6jriFyfey/lWJLq4bUh2jwoR5ChWQuQoOH8FEh1l/bEp46iHHKHEJWIyFJETbazraxNWECg==
|
||||||
|
|
||||||
svg-tags@^1.0.0:
|
svg-tags@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
|
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
|
||||||
@ -2450,6 +2455,11 @@ vue-tsc@^2.1.10:
|
|||||||
"@vue/language-core" "2.1.10"
|
"@vue/language-core" "2.1.10"
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
|
|
||||||
|
vue3-toastify@^0.2.8:
|
||||||
|
version "0.2.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue3-toastify/-/vue3-toastify-0.2.8.tgz#0bb447b39f390ca9a1cb43c3c15ef3eede552b23"
|
||||||
|
integrity sha512-8jDOqsJaBZEbGpCbhWDETJc11D1lZefvgFPq/IPdM+U7+qyXoVPDvK6uq/FIgyV7qV0NcNzvGBMEzjsLQqGROw==
|
||||||
|
|
||||||
vue@^3.5.13:
|
vue@^3.5.13:
|
||||||
version "3.5.13"
|
version "3.5.13"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"
|
||||||
|
Loading…
Reference in New Issue
Block a user