Skip to content

Commit

Permalink
Merge pull request #50 from CLIMB-TRE/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
tombch authored Nov 26, 2024
2 parents 4415dfe + 0b8ba38 commit d955617
Show file tree
Hide file tree
Showing 18 changed files with 299 additions and 128 deletions.
17 changes: 4 additions & 13 deletions lib/Onyx.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,16 @@
--bs-btn-disabled-border-color: var(--bs-gray-900);
}

.card-header {
font-size: large;
min-height: 50px;
}

.card-footer {
height: 50px;
.ag-theme-quartz {
--ag-background-color: var(--bs-body-bg);
--ag-foreground-color: var(--bs-body-color);
--ag-font-family: var(--bs-font-monospace);
}

.onyx-text-pink {
color: var(--bs-pink);
}

.ag-theme-quartz {
--ag-background-color: var(--bs-body-bg);
--ag-foreground-color: var(--bs-body-color);
--ag-font-family: monospace;
}

.onyx-modal {
font-size: var(--bs-body-font-size);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Onyx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { OnyxProps } from "./interfaces";
import "./Onyx.css";
import "./bootstrap.css";

const VERSION = "0.12.4";
const VERSION = "0.13.0";

function flattenFields(fields: Record<string, ProjectField>) {
const flatFields: Record<string, ProjectField> = {};
Expand Down
73 changes: 73 additions & 0 deletions lib/components/ErrorModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Modal from "react-bootstrap/Modal";
import Form from "react-bootstrap/Form";
import Accordion from "react-bootstrap/Accordion";
import Button from "react-bootstrap/Button";

interface ErrorModalContentsProps {
error: Error | null;
message?: string;
}

interface ErrorModalProps extends ErrorModalContentsProps {
show: boolean;
onHide: () => void;
title: string;
}

function ErrorModalContents(props: ErrorModalContentsProps) {
return (
<Form>
<Form.Group className="mb-3">
<Form.Label className="d-flex justify-content-center">
Error Occurred.
</Form.Label>
{props.message && (
<Form.Text className="d-flex justify-content-center">
<b className="onyx-text-pink">{props.message}</b>
</Form.Text>
)}
<Form.Text className="d-flex justify-content-center">
Please try again or contact CLIMB-TRE support if the problem persists.
</Form.Text>
</Form.Group>
<Accordion>
<Accordion.Item eventKey="0">
<Accordion.Header>View Error Message</Accordion.Header>
<Accordion.Body>
<small className="onyx-text-pink font-monospace">
{props.error
? `${props.error.name}: ${props.error.message}`
: "No error message."}
</small>
</Accordion.Body>
</Accordion.Item>
</Accordion>
</Form>
);
}

function ErrorModal(props: ErrorModalProps) {
return (
<Modal
className="onyx-modal"
centered
show={props.show}
onHide={props.onHide}
>
<Modal.Header closeButton>
<Modal.Title>{props.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
<ErrorModalContents {...props} />
</Modal.Body>
<Modal.Footer>
<Button variant="dark" onClick={props.onHide}>
Close
</Button>
</Modal.Footer>
</Modal>
);
}

export default ErrorModal;
export { ErrorModalContents };
33 changes: 26 additions & 7 deletions lib/components/ExportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import Button from "react-bootstrap/Button";
import InputGroup from "react-bootstrap/InputGroup";
import Form from "react-bootstrap/Form";
import ProgressBar from "react-bootstrap/ProgressBar";
import { DataProps, ExportHandlerProps } from "../interfaces";
import Stack from "react-bootstrap/Stack";
import Spinner from "react-bootstrap/Spinner";
import { ExportHandlerProps } from "../interfaces";
import { ExportStatus } from "../types";
import { ErrorModalContents } from "./ErrorModal";

interface ExportModalProps extends DataProps {
interface ExportModalProps {
show: boolean;
onHide: () => void;
defaultFileNamePrefix: string;
Expand Down Expand Up @@ -39,6 +42,7 @@ function isInvalidPrefix(prefix: string) {
function ExportModal(props: ExportModalProps) {
const [exportStatus, setExportStatus] = useState(ExportStatus.READY);
const [exportProgress, setExportProgress] = useState(0);
const [exportError, setExportError] = useState<Error | null>(null);
const [fileNamePrefix, setFileNamePrefix] = useState("");
const [fileNameIsInvalid, setFileNameIsInvalid] = useState(false);
const { statusToken, readyExport, cancelExport } = useExportStatusToken();
Expand All @@ -54,13 +58,14 @@ function ExportModal(props: ExportModalProps) {
} else setFileNameIsInvalid(false);

setExportProgress(0);
setExportError(null);
readyExport();
setExportStatus(ExportStatus.RUNNING);
props.handleExport({
fileName: prefix + props.fileExtension,
statusToken,
setExportProgress,
setExportStatus,
setExportProgress,
setExportError,
});
};

Expand Down Expand Up @@ -139,12 +144,24 @@ function ExportModal(props: ExportModalProps) {
<ProgressBar now={exportProgress} variant="danger" />
</Form.Group>
)}
{exportStatus === ExportStatus.ERROR && (
<ErrorModalContents error={exportError} />
)}
{exportStatus === ExportStatus.WRITING && (
<Form.Group className="mb-3">
<Form.Label className="d-flex justify-content-center">
<Stack direction="horizontal" gap={2}>
<Spinner />
<span>Writing File...</span>
</Stack>
</Form.Label>
</Form.Group>
)}
{exportStatus === ExportStatus.FINISHED && (
<Form.Group className="mb-3">
<Form.Label className="d-flex justify-content-center">
Export Finished.
</Form.Label>
<ProgressBar now={exportProgress} />
<Form.Text className="d-flex justify-content-center">
<span>
File Name:{" "}
Expand Down Expand Up @@ -172,15 +189,17 @@ function ExportModal(props: ExportModalProps) {
Cancel
</Button>
)}
{exportStatus === ExportStatus.CANCELLED && (
{(exportStatus === ExportStatus.CANCELLED ||
exportStatus === ExportStatus.ERROR) && (
<Button
variant="primary"
onClick={() => setExportStatus(ExportStatus.READY)}
>
Retry
</Button>
)}
{exportStatus === ExportStatus.FINISHED && (
{(exportStatus === ExportStatus.WRITING ||
exportStatus === ExportStatus.FINISHED) && (
<Button variant="primary" onClick={props.onHide}>
Done
</Button>
Expand Down
7 changes: 2 additions & 5 deletions lib/components/FilterPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function FilterPanel(props: FilterPanelProps) {
return (
<Card className="h-50">
<Card.Header>
<span>Filters</span>
<span>Filter</span>
<Button
className="float-end"
size="sm"
Expand Down Expand Up @@ -129,10 +129,7 @@ function FilterPanel(props: FilterPanelProps) {
variant="dark"
onClick={() => handleEditMode(filter, index)}
>
<span
className="onyx-text-pink"
style={{ fontFamily: "monospace" }}
>
<span className="onyx-text-pink font-monospace">
{formatFilter(filter)}
</span>
</Button>
Expand Down
4 changes: 2 additions & 2 deletions lib/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Nav from "react-bootstrap/Nav";
import Navbar from "react-bootstrap/Navbar";
import NavDropdown from "react-bootstrap/NavDropdown";
import { useQuery } from "@tanstack/react-query";
import { MdLightMode, MdDarkMode, MdWebhook } from "react-icons/md";
import { MdLightMode, MdDarkMode, MdJoinInner } from "react-icons/md";

interface HeaderProps {
httpPathHandler: (path: string) => Promise<Response>;
Expand Down Expand Up @@ -75,7 +75,7 @@ function Header(props: HeaderProps) {
>
<Container fluid>
<Navbar.Brand>
<MdWebhook color="var(--bs-pink)" /> Onyx
<MdJoinInner color="var(--bs-pink)" /> Onyx
</Navbar.Brand>
<Navbar.Toggle aria-controls="navbarScroll" />
<Navbar.Collapse id="navbarScroll">
Expand Down
2 changes: 1 addition & 1 deletion lib/components/QueryHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function QueryHandler({
<LoadingSpinner />
) : error ? (
<Alert variant="danger">Error: {error.message}</Alert>
) : data.messages ? (
) : data?.messages ? (
<ErrorMessages messages={data.messages} />
) : (
children
Expand Down
67 changes: 46 additions & 21 deletions lib/components/RecordModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useMemo } from "react";
import { CustomCellRendererProps } from "@ag-grid-community/react";
import Badge from "react-bootstrap/Badge";
import Stack from "react-bootstrap/Stack";
Expand All @@ -12,10 +12,12 @@ import Row from "react-bootstrap/Row";
import Container from "react-bootstrap/Container";
import { useQuery } from "@tanstack/react-query";
import Table from "./Table";
import ErrorModal from "./ErrorModal";
import QueryHandler from "./QueryHandler";
import { ResultData, ResultType, ExportStatus } from "../types";
import { DataProps, ExportHandlerProps } from "../interfaces";
import ExportModal from "./ExportModal";
import { s3BucketsMessage } from "../utils/errorMessages";

interface RecordModalProps extends DataProps {
recordID: string;
Expand Down Expand Up @@ -48,10 +50,16 @@ function RecordDataField({

function RecordData(props: RecordModalProps) {
const [exportModalShow, setExportModalShow] = useState(false);
const [errorModalShow, setErrorModalShow] = useState(false);
const [s3ReportError, setS3ReportError] = useState<Error | null>(null);

const handleErrorModalShow = (error: Error) => {
setS3ReportError(error);
setErrorModalShow(true);
};

const DetailCellRenderer = (cellRendererProps: CustomCellRendererProps) => {
if (
props.s3PathHandler &&
typeof cellRendererProps.value === "string" &&
cellRendererProps.value.startsWith("s3://") &&
cellRendererProps.value.endsWith(".html")
Expand All @@ -62,7 +70,9 @@ function RecordData(props: RecordModalProps) {
size="sm"
variant="link"
onClick={() =>
props.s3PathHandler && props.s3PathHandler(cellRendererProps.value)
props
.s3PathHandler(cellRendererProps.value)
.catch((error: Error) => handleErrorModalShow(error))
}
>
{cellRendererProps.value}
Expand Down Expand Up @@ -96,23 +106,32 @@ function RecordData(props: RecordModalProps) {
.join(" ");
};

const detailFields = Object.entries(recordData.data).filter(
([key]) => props.projectFields.get(key)?.type !== "relation"
const detailFields = useMemo(
() =>
Object.entries(recordData?.data || {}).filter(
([key]) => props.projectFields.get(key)?.type !== "relation"
),
[recordData, props.projectFields]
);

const relationFields = Object.entries(recordData.data)
.filter(([key]) => props.projectFields.get(key)?.type === "relation")
.sort(([key1], [key2]) => (key1 < key2 ? -1 : 1));
const relationFields = useMemo(
() =>
Object.entries(recordData?.data || {})
.filter(([key]) => props.projectFields.get(key)?.type === "relation")
.sort(([key1], [key2]) => (key1 < key2 ? -1 : 1)),
[recordData, props.projectFields]
);

const handleJSONExport = (exportProps: ExportHandlerProps) => {
const fileWriter = props.fileWriter;

if (fileWriter) {
exportProps.setExportProgress(100);
const jsonData = JSON.stringify(recordData.data);
fileWriter(exportProps.fileName, jsonData);
exportProps.setExportStatus(ExportStatus.FINISHED);
}
const jsonData = JSON.stringify(recordData.data);
exportProps.setExportStatus(ExportStatus.WRITING);
props
.fileWriter(exportProps.fileName, jsonData)
.then(() => exportProps.setExportStatus(ExportStatus.FINISHED))
.catch((error: Error) => {
exportProps.setExportError(error);
exportProps.setExportStatus(ExportStatus.ERROR);
});
};

return (
Expand All @@ -125,6 +144,13 @@ function RecordData(props: RecordModalProps) {
id="record-data-tabs"
defaultActiveKey="record-data-details"
>
<ErrorModal
title="S3 Reports"
message={s3BucketsMessage}
error={s3ReportError}
show={errorModalShow}
onHide={() => setErrorModalShow(false)}
/>
<ExportModal
{...props}
defaultFileNamePrefix={props.recordID}
Expand All @@ -140,18 +166,18 @@ function RecordData(props: RecordModalProps) {
<hr />
<Container>
<RecordDataField
record={recordData.data}
record={recordData?.data}
field="published_date"
name="Date"
/>
<RecordDataField
record={recordData.data}
record={recordData?.data}
field="site"
name="Site"
/>
{recordData.data["platform"] && (
{recordData?.data?.platform && (
<RecordDataField
record={recordData.data}
record={recordData?.data}
field="platform"
name="Platform"
/>
Expand All @@ -171,7 +197,6 @@ function RecordData(props: RecordModalProps) {
<hr />
<Button
size="sm"
disabled={!props.fileWriter}
variant="dark"
onClick={() => setExportModalShow(true)}
>
Expand Down
Loading

0 comments on commit d955617

Please sign in to comment.