Skip to content

Commit

Permalink
Advanced json editor in admin (#122)
Browse files Browse the repository at this point in the history
* Schema in overlay

* Use simple text editor

* Move gen.kt

* New schemas
  • Loading branch information
azat-ismagilov authored Oct 14, 2023
1 parent e2765e5 commit a79e05c
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 3 deletions.
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ build_version=dev
npm.download=true
org.gradle.parallel=true
org.gradle.caching=true
live.dev.embedFrontend=true
live.dev.embedFrontend=true
live.dev.embedSchema=true
14 changes: 14 additions & 0 deletions src/backend/src/main/kotlin/org/icpclive/admin/Routing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.icpclive.admin
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
Expand Down Expand Up @@ -92,6 +93,19 @@ fun Route.configureAdminApiRouting() {
}
}
}

route("/advancedJson") {
get {
call.respondFile(Config.advancedJsonPath.toFile())
}
post {
call.adminApiAction {
val text = call.receiveText()
Config.advancedJsonPath.toFile().writeText(text)
}
}
}

webSocket("/advancedProperties") { sendJsonFlow(DataBus.advancedPropertiesFlow.await()) }
webSocket("/backendLog") { sendFlow(DataBus.loggerFlow) }
webSocket("/adminActions") { sendFlow(DataBus.adminActionsFlow) }
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/admin/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Analytics from "./components/Analytics";
import TeamSpotlight from "./components/TeamSpotlight";
import { useLocalStorageState } from "./utils";
import FullScreenClockManager from "./components/FullScreenClockManager";
import AdvancedJson from "./components/AdvancedJson";

const dashboard_elements = {
"Controls": <Controls/>,
Expand Down Expand Up @@ -58,6 +59,7 @@ function App() {
<Route path="/log" element={<BackendLog/>}/>
<Route path="/analytics" element={<Analytics/>}/>
<Route path="/teamSpotlight" element={<TeamSpotlight/>}/>
<Route path="/advancedJson" element={<AdvancedJson/>}/>
{/* <Route path="/advancedproperties" element={<AdvancedProperties/>}/> */}
</Routes>
<Overlay isOverlayPreviewShown={isOverlayPreviewShown}/>
Expand Down
1 change: 1 addition & 0 deletions src/frontend/admin/src/AppNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const pages = {
"Backend Log": "log",
"Analytics": "analytics",
"Spotlight": "teamSpotlight",
"Advanced": "advancedJson",
// "Advanced Properties": "AdvancedProperties",
};

Expand Down
65 changes: 65 additions & 0 deletions src/frontend/admin/src/components/AdvancedJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState, useEffect } from "react";
import { Button, Container, TextField } from "@mui/material";
import { errorHandlerWithSnackbar } from "../errors";
import { useSnackbar } from "notistack";
import { BASE_URL_BACKEND, SCHEMAS_LOCATION } from "../config";
import Typography from "@mui/material/Typography";
import { createApiGet, createApiPost } from "../utils";

function AdvancedJson() {
const { enqueueSnackbar } = useSnackbar();
const errorHandler = errorHandlerWithSnackbar(enqueueSnackbar);

const schemaUrl = SCHEMAS_LOCATION + "/advanced.schema.json";
const apiUrl = BASE_URL_BACKEND + "/advancedJson";

const schemaGet = createApiGet(schemaUrl);
const apiGet = createApiGet(apiUrl);
const apiPost = createApiPost(apiUrl);

const [schema, setSchema] = useState();
const [data, setData] = useState();

useEffect(() => {
schemaGet("")
.then(data => setSchema(data))
.catch(errorHandler("Failed to load advanced json schema"));
}, [schemaUrl]);

useEffect(() => {
apiGet("")
.then(data => setData(JSON.stringify(data, null, 2)))
.catch(errorHandler("Failed to load advanced json data"));
}, [apiUrl]);

const onSubmit = () => {
const dataJson = JSON.parse(data);
console.log(dataJson);
apiPost("", dataJson)
.catch(errorHandler("Failed to save advanced json data"));
};

if (schema === undefined || data === undefined) {
return (
<Container maxWidth="md" sx={{ pt: 2 }}>
<Typography variant="h6">Loading...</Typography>
</Container>
);
}

return (
<Container maxWidth="md" sx={{ pt: 2 }}>
<TextField
value={data}
onChange={(e) => setData(e.target.value)}
fullWidth
multiline
/>
<Button type="submit" onClick={onSubmit}>
Save
</Button>
</Container>
);
}

export default AdvancedJson;
3 changes: 1 addition & 2 deletions src/frontend/admin/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ const BACKEND_PROTO = window.location.protocol === "https:" ? "https://" : "http
const BACKEND_PORT = process.env.REACT_APP_BACKEND_PORT ?? window.location.port;
export const BASE_URL_BACKEND = process.env.REACT_APP_BACKEND_URL ?? (BACKEND_PROTO + window.location.hostname + ":" + BACKEND_PORT + "/api/admin");
export const OVERLAY_LOCATION = process.env.REACT_APP_OVERLAY_LOCATION ?? (BACKEND_PROTO + window.location.hostname + ":" + BACKEND_PORT + "/overlay");
export const SCHEMAS_LOCATION = process.env.REACT_APP_SCHEMAS_LOCATION ?? (BACKEND_PROTO + window.location.hostname + ":" + BACKEND_PORT + "/schemas");

const WS_PROTO = window.location.protocol === "https:" ? "wss://" : "ws://";
export const BASE_URL_WS = process.env.REACT_APP_WEBSOCKET_URL ?? (WS_PROTO + window.location.hostname + ":" + BACKEND_PORT + "/api/admin");

export const WEBSOCKET_RECONNECT_TIME = 5000;

export const ADMIN_ACTIONS_WS_URL = BASE_URL_WS + "/adminActions";

0 comments on commit a79e05c

Please sign in to comment.