zudoku 0.3.1-dev.2 → 0.3.1-dev.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/dist/lib/authentication/authentication.d.ts +1 -0
- package/dist/lib/authentication/components/CallbackHandler.d.ts +3 -0
- package/dist/lib/authentication/components/CallbackHandler.js +34 -0
- package/dist/lib/authentication/components/CallbackHandler.js.map +1 -0
- package/dist/lib/authentication/providers/auth0.js +20 -1
- package/dist/lib/authentication/providers/auth0.js.map +1 -1
- package/dist/lib/authentication/providers/openid.d.ts +3 -10
- package/dist/lib/authentication/providers/openid.js +46 -31
- package/dist/lib/authentication/providers/openid.js.map +1 -1
- package/dist/lib/components/Header.js +2 -4
- package/dist/lib/components/Header.js.map +1 -1
- package/dist/lib/components/Layout.js +5 -1
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/context/ZudokuProvider.js +1 -3
- package/dist/lib/components/context/ZudokuProvider.js.map +1 -1
- package/dist/lib/core/DevPortalContext.d.ts +1 -4
- package/dist/lib/core/DevPortalContext.js +2 -2
- package/dist/lib/core/DevPortalContext.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +2 -4
- package/dist/lib/core/plugins.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +3 -4
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +2 -3
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +2 -2
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.d.ts +9 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js +14 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js.map +1 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.d.ts +6 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.js +17 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.js.map +1 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.d.ts +7 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js +10 -0
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js.map +1 -0
- package/dist/lib/plugins/openapi/schema/SchemaComponents.d.ts +3 -3
- package/dist/lib/plugins/openapi/schema/SchemaComponents.js +15 -15
- package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/SchemaView.js +1 -1
- package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/utils.d.ts +6 -0
- package/dist/lib/plugins/openapi/schema/utils.js +5 -0
- package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
- package/lib/{AuthenticationPlugin-CH5NSVOu.js → AuthenticationPlugin-owbEUimP.js} +3 -3
- package/lib/{AuthenticationPlugin-CH5NSVOu.js.map → AuthenticationPlugin-owbEUimP.js.map} +1 -1
- package/lib/{CategoryHeading-z15xh7Jb.js → CategoryHeading-DnPprxtD.js} +2 -2
- package/lib/{CategoryHeading-z15xh7Jb.js.map → CategoryHeading-DnPprxtD.js.map} +1 -1
- package/lib/{Combination-DTfV-c98.js → Combination-DruV0zX_.js} +3 -3
- package/lib/{Combination-DTfV-c98.js.map → Combination-DruV0zX_.js.map} +1 -1
- package/lib/ErrorPage-PUg985n_.js +18 -0
- package/lib/ErrorPage-PUg985n_.js.map +1 -0
- package/lib/{Input-DB9VROFR.js → Input-CBfi9Yjc.js} +5 -4
- package/lib/{Input-DB9VROFR.js.map → Input-CBfi9Yjc.js.map} +1 -1
- package/lib/{Markdown-CEccPMI_.js → Markdown-Chb9VIBv.js} +2 -2
- package/lib/{Markdown-CEccPMI_.js.map → Markdown-Chb9VIBv.js.map} +1 -1
- package/lib/{MdxPage-CnqOoqvp.js → MdxPage-CIBHMwTd.js} +5 -5
- package/lib/{MdxPage-CnqOoqvp.js.map → MdxPage-CIBHMwTd.js.map} +1 -1
- package/lib/OperationList-CZiSz5JH.js +590 -0
- package/lib/OperationList-CZiSz5JH.js.map +1 -0
- package/lib/{Route-DfAFiR7v.js → Route-Cle-r-bq.js} +4 -4
- package/lib/{Route-DfAFiR7v.js.map → Route-Cle-r-bq.js.map} +1 -1
- package/lib/{Spinner-BT_AYFrA.js → SidebarBadge-Ba0PhibA.js} +66 -76
- package/lib/SidebarBadge-Ba0PhibA.js.map +1 -0
- package/lib/{SlotletProvider-ByLSCZQa.js → SlotletProvider-Dq80og6-.js} +4 -4
- package/lib/{SlotletProvider-ByLSCZQa.js.map → SlotletProvider-Dq80og6-.js.map} +1 -1
- package/lib/Spinner-CvXZ7QK4.js +15 -0
- package/lib/Spinner-CvXZ7QK4.js.map +1 -0
- package/lib/{ZudokuContext-BIZ8zHbZ.js → ZudokuContext-BQ45UjcB.js} +2 -2
- package/lib/{ZudokuContext-BIZ8zHbZ.js.map → ZudokuContext-BQ45UjcB.js.map} +1 -1
- package/lib/{index-D-9zqIOh.js → index-Br1MQPxy.js} +595 -587
- package/lib/index-Br1MQPxy.js.map +1 -0
- package/lib/{index-Dz4LyXZI.js → index-DCJ9wEIV.js} +3 -3
- package/lib/{index-Dz4LyXZI.js.map → index-DCJ9wEIV.js.map} +1 -1
- package/lib/{index-7kcHaXD6.js → index-Yjb2PyPF.js} +4 -4
- package/lib/{index-7kcHaXD6.js.map → index-Yjb2PyPF.js.map} +1 -1
- package/lib/{urql-DrBfkb92.js → urql-YhcsXYy8.js} +2 -2
- package/lib/urql-YhcsXYy8.js.map +1 -0
- package/lib/{utils-Bh4upQ0e.js → utils-pDHePxa0.js} +3 -3
- package/lib/{utils-Bh4upQ0e.js.map → utils-pDHePxa0.js.map} +1 -1
- package/lib/zudoku.auth-auth0.js +31 -17
- package/lib/zudoku.auth-auth0.js.map +1 -1
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +491 -421
- package/lib/zudoku.auth-openid.js.map +1 -1
- package/lib/zudoku.components.js +434 -443
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.openapi-worker.js +1 -1
- package/lib/zudoku.plugin-api-keys.js +6 -6
- package/lib/zudoku.plugin-custom-page.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +8 -7
- package/lib/zudoku.plugin-openapi.js.map +1 -1
- package/package.json +80 -100
- package/src/app/main.css +26 -1
- package/src/lib/authentication/authentication.ts +1 -0
- package/src/lib/authentication/components/CallbackHandler.tsx +59 -0
- package/src/lib/authentication/providers/auth0.tsx +28 -2
- package/src/lib/authentication/providers/openid.tsx +50 -37
- package/src/lib/components/Header.tsx +3 -10
- package/src/lib/components/Layout.tsx +6 -1
- package/src/lib/components/context/ZudokuProvider.tsx +1 -4
- package/src/lib/core/DevPortalContext.ts +2 -7
- package/src/lib/core/plugins.ts +1 -2
- package/src/lib/plugins/openapi/OperationList.tsx +3 -7
- package/src/lib/plugins/openapi/OperationListItem.tsx +3 -4
- package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -1
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +27 -5
- package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.tsx +47 -0
- package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.tsx +54 -0
- package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.tsx +30 -0
- package/src/lib/plugins/openapi/schema/SchemaComponents.tsx +41 -41
- package/src/lib/plugins/openapi/schema/SchemaView.tsx +4 -4
- package/src/lib/plugins/openapi/schema/utils.ts +8 -0
- package/dist/lib/plugins/openapi/util/prose.d.ts +0 -1
- package/dist/lib/plugins/openapi/util/prose.js +0 -4
- package/dist/lib/plugins/openapi/util/prose.js.map +0 -1
- package/lib/OperationList-Cxiw2Z-v.js +0 -457
- package/lib/OperationList-Cxiw2Z-v.js.map +0 -1
- package/lib/Spinner-BT_AYFrA.js.map +0 -1
- package/lib/index-D-9zqIOh.js.map +0 -1
- package/lib/urql-DrBfkb92.js.map +0 -1
- package/src/lib/plugins/openapi/util/prose.ts +0 -7
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { MoonStarIcon, SunIcon } from "lucide-react";
|
|
2
2
|
import { memo } from "react";
|
|
3
|
-
|
|
4
3
|
import { Link, useLocation } from "react-router-dom";
|
|
5
4
|
import { useAuth } from "../authentication/hook.js";
|
|
6
5
|
import { isProfileMenuPlugin, ProfileNavigationItem } from "../core/plugins.js";
|
|
@@ -45,6 +44,7 @@ const RecursiveMenu = ({ item }: { item: ProfileNavigationItem }) => {
|
|
|
45
44
|
};
|
|
46
45
|
|
|
47
46
|
export const Header = memo(function HeaderInner() {
|
|
47
|
+
const auth = useAuth();
|
|
48
48
|
const [isDark, toggleTheme] = useTheme();
|
|
49
49
|
const { isAuthenticated, profile, isAuthEnabled } = useAuth();
|
|
50
50
|
const { pathname } = useLocation();
|
|
@@ -97,15 +97,8 @@ export const Header = memo(function HeaderInner() {
|
|
|
97
97
|
<div className="items-center justify-self-end text-sm hidden lg:flex gap-2">
|
|
98
98
|
<Slotlet name="head-navigation-start" />
|
|
99
99
|
{isAuthEnabled && !isAuthenticated ? (
|
|
100
|
-
<Button variant="ghost"
|
|
101
|
-
|
|
102
|
-
to={{
|
|
103
|
-
pathname: "/signin",
|
|
104
|
-
search: `?redirect=${encodeURIComponent(pathname)}`,
|
|
105
|
-
}}
|
|
106
|
-
>
|
|
107
|
-
Login
|
|
108
|
-
</Link>
|
|
100
|
+
<Button variant="ghost" onClick={() => auth.login()}>
|
|
101
|
+
Login
|
|
109
102
|
</Button>
|
|
110
103
|
) : (
|
|
111
104
|
accountItems.length > 0 && (
|
|
@@ -14,13 +14,18 @@ import { Spinner } from "./Spinner.js";
|
|
|
14
14
|
export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
15
15
|
const location = useLocation();
|
|
16
16
|
const { setActiveAnchor } = useViewportAnchor();
|
|
17
|
-
const { meta } = useZudoku();
|
|
17
|
+
const { meta, authentication } = useZudoku();
|
|
18
18
|
|
|
19
19
|
useScrollToAnchor();
|
|
20
20
|
useScrollToTop();
|
|
21
21
|
|
|
22
22
|
const previousLocationPath = useRef(location.pathname);
|
|
23
23
|
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
// Initialize the authentication plugin
|
|
26
|
+
authentication?.pageLoad ? authentication.pageLoad() : null;
|
|
27
|
+
}, [authentication]);
|
|
28
|
+
|
|
24
29
|
useEffect(() => {
|
|
25
30
|
// always reset on location change
|
|
26
31
|
if (location.pathname !== previousLocationPath.current) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
2
2
|
import type { PropsWithChildren } from "react";
|
|
3
|
-
import { useNavigate } from "react-router-dom";
|
|
4
3
|
import { DevPortalContext } from "../../core/DevPortalContext.js";
|
|
5
4
|
import { ZudokuReactContext } from "./ZudokuContext.js";
|
|
6
5
|
|
|
@@ -8,11 +7,9 @@ export const ZudokuProvider = ({
|
|
|
8
7
|
children,
|
|
9
8
|
context,
|
|
10
9
|
}: PropsWithChildren<{ context: DevPortalContext }>) => {
|
|
11
|
-
const navigate = useNavigate();
|
|
12
|
-
|
|
13
10
|
useSuspenseQuery({
|
|
14
11
|
queryFn: async () => {
|
|
15
|
-
await context.initialize(
|
|
12
|
+
await context.initialize();
|
|
16
13
|
return true;
|
|
17
14
|
},
|
|
18
15
|
queryKey: ["zudoku-initialize"],
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
-
import { NavigateFunction } from "react-router-dom";
|
|
3
2
|
import type { SidebarConfig } from "../../config/validators/SidebarSchema.js";
|
|
4
3
|
import { type AuthenticationProvider } from "../authentication/authentication.js";
|
|
5
4
|
import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
|
|
@@ -84,15 +83,11 @@ export class DevPortalContext {
|
|
|
84
83
|
this.page = config.page;
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
initialize = async ({
|
|
88
|
-
navigate,
|
|
89
|
-
}: {
|
|
90
|
-
navigate: NavigateFunction;
|
|
91
|
-
}): Promise<void> => {
|
|
86
|
+
initialize = async (): Promise<void> => {
|
|
92
87
|
await Promise.all(
|
|
93
88
|
this.plugins
|
|
94
89
|
.filter(needsInitialization)
|
|
95
|
-
.map((plugin) => plugin.initialize?.(this
|
|
90
|
+
.map((plugin) => plugin.initialize?.(this)),
|
|
96
91
|
);
|
|
97
92
|
};
|
|
98
93
|
|
package/src/lib/core/plugins.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactElement } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { type RouteObject } from "react-router-dom";
|
|
3
3
|
import type { Sidebar } from "../../config/validators/SidebarSchema.js";
|
|
4
4
|
import { MdxComponentsType } from "../util/MdxComponents.js";
|
|
5
5
|
import { DevPortalContext, type ApiIdentity } from "./DevPortalContext.js";
|
|
@@ -40,7 +40,6 @@ export type ProfileNavigationItem = {
|
|
|
40
40
|
export interface CommonPlugin {
|
|
41
41
|
initialize?: (
|
|
42
42
|
context: DevPortalContext,
|
|
43
|
-
options: { navigate: NavigateFunction },
|
|
44
43
|
) => Promise<void | boolean> | void | boolean;
|
|
45
44
|
getHead?: () => ReactElement | undefined;
|
|
46
45
|
getMdxComponents?: () => MdxComponentsType;
|
|
@@ -4,14 +4,13 @@ import { DeveloperHint } from "../../components/DeveloperHint.js";
|
|
|
4
4
|
import { ErrorPage } from "../../components/ErrorPage.js";
|
|
5
5
|
import { Heading } from "../../components/Heading.js";
|
|
6
6
|
import { InlineCode } from "../../components/InlineCode.js";
|
|
7
|
-
import { Markdown } from "../../components/Markdown.js";
|
|
7
|
+
import { Markdown, ProseClasses } from "../../components/Markdown.js";
|
|
8
8
|
import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
9
9
|
import { cn } from "../../util/cn.js";
|
|
10
10
|
import { OperationListItem } from "./OperationListItem.js";
|
|
11
11
|
import StaggeredRender from "./StaggeredRender.js";
|
|
12
12
|
import { useOasConfig } from "./context.js";
|
|
13
13
|
import { graphql } from "./graphql/index.js";
|
|
14
|
-
import { SchemaProseClasses } from "./util/prose.js";
|
|
15
14
|
import { useQuery } from "./util/urql.js";
|
|
16
15
|
|
|
17
16
|
export const OperationsFragment = graphql(/* GraphQL */ `
|
|
@@ -124,10 +123,7 @@ export const OperationList = () => {
|
|
|
124
123
|
return (
|
|
125
124
|
<div className="pt-[--padding-content-top]">
|
|
126
125
|
<div
|
|
127
|
-
className={cn(
|
|
128
|
-
SchemaProseClasses,
|
|
129
|
-
"mb-16 max-w-full prose-img:max-w-prose",
|
|
130
|
-
)}
|
|
126
|
+
className={cn(ProseClasses, "mb-16 max-w-full prose-img:max-w-prose")}
|
|
131
127
|
>
|
|
132
128
|
<CategoryHeading>Overview</CategoryHeading>
|
|
133
129
|
<Heading level={1} id="description" registerSidebarAnchor>
|
|
@@ -142,7 +138,7 @@ export const OperationList = () => {
|
|
|
142
138
|
{tag.name && <CategoryHeading>{tag.name}</CategoryHeading>}
|
|
143
139
|
{tag.description && (
|
|
144
140
|
<Markdown
|
|
145
|
-
className={`${
|
|
141
|
+
className={`${ProseClasses} max-w-full prose-img:max-w-prose w-full mt-2 mb-12`}
|
|
146
142
|
content={tag.description}
|
|
147
143
|
/>
|
|
148
144
|
)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { Heading } from "../../components/Heading.js";
|
|
3
|
-
import { Markdown } from "../../components/Markdown.js";
|
|
3
|
+
import { Markdown, ProseClasses } from "../../components/Markdown.js";
|
|
4
4
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../ui/Tabs.js";
|
|
5
5
|
import { groupBy } from "../../util/groupBy.js";
|
|
6
6
|
import { renderIf } from "../../util/renderIf.js";
|
|
@@ -9,7 +9,6 @@ import { ParameterList } from "./ParameterList.js";
|
|
|
9
9
|
import { Sidecar } from "./Sidecar.js";
|
|
10
10
|
import { FragmentType, useFragment } from "./graphql/index.js";
|
|
11
11
|
import { SchemaView } from "./schema/SchemaView.js";
|
|
12
|
-
import { SchemaProseClasses } from "./util/prose.js";
|
|
13
12
|
|
|
14
13
|
export const PARAM_GROUPS = ["path", "query", "header", "cookie"] as const;
|
|
15
14
|
export type ParameterGroup = (typeof PARAM_GROUPS)[number];
|
|
@@ -39,7 +38,7 @@ export const OperationListItem = ({
|
|
|
39
38
|
</Heading>
|
|
40
39
|
{operation.description && (
|
|
41
40
|
<Markdown
|
|
42
|
-
className={
|
|
41
|
+
className={`${ProseClasses} max-w-full prose-img:max-w-prose`}
|
|
43
42
|
content={operation.description}
|
|
44
43
|
/>
|
|
45
44
|
)}
|
|
@@ -89,7 +88,7 @@ export const OperationListItem = ({
|
|
|
89
88
|
))}
|
|
90
89
|
</TabsList>
|
|
91
90
|
)}
|
|
92
|
-
<ul className="list-none m-0 px-0
|
|
91
|
+
<ul className="list-none m-0 px-0">
|
|
93
92
|
{operation.responses.map((response) => (
|
|
94
93
|
<TabsContent
|
|
95
94
|
value={response.statusCode}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
2
|
-
import { CirclePlayIcon } from "lucide-react";
|
|
3
2
|
import { type PropsWithChildren, useState } from "react";
|
|
4
3
|
import {
|
|
5
4
|
Dialog,
|
|
@@ -11,16 +10,39 @@ import { Playground, type PlaygroundContentProps } from "./Playground.js";
|
|
|
11
10
|
|
|
12
11
|
export type PlaygroundDialogProps = PropsWithChildren<PlaygroundContentProps>;
|
|
13
12
|
|
|
13
|
+
const HeroPlayIcon = ({
|
|
14
|
+
className,
|
|
15
|
+
size = 16,
|
|
16
|
+
}: {
|
|
17
|
+
className?: string;
|
|
18
|
+
size?: number;
|
|
19
|
+
}) => (
|
|
20
|
+
<svg
|
|
21
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
+
viewBox="0 0 24 24"
|
|
23
|
+
fill="currentColor"
|
|
24
|
+
className={className}
|
|
25
|
+
width={size}
|
|
26
|
+
height={size}
|
|
27
|
+
>
|
|
28
|
+
<path
|
|
29
|
+
fillRule="evenodd"
|
|
30
|
+
d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm14.024-.983a1.125 1.125 0 0 1 0 1.966l-5.603 3.113A1.125 1.125 0 0 1 9 15.113V8.887c0-.857.921-1.4 1.671-.983l5.603 3.113Z"
|
|
31
|
+
clipRule="evenodd"
|
|
32
|
+
/>
|
|
33
|
+
</svg>
|
|
34
|
+
);
|
|
35
|
+
|
|
14
36
|
const PlaygroundDialog = (props: PlaygroundDialogProps) => {
|
|
15
37
|
const [open, setOpen] = useState(false);
|
|
16
38
|
return (
|
|
17
39
|
<Dialog onOpenChange={(open) => setOpen(open)}>
|
|
18
40
|
<DialogTrigger asChild>
|
|
19
41
|
{props.children ?? (
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
size={
|
|
23
|
-
|
|
42
|
+
<button className="flex gap-1 items-center px-2 py-1 rounded-md bg-primary/80 hover:bg-primary transition text-primary-foreground text-xs">
|
|
43
|
+
Test
|
|
44
|
+
<HeroPlayIcon className="" size={14} />
|
|
45
|
+
</button>
|
|
24
46
|
)}
|
|
25
47
|
</DialogTrigger>
|
|
26
48
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
|
+
import { SquareMinusIcon, SquarePlusIcon } from "lucide-react";
|
|
3
|
+
import type { SchemaObject } from "../../../../oas/parser/index.js";
|
|
4
|
+
import { Card } from "../../../../ui/Card.js";
|
|
5
|
+
import type { LogicalGroupType } from "../utils.js";
|
|
6
|
+
import { LogicalGroupItem } from "./LogicalGroupItem.js";
|
|
7
|
+
|
|
8
|
+
const typeLabel = {
|
|
9
|
+
AND: "All of",
|
|
10
|
+
OR: "Any of",
|
|
11
|
+
ONE: "One of",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const LogicalGroup = ({
|
|
15
|
+
schemas,
|
|
16
|
+
type,
|
|
17
|
+
isOpen,
|
|
18
|
+
level,
|
|
19
|
+
toggleOpen,
|
|
20
|
+
}: {
|
|
21
|
+
schemas: SchemaObject[];
|
|
22
|
+
type: LogicalGroupType;
|
|
23
|
+
isOpen: boolean;
|
|
24
|
+
toggleOpen: () => void;
|
|
25
|
+
level: number;
|
|
26
|
+
}) => (
|
|
27
|
+
<Collapsible.Root open={isOpen} onOpenChange={toggleOpen} asChild>
|
|
28
|
+
<Card className="px-6">
|
|
29
|
+
<Collapsible.Trigger className="flex gap-2 items-center py-2 w-full text-sm text-muted-foreground -translate-x-1.5">
|
|
30
|
+
{isOpen ? <SquareMinusIcon size={14} /> : <SquarePlusIcon size={14} />}
|
|
31
|
+
<span>{typeLabel[type]}</span>
|
|
32
|
+
</Collapsible.Trigger>
|
|
33
|
+
|
|
34
|
+
<Collapsible.Content className="pb-4">
|
|
35
|
+
{schemas.map((subSchema, index) => (
|
|
36
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
37
|
+
<LogicalGroupItem
|
|
38
|
+
key={index}
|
|
39
|
+
type={type}
|
|
40
|
+
schema={subSchema}
|
|
41
|
+
level={level}
|
|
42
|
+
/>
|
|
43
|
+
))}
|
|
44
|
+
</Collapsible.Content>
|
|
45
|
+
</Card>
|
|
46
|
+
</Collapsible.Root>
|
|
47
|
+
);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChevronDownIcon,
|
|
3
|
+
CircleDotIcon,
|
|
4
|
+
CircleFadingPlusIcon,
|
|
5
|
+
CircleIcon,
|
|
6
|
+
} from "lucide-react";
|
|
7
|
+
import { cn } from "../../../../util/cn.js";
|
|
8
|
+
|
|
9
|
+
import type { LogicalGroupType } from "../utils.js";
|
|
10
|
+
|
|
11
|
+
const iconMap = {
|
|
12
|
+
AND: <CircleFadingPlusIcon size={16} className="fill-card" />,
|
|
13
|
+
OR: <CircleDotIcon size={16} className="fill-card" />,
|
|
14
|
+
ONE: <CircleIcon size={14} className="fill-card" />,
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
const colorClass = {
|
|
18
|
+
AND: "text-green-500 dark:text-green-300/60",
|
|
19
|
+
OR: "text-blue-400 dark:text-blue-500",
|
|
20
|
+
ONE: "text-purple-500 dark:text-purple-300/60",
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export const LogicalGroupConnector = ({
|
|
24
|
+
type,
|
|
25
|
+
isOpen,
|
|
26
|
+
className,
|
|
27
|
+
}: {
|
|
28
|
+
type: LogicalGroupType;
|
|
29
|
+
isOpen: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
}) => {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
className={cn(
|
|
35
|
+
colorClass[type],
|
|
36
|
+
"relative text-sm flex py-2",
|
|
37
|
+
"before:border-l before:absolute before:-top-2 before:-bottom-2 before:border-border before:border-dashed before:content-['']",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
<div className="-translate-x-[7px] flex gap-1 items-center">
|
|
42
|
+
{iconMap[type]}
|
|
43
|
+
<div
|
|
44
|
+
className={cn(
|
|
45
|
+
"translate-y-px mx-px opacity-0 group-hover:opacity-100 transition",
|
|
46
|
+
!isOpen && "-rotate-90",
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
49
|
+
<ChevronDownIcon size={16} />
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import type { SchemaObject } from "../../../../oas/parser/index.js";
|
|
4
|
+
import { SchemaView } from "../SchemaView.js";
|
|
5
|
+
import type { LogicalGroupType } from "../utils.js";
|
|
6
|
+
import { LogicalGroupConnector } from "./LogicalGroupConnector.js";
|
|
7
|
+
|
|
8
|
+
export const LogicalGroupItem = (props: {
|
|
9
|
+
type: LogicalGroupType;
|
|
10
|
+
schema: SchemaObject;
|
|
11
|
+
level: number;
|
|
12
|
+
}) => {
|
|
13
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Collapsible.Root
|
|
17
|
+
open={isOpen}
|
|
18
|
+
onOpenChange={() => setIsOpen((prev) => !prev)}
|
|
19
|
+
className="group"
|
|
20
|
+
>
|
|
21
|
+
<Collapsible.Trigger>
|
|
22
|
+
<LogicalGroupConnector type={props.type} isOpen={isOpen} />
|
|
23
|
+
</Collapsible.Trigger>
|
|
24
|
+
{!isOpen && <div className="wavy-line bg-border translate-y-1" />}
|
|
25
|
+
<Collapsible.Content>
|
|
26
|
+
<SchemaView schema={props.schema} level={props.level + 1} />
|
|
27
|
+
</Collapsible.Content>
|
|
28
|
+
</Collapsible.Root>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
2
|
import { ListPlusIcon } from "lucide-react";
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
4
|
import { Markdown, ProseClasses } from "../../../components/Markdown.js";
|
|
5
5
|
import type { SchemaObject } from "../../../oas/parser/index.js";
|
|
6
6
|
import { Button } from "../../../ui/Button.js";
|
|
7
7
|
import { cn } from "../../../util/cn.js";
|
|
8
|
+
import { objectEntries } from "../../../util/objectEntries.js";
|
|
9
|
+
import { LogicalGroup } from "./LogicalGroup/LogicalGroup.js";
|
|
8
10
|
import { SchemaView } from "./SchemaView.js";
|
|
9
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
hasLogicalGroupings,
|
|
13
|
+
isComplexType,
|
|
14
|
+
LogicalSchemaTypeMap,
|
|
15
|
+
} from "./utils.js";
|
|
10
16
|
|
|
11
17
|
export const SchemaLogicalGroup = ({
|
|
12
18
|
schema,
|
|
@@ -15,41 +21,34 @@ export const SchemaLogicalGroup = ({
|
|
|
15
21
|
schema: SchemaObject;
|
|
16
22
|
level: number;
|
|
17
23
|
}) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
groupName: string,
|
|
21
|
-
separator: string,
|
|
22
|
-
) => {
|
|
23
|
-
return group.map((subSchema, index) => (
|
|
24
|
-
<div key={index} className="my-2">
|
|
25
|
-
<strong>{groupName}</strong>
|
|
26
|
-
<div className="mt-2">
|
|
27
|
-
<SchemaView schema={subSchema} level={level + 1} />
|
|
28
|
-
{index < group.length - 1 && (
|
|
29
|
-
<div className="text-center my-2">{separator}</div>
|
|
30
|
-
)}
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
));
|
|
34
|
-
};
|
|
24
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
25
|
+
const toggleOpen = useCallback(() => setIsOpen((prev) => !prev), []);
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (schema.anyOf) return renderLogicalGroup(schema.anyOf, "Any of", "OR");
|
|
27
|
+
for (const [key, type] of objectEntries(LogicalSchemaTypeMap)) {
|
|
28
|
+
if (!schema[key]) continue;
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
return (
|
|
31
|
+
<LogicalGroup
|
|
32
|
+
schemas={schema[key]}
|
|
33
|
+
type={type}
|
|
34
|
+
isOpen={isOpen}
|
|
35
|
+
toggleOpen={toggleOpen}
|
|
36
|
+
level={level}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
41
40
|
};
|
|
42
41
|
|
|
43
42
|
export const SchemaPropertyItem = ({
|
|
44
43
|
name,
|
|
45
|
-
|
|
44
|
+
schema,
|
|
46
45
|
group,
|
|
47
46
|
level,
|
|
48
47
|
defaultOpen = false,
|
|
49
48
|
showCollapseButton = true,
|
|
50
49
|
}: {
|
|
51
50
|
name: string;
|
|
52
|
-
|
|
51
|
+
schema: SchemaObject;
|
|
53
52
|
group: "required" | "optional" | "deprecated";
|
|
54
53
|
level: number;
|
|
55
54
|
defaultOpen?: boolean;
|
|
@@ -63,12 +62,12 @@ export const SchemaPropertyItem = ({
|
|
|
63
62
|
<div className="flex gap-2 items-center">
|
|
64
63
|
<code>{name}</code>
|
|
65
64
|
<span className="text-muted-foreground">
|
|
66
|
-
{
|
|
67
|
-
<span>{
|
|
68
|
-
) : Array.isArray(
|
|
69
|
-
<span>{
|
|
65
|
+
{schema.type === "array" && schema.items?.type ? (
|
|
66
|
+
<span>{schema.items.type}[]</span>
|
|
67
|
+
) : Array.isArray(schema.type) ? (
|
|
68
|
+
<span>{schema.type.join(" | ")}</span>
|
|
70
69
|
) : (
|
|
71
|
-
<span>{
|
|
70
|
+
<span>{schema.type}</span>
|
|
72
71
|
)}
|
|
73
72
|
</span>
|
|
74
73
|
{group === "optional" && (
|
|
@@ -78,14 +77,14 @@ export const SchemaPropertyItem = ({
|
|
|
78
77
|
)}
|
|
79
78
|
</div>
|
|
80
79
|
|
|
81
|
-
{
|
|
80
|
+
{schema.description && (
|
|
82
81
|
<Markdown
|
|
83
82
|
className={cn(ProseClasses, "text-sm leading-normal line-clamp-4")}
|
|
84
|
-
content={
|
|
83
|
+
content={schema.description}
|
|
85
84
|
/>
|
|
86
85
|
)}
|
|
87
86
|
|
|
88
|
-
{(hasLogicalGroupings(
|
|
87
|
+
{(hasLogicalGroupings(schema) || isComplexType(schema)) && (
|
|
89
88
|
<Collapsible.Root
|
|
90
89
|
defaultOpen={defaultOpen}
|
|
91
90
|
open={isOpen}
|
|
@@ -107,14 +106,15 @@ export const SchemaPropertyItem = ({
|
|
|
107
106
|
)}
|
|
108
107
|
<Collapsible.Content>
|
|
109
108
|
<div className="mt-2">
|
|
110
|
-
{hasLogicalGroupings(
|
|
111
|
-
<SchemaLogicalGroup schema={
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
{hasLogicalGroupings(schema) ? (
|
|
110
|
+
<SchemaLogicalGroup schema={schema} level={level + 1} />
|
|
111
|
+
) : schema.type === "object" ? (
|
|
112
|
+
<SchemaView schema={schema} level={level + 1} />
|
|
113
|
+
) : (
|
|
114
|
+
schema.type === "array" &&
|
|
115
|
+
typeof schema.items === "object" && (
|
|
116
|
+
<SchemaView schema={schema.items} level={level + 1} />
|
|
117
|
+
)
|
|
118
118
|
)}
|
|
119
119
|
</div>
|
|
120
120
|
</Collapsible.Content>
|
|
@@ -111,11 +111,11 @@ export const SchemaView = ({
|
|
|
111
111
|
(group) =>
|
|
112
112
|
groupedProperties[group] && (
|
|
113
113
|
<ul key={group} className="divide-y">
|
|
114
|
-
{groupedProperties[group].map(([
|
|
114
|
+
{groupedProperties[group].map(([name, schema]) => (
|
|
115
115
|
<SchemaPropertyItem
|
|
116
|
-
key={
|
|
117
|
-
name={
|
|
118
|
-
|
|
116
|
+
key={name}
|
|
117
|
+
name={name}
|
|
118
|
+
schema={schema}
|
|
119
119
|
group={group}
|
|
120
120
|
level={level}
|
|
121
121
|
defaultOpen={isTopLevelSingleItem || defaultOpen}
|
|
@@ -8,3 +8,11 @@ export const isComplexType = (value: SchemaObject) =>
|
|
|
8
8
|
|
|
9
9
|
export const hasLogicalGroupings = (value: SchemaObject) =>
|
|
10
10
|
Boolean(value.oneOf ?? value.allOf ?? value.anyOf);
|
|
11
|
+
|
|
12
|
+
export const LogicalSchemaTypeMap = {
|
|
13
|
+
allOf: "AND",
|
|
14
|
+
anyOf: "OR",
|
|
15
|
+
oneOf: "ONE",
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
export type LogicalGroupType = "AND" | "OR" | "ONE";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const SchemaProseClasses: string;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prose.js","sourceRoot":"","sources":["../../../../../src/lib/plugins/openapi/util/prose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAClC,YAAY,EACZ,kCAAkC,CACnC,CAAC"}
|