Skip to content

Commit

Permalink
Merge pull request #285 from bento-platform/feat/service-req-ux
Browse files Browse the repository at this point in the history
feat: service request UX improvements
  • Loading branch information
davidlougheed authored Aug 31, 2023
2 parents f9eb659 + a72d1f2 commit 52e3f90
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 106 deletions.
111 changes: 5 additions & 106 deletions src/components/ServiceList.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, {useCallback, useEffect, useMemo, useState} from "react";
import React, {useMemo, useState} from "react";
import { useSelector } from "react-redux";
import PropTypes from "prop-types";

import { Link } from "react-router-dom";

import {Table, Typography, Tag, Icon, Button, Modal, Form, Input, Divider, Skeleton} from "antd";
import {Table, Typography, Tag, Icon, Button} from "antd";

import {getIsAuthenticated, useAuthorizationHeader} from "../lib/auth/utils";
import JsonDisplay from "./JsonDisplay";
import {getIsAuthenticated} from "../lib/auth/utils";

import ServiceRequestModal from "./services/ServiceRequestModal";

const SERVICE_KIND_STYLING = { fontFamily: "monospace" };

Expand Down Expand Up @@ -110,107 +110,6 @@ const serviceColumns = (isAuthenticated, setRequestModalService) => [
];
/* eslint-enable react/prop-types */

const ServiceRequestModal = ({service, onCancel}) => {
const bentoServicesByKind = useSelector(state => state.bentoServices.itemsByKind);
const serviceUrl = useMemo(() => bentoServicesByKind[service]?.url, [bentoServicesByKind, service]);

const [requestPath, setRequestPath] = useState("service-info");
const [requestLoading, setRequestLoading] = useState(false);
const [requestData, setRequestData] = useState(null);
const [requestIsJSON, setRequestIsJSON] = useState(false);

const [hasAttempted, setHasAttempted] = useState(false);

const authHeader = useAuthorizationHeader();

const performRequestModalGet = useCallback(() => {
if (!serviceUrl) {
setRequestData(null);
return;
}
(async () => {
setRequestLoading(true);

try {
const res = await fetch(`${serviceUrl}/${requestPath}`, {
headers: authHeader,
});

if ((res.headers.get("content-type") ?? "").includes("application/json")) {
const data = await res.json();
setRequestIsJSON(true);
setRequestData(data);
} else {
const data = await res.text();
setRequestIsJSON(false);
setRequestData(data);
}
} finally {
setRequestLoading(false);
}
})();
}, [serviceUrl, requestPath, authHeader]);

useEffect(() => {
setRequestData(null);
setRequestIsJSON(false);
setRequestPath("service-info");
setHasAttempted(false);
}, [service]);

useEffect(() => {
if (!hasAttempted) {
performRequestModalGet();
setHasAttempted(true);
}
}, [hasAttempted, performRequestModalGet]);

return (
<Modal
visible={service !== null}
title={`${service}: make a request`}
footer={null}
width={960}
onCancel={onCancel}
>
<Form layout="inline" style={{display: "flex"}}>
<Form.Item style={{flex: 1}} wrapperCol={{span: 24}}>
<Input
addonBefore={(serviceUrl ?? "ERROR") + "/"}
value={requestPath}
disabled={!hasAttempted || requestLoading}
onChange={e => setRequestPath(e.target.value)}
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlFor="submit" onClick={e => {
performRequestModalGet();
e.preventDefault();
}}>GET</Button>
</Form.Item>
</Form>
<Divider />
{requestLoading ? <Skeleton loading={true} /> : (
requestIsJSON
? <JsonDisplay jsonSrc={requestData} />
: (
<div style={{maxWidth: "100%", overflowX: "auto"}}>
<pre>
{((typeof requestData) === "string" || requestData === null)
? requestData
: JSON.stringify(requestData)}
</pre>
</div>
)
)}
</Modal>
);
};
ServiceRequestModal.propTypes = {
service: PropTypes.string,
onCancel: PropTypes.func,
};

const ServiceList = () => {
const [requestModalService, setRequestModalService] = useState(null);

Expand Down
115 changes: 115 additions & 0 deletions src/components/services/ServiceRequestModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, {useCallback, useEffect, useMemo, useState} from "react";
import {useSelector} from "react-redux";
import PropTypes from "prop-types";

import {Button, Divider, Form, Input, Modal, Skeleton} from "antd";

import {useAuthorizationHeader} from "../../lib/auth/utils";
import JsonDisplay from "../JsonDisplay";

const ServiceRequestModal = ({service, onCancel}) => {
const bentoServicesByKind = useSelector(state => state.bentoServices.itemsByKind);
const serviceUrl = useMemo(() => bentoServicesByKind[service]?.url, [bentoServicesByKind, service]);

const [requestPath, setRequestPath] = useState("service-info");
const [requestLoading, setRequestLoading] = useState(false);
const [requestData, setRequestData] = useState(null);
const [requestIsJSON, setRequestIsJSON] = useState(false);

const [hasAttempted, setHasAttempted] = useState(false);

const authHeader = useAuthorizationHeader();

const performRequestModalGet = useCallback(() => {
if (!serviceUrl) {
setRequestData(null);
return;
}
(async () => {
setRequestLoading(true);

const p = requestPath.replace(/^\//, "");
try {
const res = await fetch(`${serviceUrl}/${p}`, {
headers: authHeader,
});

if ((res.headers.get("content-type") ?? "").includes("application/json")) {
const data = await res.json();
setRequestIsJSON(true);
setRequestData(data);
} else {
const data = await res.text();
setRequestIsJSON(false);
setRequestData(data);
}
} finally {
setRequestLoading(false);
setRequestPath(p); // With starting '/' trimmed off if needed
}
})();
}, [serviceUrl, requestPath, authHeader]);

useEffect(() => {
setRequestData(null);
setRequestIsJSON(false);
setRequestPath("service-info");
setHasAttempted(false);
}, [service]);

useEffect(() => {
if (!hasAttempted) {
performRequestModalGet();
setHasAttempted(true);
}
}, [hasAttempted, performRequestModalGet]);

const formSubmit = useCallback(e => {
performRequestModalGet();
e.preventDefault();
}, [performRequestModalGet]);

return (
<Modal
visible={service !== null}
title={`${service}: make a request`}
footer={null}
width={960}
onCancel={onCancel}
>
<Form layout="inline" style={{display: "flex"}} onSubmit={formSubmit}>
<Form.Item style={{flex: 1}} wrapperCol={{span: 24}}>
<Input
addonBefore={(serviceUrl ?? "ERROR") + "/"}
value={requestPath}
disabled={!hasAttempted || requestLoading}
onChange={e => setRequestPath(e.target.value)}
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlFor="submit" loading={requestLoading} onClick={formSubmit}>GET</Button>
</Form.Item>
</Form>
<Divider />
{requestLoading ? <Skeleton loading={true} /> : (
requestIsJSON
? <JsonDisplay jsonSrc={requestData} />
: (
<div style={{maxWidth: "100%", overflowX: "auto"}}>
<pre>
{((typeof requestData) === "string" || requestData === null)
? requestData
: JSON.stringify(requestData)}
</pre>
</div>
)
)}
</Modal>
);
};
ServiceRequestModal.propTypes = {
service: PropTypes.string,
onCancel: PropTypes.func,
};

export default ServiceRequestModal;

0 comments on commit 52e3f90

Please sign in to comment.