Skip to content

Commit

Permalink
Section design toggle
Browse files Browse the repository at this point in the history
  • Loading branch information
riccardo-forina committed Nov 28, 2024
1 parent fdde94b commit f3a3911
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 131 deletions.
76 changes: 43 additions & 33 deletions packages/ui/src/components/Section.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,68 @@
import { ReactNode } from "react";
import { createContext, ReactNode, useContext, useState } from "react";
import {
Badge,
Button,
Card,
CardBody,
CardHeader,
CardTitle,
Split,
SplitItem,
Switch,
} from "@patternfly/react-core";
import { PencilAltIcon } from "@patternfly/react-icons";

const SectionContext = createContext<{
view: "viewer" | "designer";
toggleView: () => void;
}>({
view: "viewer",
toggleView: () => {},
});

export function useSection() {
return useContext(SectionContext).view;
}

export function Section({
title,
count,
id,
children,
onEdit,
}: {
title: ReactNode;
count?: number;
id: string;
children: ReactNode;
onEdit?: () => void;
}) {
const [view, setView] = useState<"viewer" | "designer">("viewer");
const toggleView = () =>
setView((v) => (v === "viewer" ? "designer" : "viewer"));
return (
<Card isPlain={true} isLarge={true} id={id}>
<CardHeader
actions={{
actions: (
<>
{onEdit && (
<Button
variant={"control"}
icon={<PencilAltIcon />}
onClick={onEdit}
/>
<SectionContext.Provider value={{ view, toggleView }}>
<Card isPlain={true} isLarge={true} id={id}>
<CardHeader
actions={{
actions: (
<Switch
isChecked={view === "designer"}
onChange={toggleView}
label={"Design"}
/>
),
}}
>
<CardTitle>
<Split hasGutter={true}>
<SplitItem>{title}</SplitItem>
{count !== undefined && (
<SplitItem>
<Badge>{count}</Badge>
</SplitItem>
)}
</>
),
}}
>
<CardTitle>
<Split hasGutter={true}>
<SplitItem>{title}</SplitItem>
{count !== undefined && (
<SplitItem>
<Badge>{count}</Badge>
</SplitItem>
)}
</Split>
</CardTitle>
</CardHeader>
<CardBody>{children}</CardBody>
</Card>
</Split>
</CardTitle>
</CardHeader>
<CardBody>{children}</CardBody>
</Card>
</SectionContext.Provider>
);
}
5 changes: 2 additions & 3 deletions packages/ui/src/documentDesigner/Designer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import { SecurityScheme } from "./SecurityScheme.tsx";
import { SecurityRequirements } from "./SecurityRequirements.tsx";
import { useMachineSelector } from "./DocumentDesignerMachineContext.ts";
import { DesignerLayout } from "./DesignerLayout.tsx";
import { PathsExplorer } from "./PathsExplorer.tsx";
import { PathsTree } from "./PathsTree.tsx";
import { OpenApiEditorMachineContext } from "../OpenApiEditor.tsx";
import { Paths } from "./Paths.tsx";

export function Designer() {
const {
Expand Down Expand Up @@ -38,7 +37,7 @@ export function Designer() {
return (
<DesignerLayout
info={<Info />}
paths={editable ? <PathsTree /> : <PathsExplorer />}
paths={<Paths />}
pathsCount={pathsCount}
contact={<Contact />}
license={<License />}
Expand Down
11 changes: 7 additions & 4 deletions packages/ui/src/documentDesigner/Info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
useMachineActorRef,
useMachineSelector,
} from "./DocumentDesignerMachineContext.ts";
import { useSection } from "../components/Section.tsx";

export function Info() {
const { title, version, description, editable } = useMachineSelector(
Expand All @@ -20,8 +21,10 @@ export function Info() {
description: context.description,
editable: context.editable,
};
}
},
);
const view = useSection();
const isEditable = view === "designer" || editable;
const actorRef = useMachineActorRef();
return (
<DescriptionList isHorizontal={true}>
Expand All @@ -33,7 +36,7 @@ export function Info() {
actorRef.send({ type: "CHANGE_TITLE", title });
}}
value={title}
editing={editable}
editing={isEditable}
autoFocus={true}
/>
</DescriptionListDescription>
Expand All @@ -46,14 +49,14 @@ export function Info() {
actorRef.send({ type: "CHANGE_VERSION", version });
}}
value={version}
editing={editable}
editing={isEditable}
/>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Description</DescriptionListTerm>
<DescriptionListDescription>
<Markdown editing={editable}>{description}</Markdown>
<Markdown editing={isEditable}>{description}</Markdown>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
Expand Down
13 changes: 13 additions & 0 deletions packages/ui/src/documentDesigner/Paths.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useSection } from "../components/Section.tsx";
import { useMachineSelector } from "./DocumentDesignerMachineContext.ts";
import { PathsTree } from "./PathsTree.tsx";
import { PathsExplorer } from "./PathsExplorer.tsx";

export function Paths() {
const { editable } = useMachineSelector(({ context }) => ({
editable: context.editable,
}));
const view = useSection();
const isEditable = view === "designer" || editable;
return isEditable ? <PathsTree /> : <PathsExplorer />;
}
186 changes: 95 additions & 91 deletions packages/ui/src/documentDesigner/PathsExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { Markdown } from "../components/Markdown.tsx";
import { Path } from "../components/Path.tsx";
import { TagLabel } from "../components/TagLabel.tsx";
import { assign, setup } from "xstate";
import { useMachine } from "@xstate/react";
import { useActor } from "@xstate/react";
import { SectionSkeleton } from "../components/SectionSkeleton.tsx";
import { useState } from "react";
import { OperationLabel } from "./OperationLabel.tsx";
Expand Down Expand Up @@ -123,7 +123,7 @@ export function PathsExplorer() {
allPaths: context.paths,
};
});
const [state, send] = useMachine(machine, {
const [state, send] = useActor(machine, {
input: {
paths: allPaths,
},
Expand Down Expand Up @@ -289,95 +289,99 @@ function OperationRow({
id={`path-${pathId}-operation-${name}-expand`}
isHidden={!isExpanded}
>
<Stack hasGutter={true}>
{operation.description && (
<Markdown searchTerm={searchTerm}>{operation.description}</Markdown>
)}
{operation.pathParameters.length +
operation.headerParameters.length +
operation.queryParameters.length +
operation.headerParameters.length >
0 && (
<>
<Title headingLevel={"h4"}>Request</Title>
<Accordion>
{operation.pathParameters.length > 0 && (
<AccordionSection
title={"Path parameters"}
id={"path-params"}
startExpanded={false}
count={operation.pathParameters.length}
>
<Parameters
parameters={operation.pathParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
{operation.queryParameters.length > 0 && (
<AccordionSection
title={"Query parameters"}
id={"query-params"}
startExpanded={false}
count={operation.queryParameters.length}
>
<Parameters
parameters={operation.queryParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
{operation.headerParameters.length > 0 && (
<AccordionSection
title={"Header parameters"}
id={"header-params"}
startExpanded={false}
count={operation.headerParameters.length}
>
<Parameters
parameters={operation.headerParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
{operation.cookieParameters.length > 0 && (
<AccordionSection
title={"Cookie parameters"}
id={"cookie-params"}
startExpanded={false}
count={operation.cookieParameters.length}
>
<Parameters
parameters={operation.cookieParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
</Accordion>
</>
)}
<Title headingLevel={"h4"}>Responses</Title>
<Accordion>
{operation.responses.map((t) => (
<AccordionSection
title={
<Split hasGutter={true}>
<StatusCodeLabel code={t.statusCode} />
{t.description && (
<Markdown searchTerm={searchTerm}>
{t.description}
</Markdown>
)}
</Split>
}
id={`response-${t.statusCode}`}
startExpanded={false}
>
TODO
</AccordionSection>
))}
</Accordion>
</Stack>
{isExpanded && (
<Stack hasGutter={true}>
{operation.description && (
<Markdown searchTerm={searchTerm}>
{operation.description}
</Markdown>
)}
{operation.pathParameters.length +
operation.headerParameters.length +
operation.queryParameters.length +
operation.headerParameters.length >
0 && (
<>
<Title headingLevel={"h4"}>Request</Title>
<Accordion>
{operation.pathParameters.length > 0 && (
<AccordionSection
title={"Path parameters"}
id={"path-params"}
startExpanded={false}
count={operation.pathParameters.length}
>
<Parameters
parameters={operation.pathParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
{operation.queryParameters.length > 0 && (
<AccordionSection
title={"Query parameters"}
id={"query-params"}
startExpanded={false}
count={operation.queryParameters.length}
>
<Parameters
parameters={operation.queryParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
{operation.headerParameters.length > 0 && (
<AccordionSection
title={"Header parameters"}
id={"header-params"}
startExpanded={false}
count={operation.headerParameters.length}
>
<Parameters
parameters={operation.headerParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
{operation.cookieParameters.length > 0 && (
<AccordionSection
title={"Cookie parameters"}
id={"cookie-params"}
startExpanded={false}
count={operation.cookieParameters.length}
>
<Parameters
parameters={operation.cookieParameters}
searchTerm={searchTerm}
/>
</AccordionSection>
)}
</Accordion>
</>
)}
<Title headingLevel={"h4"}>Responses</Title>
<Accordion>
{operation.responses.map((t) => (
<AccordionSection
title={
<Split hasGutter={true}>
<StatusCodeLabel code={t.statusCode} />
{t.description && (
<Markdown searchTerm={searchTerm}>
{t.description}
</Markdown>
)}
</Split>
}
id={`response-${t.statusCode}`}
startExpanded={false}
>
TODO
</AccordionSection>
))}
</Accordion>
</Stack>
)}
</DataListContent>
</DataListItem>
);
Expand Down

0 comments on commit f3a3911

Please sign in to comment.