Restyle and support logs.

This commit is contained in:
Thomas E Lackey 2024-02-15 13:41:12 -06:00
parent 02e2053bdf
commit a40bb93abb
6 changed files with 184 additions and 84 deletions

View File

@ -41,5 +41,9 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"prettier": "^3.2.5"
} }
} }

View File

@ -1,53 +1,64 @@
import { import {QueryClient, QueryClientProvider, useQuery, useQueryClient,} from '@tanstack/react-query'
useQuery, import React, {useState} from "react";
useMutation, import {fetchAllStatuses, fetchLogs} from './utils/data-utils';
useQueryClient, import Modal from './Modal'
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
import {fetchAllStatuses} from './utils/data-utils';
// Create a client // Create a client
const queryClient = new QueryClient() const queryClient = new QueryClient()
function App() { function App() {
return ( return (// Provide the client to your App
// Provide the client to your App
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<center>
<StatusTable/> <StatusTable/>
</center> </QueryClientProvider>)
</QueryClientProvider>
)
} }
function StatusTable() { function StatusTable() {
// Access the client // Access the client
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [logId, setLogId] = useState("");
// Queries // Queries
const query = useQuery({queryKey: ['allStatus'], queryFn: fetchAllStatuses}) const query = useQuery({queryKey: ['allStatus'], queryFn: fetchAllStatuses})
const queryLog = useQuery({queryKey: ['log', logId], queryFn: () => fetchLogs(logId)});
return ( return (<div>
<table id="all-status"> {logId && (<Modal open={true}>
<tr> <button className="close" onClick={() => setLogId("")}>CLOSE</button>
<th>URL</th> <div className="log-data">
<th>Application</th> <pre>{queryLog.data}</pre>
<th>Status</th> </div>
<th>Last Update</th> </Modal>)}
<th>Request ID</th> <div id="all-status">
</tr> {query.data?.map((status: any) => <div className={status.lastState.toLowerCase() + " status-row"}>
{query.data?.map((status: any) => <div className="status-line">
<tr className={"tr-status " + status.lastState.toLowerCase()}> <span className="status-key">Request ID:</span>
<td className="td-url">{status.deployment && <a href={status.url}>{status.url}</a>}</td> <span className="status-value">{status.id}</span>
<td className="td-app-crn">{status.app}</td> </div>
<td className="td-status">{status.lastState}</td> <div className="status-line">
<td className="td-last-update">{status.lastUpdate}</td> <span className="status-key">Application:</span>
<td className="td-id">{status.id}</td> <span className="status-value">{status.app}</span>
</tr> </div>
)} {status.deployment && <div className="status-line">
</table> <span className="status-key">URL:</span>
) <span className="status-value"><a href={status.url}>{status.url}</a></span>
</div>}
<div className="status-line">
<span className="status-key">Last Update:</span>
<span className="status-value">{status.lastUpdate}</span>
</div>
<div className="status-line">
<span className="status-key">Last State:</span>
<span className="status-value">{(status.logAvailable &&
<button className={"button-" + status.lastState.toLowerCase()}
onClick={() => {
queryClient.invalidateQueries({queryKey: ["log"]}).then(() => setLogId(status.id))
}}>{status.lastState}
</button>) || status.lastState}</span>
</div>
</div>)}
</div>
</div>)
} }
export default App; export default App;

37
src/Modal.tsx Normal file
View File

@ -0,0 +1,37 @@
import {Component} from "react";
const MODAL_STYLES = {
position: "absolute" as "absolute",
backgroundColor: "#FFF",
marginTop: "2em",
padding: "2em",
zIndex: "1000",
width: "75%",
height: "85%",
borderRadius: ".5em",
};
const OVERLAY_STYLE = {
position: "fixed" as "fixed",
display: "flex",
justifyContent: "center",
top: "0",
left: "0",
width: "100%",
height: "100%",
backgroundColor: "rgba(0,0,0, .8)",
zIndex: "1000",
};
class Modal extends Component<{ open: any, children: any }> {
render() {
let {open, children} = this.props;
if (!open) return null;
return (<>
<div style={OVERLAY_STYLE}>
<div style={MODAL_STYLES}>{children}</div>
</div>
</>);
}
}
export default Modal;

View File

@ -5,6 +5,7 @@ body {
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
background-color: white;
} }
code { code {
@ -12,41 +13,60 @@ code {
monospace; monospace;
} }
button {
cursor: pointer;
}
#all-status { #all-status {
width: 85%; margin: auto;
min-width: 50%;
max-width: 75%;
padding: 10px;
} }
#all-status td { .log-data {
padding: 0.3em; overflow: auto;
color: grey;
background-color: black;
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
width: 98%;
height: 95%;
padding: 1em;
} }
table { .status-row {
border-collapse:separate; width: auto;
border:solid lightblue 1px; background-color: white;
border-radius:6px; padding: 1em;
margin: 1em;
border-radius: 25px;
} }
td, th { .status-key {
border-left:solid lightblue 1px; font-weight: bold;
border-top:solid lightblue 1px; margin-right: 0.5em;
} }
th { .status-value {
border-top: none;
}
td:first-child, th:first-child {
border-left: none;
} }
.deployed { .deployed {
background-color: #ddffdd; background-color: #ddffdd;
} }
.button-deployed {
background-color: lawngreen;
color: white;
}
.error { .error {
background-color: #ffdddd; background-color: #ffdddd;
} }
.button-error {
background-color: red;
}
.cancelled { .cancelled {
background-color: #efefef; background-color: #efefef;
text-color: #dddddd; text-color: #dddddd;
@ -64,18 +84,3 @@ td:first-child, th:first-child {
.deploying { .deploying {
background-color: #fff1dd; background-color: #fff1dd;
} }
.tr-status {
font-size: small;
font-family: 'Courier New', Courier, monospace;
}
.td-id {
font-size: xx-small;
}
.td-last-update{
}
.td-status{
}

View File

@ -6,3 +6,16 @@ export const fetchAllStatuses = async () => {
} }
return await res.json(); return await res.json();
} }
export const fetchLogs = async (id: string) => {
if (!id) {
return "";
}
let url = `http://localhost:9555/log/${id}`
const res = await fetch(url);
if (!res.ok) {
throw new Error('Network response was not ok')
}
return await res.text();
}

View File

@ -87,7 +87,7 @@
"@jridgewell/trace-mapping" "^0.3.17" "@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1" jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.22.5": "@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5":
version "7.22.5" version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
@ -127,6 +127,21 @@
"@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-split-export-declaration" "^7.22.6"
semver "^6.3.1" semver "^6.3.1"
"@babel/helper-create-class-features-plugin@^7.21.0":
version "7.23.10"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz#25d55fafbaea31fd0e723820bb6cc3df72edf7ea"
integrity sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.22.5"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-member-expression-to-functions" "^7.23.0"
"@babel/helper-optimise-call-expression" "^7.22.5"
"@babel/helper-replace-supers" "^7.22.20"
"@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
semver "^6.3.1"
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5":
version "7.22.15" version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1"
@ -380,6 +395,16 @@
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
"@babel/plugin-proposal-private-property-in-object@^7.21.11":
version "7.21.11"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c"
integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
"@babel/helper-create-class-features-plugin" "^7.21.0"
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
"@babel/plugin-syntax-async-generators@^7.8.4": "@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4" version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@ -7676,6 +7701,11 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
prettier@^3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"