diff --git a/backend/.plano.py b/backend/.plano.py index 5124d5e..eab95d3 100644 --- a/backend/.plano.py +++ b/backend/.plano.py @@ -25,7 +25,7 @@ def build(no_cache=False): no_cache_arg = "--no-cache" if no_cache else "" - run(f"podman build {no_cache_arg} -t {image_tag} .") + run(f"podman build {no_cache_arg} --format docker -t {image_tag} .") @command def run_(): diff --git a/frontend/.plano.py b/frontend/.plano.py index f8b38a4..7a7571a 100644 --- a/frontend/.plano.py +++ b/frontend/.plano.py @@ -26,7 +26,7 @@ def build(no_cache=False): no_cache_arg = "--no-cache" if no_cache else "" - run(f"podman build {no_cache_arg} -t {image_tag} .") + run(f"podman build {no_cache_arg} --format docker -t {image_tag} .") @command def run_(): diff --git a/frontend/python/main.py b/frontend/python/main.py index 4f4832b..a56eeb4 100644 --- a/frontend/python/main.py +++ b/frontend/python/main.py @@ -25,7 +25,7 @@ import uvicorn from animalid import generate_animal_id -from httpx import AsyncClient +from httpx import AsyncClient, HTTPError from sse_starlette.sse import EventSourceResponse from starlette.applications import Starlette from starlette.responses import FileResponse, JSONResponse, Response @@ -73,11 +73,15 @@ async def generate_id(request): async def hello(request): request_data = await request.json() - backend_request, backend_response = await send_greeting(request_data["name"], request_data["text"]) + name = request_data["name"] + text = request_data["text"] + + backend_request, backend_response, backend_error = await send_greeting(name, text) record = { "request": backend_request, "response": backend_response, + "error": backend_error, } records.append(record); @@ -94,11 +98,14 @@ async def send_greeting(name, text): } async with AsyncClient() as client: - response = await client.post(f"{backend_url}/api/hello", json=request_data) + try: + response = await client.post(f"{backend_url}/api/hello", json=request_data) + except HTTPError as e: + return request_data, None, str(e) response_data = response.json() - return request_data, response_data + return request_data, response_data, None @star.route("/api/health", methods=["GET"]) async def health(request): diff --git a/frontend/static/gesso/general.css b/frontend/static/gesso/general.css index f4b3abd..da09394 100644 --- a/frontend/static/gesso/general.css +++ b/frontend/static/gesso/general.css @@ -1,4 +1,4 @@ -@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,600;0,700;1,300;1,400;1,600;1,700&display=swap"); +@import url('https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,400;0,500;0,600;1,400;1,500;1,600&display=swap'); @import url("https://fonts.googleapis.com/icon?family=Material+Icons+Outlined"); :root { @@ -32,7 +32,7 @@ br { } body { - font: 13pt/19pt "Source Sans Pro", sans-serif; + font: 13pt/19pt "Source Sans 3", sans-serif; font-weight: 400; color: var(--black); margin: 0; @@ -57,5 +57,9 @@ h2 { } h1, h2, h3, h4, th, b { + font-weight: 500; +} + +b { font-weight: 600; } diff --git a/frontend/static/gesso/gesso.js b/frontend/static/gesso/gesso.js index d0faad3..304ee87 100644 --- a/frontend/static/gesso/gesso.js +++ b/frontend/static/gesso/gesso.js @@ -251,7 +251,7 @@ export function formatBoolean(value) { else return "No"; } -export function getJson(url, handler) { +export function getJson(url, responseDataHandler, errorHandler) { console.log("Getting data from", url); fetch(url, { @@ -260,16 +260,20 @@ export function getJson(url, handler) { }) .then(response => response.json()) .then(responseData => { - if (handler) { - handler(responseData); + if (responseDataHandler) { + responseDataHandler(responseData); } }) .catch(error => { - console.log(error); + if (errorHandler) { + errorHandler(error); + } else { + console.log(error); + } }); } -export function postJson(url, requestData, handler) { +export function postJson(url, requestData, responseDataHandler, errorHandler) { console.log("Posting data to", url); fetch(url, { @@ -279,12 +283,16 @@ export function postJson(url, requestData, handler) { }) .then(response => response.json()) .then(responseData => { - if (handler) { - handler(responseData) + if (responseDataHandler) { + responseDataHandler(responseData) } }) .catch(error => { - console.log(error); + if (errorHandler) { + errorHandler(error); + } else { + console.log(error); + } }); } @@ -374,8 +382,8 @@ export class Router { } } -// One column: [title string, data key, optional rendering function] -// Rendering function: render(value, item, context) => value +// One column: [columnTitle, recordKey, cellRenderFunction (optional)] +// cellRenderFunction: render(record, recordKey, context) => value or elem // Context is whatever the user chooses to pass into update() export class Table { constructor(id, columns) { @@ -383,7 +391,7 @@ export class Table { this.columns = columns; } - update(items, context) { + update(records, context) { const headings = []; const rows = []; const div = createDiv(null, `#${this.id}`); @@ -392,17 +400,18 @@ export class Table { headings.push(column[0]); } - for (const item of items) { + for (const record of records) { const row = []; for (const column of this.columns) { - let value = item[column[1]]; + const recordKey = column[1]; + const cellRenderFunction = column[2]; - if (column.length === 3) { - value = column[2](value, item, context); + if (cellRenderFunction) { + row.push(cellRenderFunction(record, recordKey, context)); + } else { + row.push(record[recordKey]); } - - row.push(value); } rows.push(row); diff --git a/frontend/static/gesso/tables.css b/frontend/static/gesso/tables.css index 1668a43..fbce805 100644 --- a/frontend/static/gesso/tables.css +++ b/frontend/static/gesso/tables.css @@ -2,7 +2,11 @@ table { width: 100%; } -table th, -table td { +th, +td { text-align: left; } + +th { + padding-bottom: 0.4em; +} diff --git a/frontend/static/main.css b/frontend/static/main.css index da93a16..a462901 100644 --- a/frontend/static/main.css +++ b/frontend/static/main.css @@ -1 +1,10 @@ @import url("./gesso/gesso.css"); + +span.name { + font-weight: 600; +} + +span.error { + font-weight: 500; + color: red; +} diff --git a/frontend/static/main.js b/frontend/static/main.js index 9e89e16..a53577c 100644 --- a/frontend/static/main.js +++ b/frontend/static/main.js @@ -12,7 +12,7 @@ const html = `
-
Your name is .
+
Your name is .
@@ -28,25 +28,29 @@ const html = ` `; -function renderRequest(value, item, context) { +function renderRequest(record, recordKey, context) { const elem = gesso.createElement(null, "div"); - elem.innerHTML = item.request.text.replace(item.request.name, `${item.request.name}`); + elem.innerHTML = record.request.text.replace(record.request.name, `${record.request.name}`); return elem; } -function renderResponse(value, item, context) { +function renderResponse(record, recordKey, context) { const elem = gesso.createElement(null, "div"); - elem.innerHTML = item.response.text.replace(item.response.name, `${item.response.name}`); + if (record.error) { + elem.innerHTML = `Error: ${record.error}`; + } else { + elem.innerHTML = record.response.text.replace(record.response.name, `${record.response.name}`); + } return elem; } const helloTable = new gesso.Table("hello-table", [ - ["Frontend requests", "request", renderRequest], - ["Backend responses", "response", renderResponse], + ["Frontend", "request", renderRequest], + ["Backend", "response", renderResponse], ]); class MainPage extends gesso.Page { @@ -81,10 +85,10 @@ class MainPage extends gesso.Page { updateContent() { $("#name").textContent = this.name; - gesso.getJson("/api/data", data => { - const responses = Object.values(data).reverse(); + gesso.getJson("/api/data", responseData => { + const responses = Object.values(responseData).reverse(); - helloTable.update(responses, data); + helloTable.update(responses, responseData); }); } }