From f6807ccf826f7aee454eb45378feb0e0d8fee1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Wed, 17 Apr 2024 12:18:06 +0200 Subject: [PATCH 01/19] Add messages response titles --- .../components/parts/method/response/ResponsesList.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/web/src/components/parts/method/response/ResponsesList.tsx b/web/src/components/parts/method/response/ResponsesList.tsx index 8a5ebb6..1fa134c 100644 --- a/web/src/components/parts/method/response/ResponsesList.tsx +++ b/web/src/components/parts/method/response/ResponsesList.tsx @@ -9,9 +9,17 @@ export default function ResponsesList({ responses }: { responses: unknown[] }) {
{responses.map((response, index) => (
- {JSON.stringify(response, null, 2)} + +
Response {index + 1}
+ {JSON.stringify(response, null, 2)} +
))} + + + Total messages: {responses.length} + +
); } From e8d8b744764e50c4ae09dd0ac0d4fa4eee02f749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Wed, 17 Apr 2024 12:18:18 +0200 Subject: [PATCH 02/19] Improve methods coloring --- web/src/components/parts/method/Method.tsx | 15 +++++++++++++-- web/src/services/protobufjs.ts | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/web/src/components/parts/method/Method.tsx b/web/src/components/parts/method/Method.tsx index c6470cc..de4325d 100644 --- a/web/src/components/parts/method/Method.tsx +++ b/web/src/components/parts/method/Method.tsx @@ -1,6 +1,6 @@ import { Badge, Collapse, ProgressBar, Spinner } from "react-bootstrap"; import protobuf from "protobufjs"; -import { useState } from "react"; +import { CSSProperties, useState } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; @@ -78,8 +78,19 @@ export default function Method({ method.comment ?? "", ); + const style = { "--bs-bg-opacity": 0.1 } as CSSProperties; + return ( -
+
+ ); From 7965b17876249814f9bb99c30a5a92563af064f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 00:23:44 +0200 Subject: [PATCH 07/19] Add authorization types tests --- .../components/metadata/Metadata.tsx | 78 ++++++++++--------- web/src/components/metadata/Authorization.tsx | 1 + 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/web/__tests__/components/metadata/Metadata.tsx b/web/__tests__/components/metadata/Metadata.tsx index 73995b8..6c01985 100644 --- a/web/__tests__/components/metadata/Metadata.tsx +++ b/web/__tests__/components/metadata/Metadata.tsx @@ -162,43 +162,49 @@ describe("Metadata", () => { ).not.toBeInTheDocument(); }); - it("renders - add authorization", async () => { - let metadata: Metadata = {}; - const contextMetadata: MetadataContextData = { - metadata: metadata, - setMetadata: (fun) => { - if (typeof fun !== "function") { - metadata = { ...metadata, ...fun }; - } else { - metadata = { ...fun(metadata) }; - } - return metadata; - }, - }; - - await act(async () => { - render( - - {}} /> - , + const authorizationTypes = Object.values(AuthorizationType); + authorizationTypes.forEach((type) => { + it(`renders - add authorization - ${type}`, async () => { + let metadata: Metadata = {}; + const contextMetadata: MetadataContextData = { + metadata: metadata, + setMetadata: (fun) => { + if (typeof fun !== "function") { + metadata = { ...metadata, ...fun }; + } else { + metadata = { ...fun(metadata) }; + } + return metadata; + }, + }; + + await act(async () => { + render( + + {}} /> + , + ); + }); + + const element = screen.getByTestId("metadata-modal"); + expect(element).toBeInTheDocument(); + + const select = screen.getByTestId("metadata-authorization-select"); + const input = screen.getByTestId("metadata-authorization-input"); + const button = screen.getByTestId("metadata-authorization-set"); + + const myPrivateToken = "MyPrivateToken"; + + await act(async () => { + fireEvent.change(select, { target: { value: type } }); + fireEvent.change(input, { target: { value: myPrivateToken } }); + button.click(); + }); + + expect(select).toHaveTextContent(type); + expect(metadata[typeToKey[type]]).toBe( + `${typeToPrefix[type]} ${myPrivateToken}`.trim(), ); }); - - const element = screen.getByTestId("metadata-modal"); - expect(element).toBeInTheDocument(); - - const input = screen.getByTestId("metadata-authorization-input"); - const button = screen.getByTestId("metadata-authorization-set"); - - const myPrivateToken = "MyPrivateToken"; - - await act(async () => { - fireEvent.change(input, { target: { value: myPrivateToken } }); - button.click(); - }); - - expect(metadata[typeToKey[AuthorizationType.BEARER]]).toBe( - `${typeToPrefix[AuthorizationType.BEARER]} ${myPrivateToken}`, - ); }); }); diff --git a/web/src/components/metadata/Authorization.tsx b/web/src/components/metadata/Authorization.tsx index fc03915..1c82dab 100644 --- a/web/src/components/metadata/Authorization.tsx +++ b/web/src/components/metadata/Authorization.tsx @@ -58,6 +58,7 @@ export default function Authorization() { onChange={(e) => { setAuthorizationType(e.target.value as AuthorizationType); }} + data-testid="metadata-authorization-select" className="mb-2" > {authorizationTypes.map((type) => ( From 0707f44f532a9c325ed0434a22257cc22bae50b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 01:50:46 +0200 Subject: [PATCH 08/19] Collapsible endpoints (services, types, enums --- .../components/CollapsibleHeader.test.tsx | 31 ++++ web/__tests__/components/Endpoints.test.tsx | 139 +++++++++++++++++- web/src/components/CollapsibleHeader.tsx | 38 +++++ web/src/components/Endpoints.tsx | 121 +++++++++++---- web/src/components/parts/Service.tsx | 20 +-- web/src/components/parts/method/Method.tsx | 15 +- 6 files changed, 313 insertions(+), 51 deletions(-) create mode 100644 web/__tests__/components/CollapsibleHeader.test.tsx create mode 100644 web/src/components/CollapsibleHeader.tsx diff --git a/web/__tests__/components/CollapsibleHeader.test.tsx b/web/__tests__/components/CollapsibleHeader.test.tsx new file mode 100644 index 0000000..e3b8cef --- /dev/null +++ b/web/__tests__/components/CollapsibleHeader.test.tsx @@ -0,0 +1,31 @@ +import { act, render } from "@testing-library/react"; +import CollapsibleHeader from "@/components/CollapsibleHeader"; + +describe("CollapsibleHeader", () => { + it("renders - expanded", async () => { + const onClick = jest.fn(); + const elementRendered = await act(async () => { + return render( + + Header + , + ); + }); + + const element = elementRendered.container.firstChild; + expect(element).toBeInTheDocument(); + }); + it("renders - collapsed", async () => { + const onClick = jest.fn(); + const elementRendered = await act(async () => { + return render( + + Header + , + ); + }); + + const element = elementRendered.container.firstChild; + expect(element).toBeInTheDocument(); + }); +}); diff --git a/web/__tests__/components/Endpoints.test.tsx b/web/__tests__/components/Endpoints.test.tsx index f1efc94..121fe52 100644 --- a/web/__tests__/components/Endpoints.test.tsx +++ b/web/__tests__/components/Endpoints.test.tsx @@ -7,7 +7,7 @@ import { context } from "../../tests/protobufjs-source"; describe("Endpoints", () => { beforeEach(async () => { await act(async () => { - render( + return render( { const services = screen.getByTestId("enums"); expect(services).toBeInTheDocument(); }); + + it("collapse services", async () => { + const services = screen.getByTestId("services"); + + const button = services.querySelector("button"); + expect(button).toBeInTheDocument(); + if (!button) { + throw new Error("Button not found"); + } + + const detailsVisible = screen.queryAllByTestId("service-detail"); + detailsVisible.forEach((detail) => { + expect(detail).toBeVisible(); + }); + + await act(async () => { + button.click(); + }); + + new Promise((resolve) => { + setTimeout(() => { + const detailsHidden = screen.queryAllByTestId("service-detail"); + detailsHidden.forEach((detail) => { + expect(detail).not.toBeVisible(); + }); + resolve(undefined); + }, 1000); + }); + }); + + it("collapse types", async () => { + const services = screen.getByTestId("types"); + + const button = services.querySelector("button"); + expect(button).toBeInTheDocument(); + if (!button) { + throw new Error("Button not found"); + } + + const detailsVisible = screen.queryAllByTestId("type-detail"); + detailsVisible.forEach((detail) => { + expect(detail).toBeVisible(); + }); + + await act(async () => { + button.click(); + }); + + new Promise((resolve) => { + setTimeout(() => { + const detailsHidden = screen.queryAllByTestId("type-detail"); + detailsHidden.forEach((detail) => { + expect(detail).not.toBeVisible(); + }); + resolve(undefined); + }, 1000); + }); + }); + + it("collapse enums", async () => { + const services = screen.getByTestId("enums"); + + const button = services.querySelector("button"); + expect(button).toBeInTheDocument(); + if (!button) { + throw new Error("Button not found"); + } + + const detailsVisible = screen.queryAllByTestId("enum-detail"); + detailsVisible.forEach((detail) => { + expect(detail).toBeVisible(); + }); + + await act(async () => { + button.click(); + }); + + new Promise((resolve) => { + setTimeout(() => { + const detailsHidden = screen.queryAllByTestId("enum-detail"); + detailsHidden.forEach((detail) => { + expect(detail).not.toBeVisible(); + }); + resolve(undefined); + }, 1000); + }); + }); +}); + +describe("Endpoints Errors", () => { + it("renders error", async () => { + const errorMessage = "Test error"; + const rendered = await act(async () => { + return render( + + + , + ); + }); + + const containerElement = rendered.container.firstChild; + expect(containerElement).toHaveTextContent(errorMessage); + + const services = rendered.queryByTestId("services"); + expect(services).not.toBeInTheDocument(); + }); + + it("renders no context", async () => { + const rendered = await act(async () => { + return render( + + + , + ); + }); + + const services = rendered.queryByTestId("services"); + expect(services).not.toBeInTheDocument(); + }); }); diff --git a/web/src/components/CollapsibleHeader.tsx b/web/src/components/CollapsibleHeader.tsx new file mode 100644 index 0000000..13ad1b4 --- /dev/null +++ b/web/src/components/CollapsibleHeader.tsx @@ -0,0 +1,38 @@ +import { ReactNode } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp"; +import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; + +export interface CollapsibleHeaderProps { + onClick: () => void; + open: boolean; + className?: string; + children: ReactNode; +} + +export default function CollapsibleHeader({ + onClick, + children, + className, + open, +}: CollapsibleHeaderProps) { + return ( + + ); +} diff --git a/web/src/components/Endpoints.tsx b/web/src/components/Endpoints.tsx index 44b782c..558209a 100644 --- a/web/src/components/Endpoints.tsx +++ b/web/src/components/Endpoints.tsx @@ -8,9 +8,34 @@ import { import Service from "@/components/parts/Service"; import Type from "@/components/parts/Type"; import EnumType from "@/components/parts/EnumType"; -import { Spinner } from "react-bootstrap"; +import { Collapse, Spinner } from "react-bootstrap"; import { FILTERED_NAMESPACES } from "@/types/constants"; import JSONBlock from "@/components/JSONBlock"; +import { useReducer } from "react"; +import CollapsibleHeader from "@/components/CollapsibleHeader"; + +enum OpenAction { + TOGGLE, +} + +enum Category { + SERVICES, + TYPES, + ENUMS, +} + +function openServices( + state: Record, + action: { type: OpenAction; target: Category }, +) { + switch (action.type) { + case OpenAction.TOGGLE: + return { + ...state, + [action.target]: !state[action.target], + }; + } +} /** * List of services, types and enums @@ -18,6 +43,12 @@ import JSONBlock from "@/components/JSONBlock"; export default function Endpoints() { const { context, error } = useSourceContext(); + const [openState, dispatchOpen] = useReducer(openServices, { + [Category.SERVICES]: true, + [Category.TYPES]: true, + [Category.ENUMS]: true, + }); + if (!!error) { return (
@@ -47,38 +78,76 @@ export default function Endpoints() { return !FILTERED_NAMESPACES.includes(type.fullName.split(".")[1]); }); + const categoryClasses = "w-100 ps-1 pe-2"; + return (
-

Services

- {services.map((service) => ( - - ))} - {services.length === 0 && ( -
No services found
- )} + + dispatchOpen({ type: OpenAction.TOGGLE, target: Category.SERVICES }) + } + > + Services + + +
+ {services.map((service) => ( + + ))} + {services.length === 0 && ( +
No services found
+ )} +
+
-

Types

-
- {types.map((type) => ( - - ))} -
- {types.length === 0 && ( -
No types found
- )} + + dispatchOpen({ type: OpenAction.TOGGLE, target: Category.TYPES }) + } + > + Types + + +
+
+ {types.map((type) => ( + + ))} +
+ {types.length === 0 && ( +
No types found
+ )} +
+
-

Enums

-
- {enums.map((enumType) => ( - - ))} -
- {types.length === 0 && ( -
No types found
- )} + + dispatchOpen({ type: OpenAction.TOGGLE, target: Category.ENUMS }) + } + > + Enums + + +
+
+ {enums.map((enumType) => ( + + ))} +
+ {types.length === 0 && ( +
No types found
+ )} +
+
); diff --git a/web/src/components/parts/Service.tsx b/web/src/components/parts/Service.tsx index 00a86f6..19d1100 100644 --- a/web/src/components/parts/Service.tsx +++ b/web/src/components/parts/Service.tsx @@ -1,12 +1,10 @@ import Method from "@/components/parts/method/Method"; import { Collapse } from "react-bootstrap"; import { useState } from "react"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp"; -import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; import protobuf from "protobufjs"; import MethodContextProvider from "@/contexts/MethodContext"; import Options from "@/components/parts/helpers/Options"; +import CollapsibleHeader from "@/components/CollapsibleHeader"; export interface ServiceProps { service: protobuf.Service; @@ -17,11 +15,12 @@ export default function Service({ service }: ServiceProps) { return (
- +
diff --git a/web/src/components/parts/method/Method.tsx b/web/src/components/parts/method/Method.tsx index de4325d..4f700ee 100644 --- a/web/src/components/parts/method/Method.tsx +++ b/web/src/components/parts/method/Method.tsx @@ -22,6 +22,7 @@ import SectionBody from "./section/SectionBody"; import SectionHeader from "@/components/parts/method/section/SectionHeader"; import RequestForm from "@/components/parts/method/request/RequestForm"; import Options from "@/components/parts/helpers/Options"; +import CollapsibleHeader from "@/components/CollapsibleHeader"; const COMMENT_DELIMITER = "\n"; @@ -91,8 +92,9 @@ export default function Method({ ].join(" ")} style={style} > -
- +
From cd50b8306b2e0dc1c78c1a05309a57539b9c2914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:17:18 +0200 Subject: [PATCH 09/19] Emphasize execute button with icon and border, move cancel bottom to the right --- .../method/request/RequestFormExecution.tsx | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/web/src/components/parts/method/request/RequestFormExecution.tsx b/web/src/components/parts/method/request/RequestFormExecution.tsx index 7db18f0..7dac707 100644 --- a/web/src/components/parts/method/request/RequestFormExecution.tsx +++ b/web/src/components/parts/method/request/RequestFormExecution.tsx @@ -12,6 +12,8 @@ import { getRequestTypeDisplayName, RequestType, } from "@/services/protobufjs"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faPlay } from "@fortawesome/free-solid-svg-icons/faPlay"; const ERROR_DELIMITER = ": "; @@ -126,31 +128,43 @@ export default function RequestFormExecution({ Problems found in the request. Please fix them before executing.
)} - - {processing && ( - )} + {processing && ( + + )} +
); } From d71f151e87e2d64d977d5b92f2dcc638cddfcaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:24:14 +0200 Subject: [PATCH 10/19] Request cancelation - show already received data --- .../method/request/RequestFormExecution.tsx | 18 +++++++++++------- .../parts/method/response/ResponseError.tsx | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/web/src/components/parts/method/request/RequestFormExecution.tsx b/web/src/components/parts/method/request/RequestFormExecution.tsx index 7dac707..bbf0fa1 100644 --- a/web/src/components/parts/method/request/RequestFormExecution.tsx +++ b/web/src/components/parts/method/request/RequestFormExecution.tsx @@ -50,11 +50,12 @@ export default function RequestFormExecution({ ) => { const backend = backends[SELECTED_BACKEND][type]; if (!backend) { - functions.setResponse({ + functions.setResponse((it) => ({ + ...it, error: new Error( `${getRequestTypeDisplayName(type)} is not supported yet`, ), - }); + })); return; } await backend( @@ -107,14 +108,17 @@ export default function RequestFormExecution({ } catch (e) { console.error(e); if (e instanceof Error) { - functions.setResponse({ - error: e, - }); + const error = e; + functions.setResponse((it) => ({ + ...it, + error, + })); } if (e instanceof CancelError) { - functions.setResponse({ + functions.setResponse((it) => ({ + ...it, error: new Error("Request canceled"), - }); + })); } } finally { functions.setCancelFunction(undefined); diff --git a/web/src/components/parts/method/response/ResponseError.tsx b/web/src/components/parts/method/response/ResponseError.tsx index 35e9862..8e1f099 100644 --- a/web/src/components/parts/method/response/ResponseError.tsx +++ b/web/src/components/parts/method/response/ResponseError.tsx @@ -7,7 +7,7 @@ export default function ResponseError({ error }: { error: Error | undefined }) { } return ( -
+
{error instanceof RpcError && ( <>
Error {error.code}
From 4648a65e9f50f1f80d20ef39f67f329a008a7a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:25:27 +0200 Subject: [PATCH 11/19] Rename total messages to total responses --- web/src/components/parts/method/response/ResponsesList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/parts/method/response/ResponsesList.tsx b/web/src/components/parts/method/response/ResponsesList.tsx index 1fa134c..afd5365 100644 --- a/web/src/components/parts/method/response/ResponsesList.tsx +++ b/web/src/components/parts/method/response/ResponsesList.tsx @@ -17,7 +17,7 @@ export default function ResponsesList({ responses }: { responses: unknown[] }) { ))} - Total messages: {responses.length} + Total responses: {responses.length}
From d5756622f62a73692f1ae3893935a33c98d8dc97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:35:27 +0200 Subject: [PATCH 12/19] Improve long comments wrapping --- web/src/components/parts/EnumType.tsx | 2 +- web/src/components/parts/Service.tsx | 14 +++++++------- web/src/components/parts/field/FieldComment.tsx | 2 +- web/src/components/parts/method/Method.tsx | 2 +- web/src/scss/App.scss | 4 ++++ 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/web/src/components/parts/EnumType.tsx b/web/src/components/parts/EnumType.tsx index c12c090..1ed909a 100644 --- a/web/src/components/parts/EnumType.tsx +++ b/web/src/components/parts/EnumType.tsx @@ -24,7 +24,7 @@ export default function EnumType({ enumType, dark, expanded }: EnumProps) { onClick={() => setOpen((open) => !open)} > [Enum] {enumType.fullName} - + {enumType.comment} diff --git a/web/src/components/parts/Service.tsx b/web/src/components/parts/Service.tsx index 19d1100..91025a8 100644 --- a/web/src/components/parts/Service.tsx +++ b/web/src/components/parts/Service.tsx @@ -20,16 +20,16 @@ export default function Service({ service }: ServiceProps) { onClick={() => setOpen((open) => !open)} className="border-0 rounded-bottom-0 px-2" > -
+
-
+ {service.fullName.replace(".", "")} -
- -
-
- {service.comment} + + + {service.comment} +
+

diff --git a/web/src/components/parts/field/FieldComment.tsx b/web/src/components/parts/field/FieldComment.tsx index 3a3d439..44ab544 100644 --- a/web/src/components/parts/field/FieldComment.tsx +++ b/web/src/components/parts/field/FieldComment.tsx @@ -16,7 +16,7 @@ export default function FieldComment({ field }: FieldCommentProps) { "fst-italic", "small", "text-secondary", - "whitespace-pre", + "whitespace-pre-wrap", ].join(" ")} > {field.comment} diff --git a/web/src/components/parts/method/Method.tsx b/web/src/components/parts/method/Method.tsx index 4f700ee..948ae6d 100644 --- a/web/src/components/parts/method/Method.tsx +++ b/web/src/components/parts/method/Method.tsx @@ -118,7 +118,7 @@ export default function Method({
{!!commentRest && ( -
+
{commentRest}
diff --git a/web/src/scss/App.scss b/web/src/scss/App.scss index 7b9b4ad..3a16807 100644 --- a/web/src/scss/App.scss +++ b/web/src/scss/App.scss @@ -15,6 +15,10 @@ $primary: green; white-space: pre; } +.whitespace-pre-wrap { + white-space: pre-wrap; +} + .grid-metadata { display: grid; grid-template-columns: 1fr 1fr 38px; From fbc1779f9f841ddf1dcc42e1e3692e5ed0fda711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:38:19 +0200 Subject: [PATCH 13/19] Try to increase timeout for collapse --- web/__tests__/components/Endpoints.test.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/__tests__/components/Endpoints.test.tsx b/web/__tests__/components/Endpoints.test.tsx index 121fe52..27574e2 100644 --- a/web/__tests__/components/Endpoints.test.tsx +++ b/web/__tests__/components/Endpoints.test.tsx @@ -4,6 +4,8 @@ import { SourceContext } from "@/contexts/SourceContext"; import { DEFAULT_HOSTNAME } from "@/types/constants"; import { context } from "../../tests/protobufjs-source"; +const COLLAPSE_TIMEOUT = 2000; + describe("Endpoints", () => { beforeEach(async () => { await act(async () => { @@ -64,7 +66,7 @@ describe("Endpoints", () => { expect(detail).not.toBeVisible(); }); resolve(undefined); - }, 1000); + }, COLLAPSE_TIMEOUT); }); }); @@ -93,7 +95,7 @@ describe("Endpoints", () => { expect(detail).not.toBeVisible(); }); resolve(undefined); - }, 1000); + }, COLLAPSE_TIMEOUT); }); }); @@ -122,7 +124,7 @@ describe("Endpoints", () => { expect(detail).not.toBeVisible(); }); resolve(undefined); - }, 1000); + }, COLLAPSE_TIMEOUT); }); }); }); From b5ccb1c9caf5ce9e75e86c6ed053d797a4236ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:38:39 +0200 Subject: [PATCH 14/19] Exclude web/out folder from WebStorm indexing --- .idea/grpcflair.iml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/grpcflair.iml b/.idea/grpcflair.iml index 95a1784..8c20726 100644 --- a/.idea/grpcflair.iml +++ b/.idea/grpcflair.iml @@ -6,6 +6,7 @@ + From 8d35c5aa9840e2f80ac64332e5390334dfdbfbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 02:44:18 +0200 Subject: [PATCH 15/19] Change request JSON to the light mode --- .../components/parts/method/__snapshots__/Method.test.tsx.snap | 2 +- web/src/components/parts/method/Method.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/__tests__/components/parts/method/__snapshots__/Method.test.tsx.snap b/web/__tests__/components/parts/method/__snapshots__/Method.test.tsx.snap index ef11167..d2efb33 100644 --- a/web/__tests__/components/parts/method/__snapshots__/Method.test.tsx.snap +++ b/web/__tests__/components/parts/method/__snapshots__/Method.test.tsx.snap @@ -41,7 +41,7 @@ exports[`Method renders - execution 1`] = `
diff --git a/web/src/components/parts/method/Method.tsx b/web/src/components/parts/method/Method.tsx
index 948ae6d..bd41779 100644
--- a/web/src/components/parts/method/Method.tsx
+++ b/web/src/components/parts/method/Method.tsx
@@ -174,7 +174,7 @@ export default function Method({
                         {JSON.stringify(request.metadata, null, 2)}
                       
                     
- + {JSON.stringify(request.message, null, 2)}
From b1bdeb6ca7cf2f95d8982879a0438d276ba14449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 03:39:53 +0200 Subject: [PATCH 16/19] Make responses list max height 50vh, scroll to bottom --- .../parts/method/response/ResponsesList.tsx | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/web/src/components/parts/method/response/ResponsesList.tsx b/web/src/components/parts/method/response/ResponsesList.tsx index afd5365..92ea413 100644 --- a/web/src/components/parts/method/response/ResponsesList.tsx +++ b/web/src/components/parts/method/response/ResponsesList.tsx @@ -6,20 +6,27 @@ export default function ResponsesList({ responses }: { responses: unknown[] }) { } return ( -
- {responses.map((response, index) => ( -
- -
Response {index + 1}
- {JSON.stringify(response, null, 2)} -
+ <> +
+
+ {responses.map((response, index) => ( + +
Response {index + 1}
+ {JSON.stringify(response, null, 2)} +
+ ))}
- ))} - +
+ Total responses: {responses.length} -
+ ); } From f719bf056de0a8e0a14470aad00d6a18fbd39334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dobr=C3=BD?= Date: Thu, 18 Apr 2024 04:25:15 +0200 Subject: [PATCH 17/19] Improve metadata & authorization button --- web/src/app/page.tsx | 20 +++++++++++++------- web/src/scss/App.scss | 12 ++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 75ccebe..9ee3545 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -29,33 +29,39 @@ export default function Home() {

{description}

-
-
+
+
Method - +
-
+
Base gRPC Url
setHostname(e.target.value)} value={hostname} + size="sm" + style={{ width: "20rem" }} data-testid="hostname-input" />
-
+
+
Date: Thu, 18 Apr 2024 05:04:20 +0200 Subject: [PATCH 18/19] Fix tests with Collapse animations, ignore coverage folder --- .idea/grpcflair.iml | 1 + web/__tests__/components/Endpoints.test.tsx | 61 ++++----------------- web/src/components/Endpoints.tsx | 12 ++-- web/src/components/parts/Type.tsx | 1 + web/tests/mocks/react-bootstrap.tsx | 15 +++++ 5 files changed, 35 insertions(+), 55 deletions(-) create mode 100644 web/tests/mocks/react-bootstrap.tsx diff --git a/.idea/grpcflair.iml b/.idea/grpcflair.iml index 8c20726..dde29ad 100644 --- a/.idea/grpcflair.iml +++ b/.idea/grpcflair.iml @@ -6,6 +6,7 @@ + diff --git a/web/__tests__/components/Endpoints.test.tsx b/web/__tests__/components/Endpoints.test.tsx index 27574e2..30aef64 100644 --- a/web/__tests__/components/Endpoints.test.tsx +++ b/web/__tests__/components/Endpoints.test.tsx @@ -1,11 +1,10 @@ +import "../../tests/mocks/react-bootstrap"; import { act, render, screen } from "@testing-library/react"; import Endpoints from "@/components/Endpoints"; import { SourceContext } from "@/contexts/SourceContext"; import { DEFAULT_HOSTNAME } from "@/types/constants"; import { context } from "../../tests/protobufjs-source"; -const COLLAPSE_TIMEOUT = 2000; - describe("Endpoints", () => { beforeEach(async () => { await act(async () => { @@ -43,89 +42,53 @@ describe("Endpoints", () => { it("collapse services", async () => { const services = screen.getByTestId("services"); + expect(services).toBeVisible(); - const button = services.querySelector("button"); + const button = screen.getByText("Services"); expect(button).toBeInTheDocument(); if (!button) { throw new Error("Button not found"); } - const detailsVisible = screen.queryAllByTestId("service-detail"); - detailsVisible.forEach((detail) => { - expect(detail).toBeVisible(); - }); - await act(async () => { button.click(); }); - new Promise((resolve) => { - setTimeout(() => { - const detailsHidden = screen.queryAllByTestId("service-detail"); - detailsHidden.forEach((detail) => { - expect(detail).not.toBeVisible(); - }); - resolve(undefined); - }, COLLAPSE_TIMEOUT); - }); + expect(services).not.toBeVisible(); }); it("collapse types", async () => { - const services = screen.getByTestId("types"); + const types = screen.getByTestId("types"); + expect(types).toBeVisible(); - const button = services.querySelector("button"); + const button = screen.getByText("Types"); expect(button).toBeInTheDocument(); if (!button) { throw new Error("Button not found"); } - const detailsVisible = screen.queryAllByTestId("type-detail"); - detailsVisible.forEach((detail) => { - expect(detail).toBeVisible(); - }); - await act(async () => { button.click(); }); - new Promise((resolve) => { - setTimeout(() => { - const detailsHidden = screen.queryAllByTestId("type-detail"); - detailsHidden.forEach((detail) => { - expect(detail).not.toBeVisible(); - }); - resolve(undefined); - }, COLLAPSE_TIMEOUT); - }); + expect(types).not.toBeVisible(); }); it("collapse enums", async () => { - const services = screen.getByTestId("enums"); + const enums = screen.getByTestId("enums"); + expect(enums).toBeVisible(); - const button = services.querySelector("button"); + const button = screen.getByText("Enums"); expect(button).toBeInTheDocument(); if (!button) { throw new Error("Button not found"); } - const detailsVisible = screen.queryAllByTestId("enum-detail"); - detailsVisible.forEach((detail) => { - expect(detail).toBeVisible(); - }); - await act(async () => { button.click(); }); - new Promise((resolve) => { - setTimeout(() => { - const detailsHidden = screen.queryAllByTestId("enum-detail"); - detailsHidden.forEach((detail) => { - expect(detail).not.toBeVisible(); - }); - resolve(undefined); - }, COLLAPSE_TIMEOUT); - }); + expect(enums).not.toBeVisible(); }); }); diff --git a/web/src/components/Endpoints.tsx b/web/src/components/Endpoints.tsx index 558209a..a2214f5 100644 --- a/web/src/components/Endpoints.tsx +++ b/web/src/components/Endpoints.tsx @@ -82,7 +82,7 @@ export default function Endpoints() { return (
-
+
Services -
+
{services.map((service) => ( ))} @@ -103,7 +103,7 @@ export default function Endpoints() {
-
+
Types -
+
{types.map((type) => ( @@ -126,7 +126,7 @@ export default function Endpoints() {
-
+
Enums -
+
{enums.map((enumType) => ( diff --git a/web/src/components/parts/Type.tsx b/web/src/components/parts/Type.tsx index d6d0af6..827f779 100644 --- a/web/src/components/parts/Type.tsx +++ b/web/src/components/parts/Type.tsx @@ -45,6 +45,7 @@ export default function Type({ type, dark, expanded }: TypeProps) { dark ? "bg-dark text-light" : "", ].join(" ")} data-testid="type-detail" + data-type-name={type.fullName} >