zudoku 0.1.1-dev.32 → 0.1.1-dev.34
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/dist/app/App.js +2 -0
- package/dist/app/App.js.map +1 -1
- package/dist/config/config.d.ts +2 -0
- package/dist/lib/components/Layout.js +1 -2
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/navigation/SideNavigationItem.d.ts +1 -1
- package/dist/lib/components/navigation/SideNavigationItem.js +6 -6
- package/dist/lib/components/navigation/SideNavigationItem.js.map +1 -1
- package/dist/lib/plugins/api-key/SettingsApiKeys.js +6 -1
- package/dist/lib/plugins/api-key/SettingsApiKeys.js.map +1 -1
- package/dist/lib/plugins/api-key/index.d.ts +1 -0
- package/dist/lib/plugins/api-key/index.js +13 -17
- package/dist/lib/plugins/api-key/index.js.map +1 -1
- package/dist/lib/plugins/index.js +0 -1
- package/dist/lib/plugins/index.js.map +1 -1
- package/dist/lib/plugins/openapi/MakeRequest.js +21 -16
- package/dist/lib/plugins/openapi/MakeRequest.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/InlineInput.d.ts +1 -0
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +2 -1
- package/dist/lib/plugins/openapi/playground/Playground.js +4 -3
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/QueryParams.js +1 -1
- package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
- package/dist/lib/plugins/redirect/index.d.ts +1 -2
- package/dist/lib/util/createVariantComponent.d.ts +4 -3
- package/dist/lib/util/createVariantComponent.js +9 -5
- package/dist/lib/util/createVariantComponent.js.map +1 -1
- package/dist/vite/plugin-redirect.d.ts +4 -0
- package/dist/vite/plugin-redirect.js +32 -0
- package/dist/vite/plugin-redirect.js.map +1 -0
- package/dist/vite/plugin.js +2 -0
- package/dist/vite/plugin.js.map +1 -1
- package/lib/{util-CJko6Ria.js → util-BJVAslZ-.js} +358 -351
- package/lib/zudoku.components.js +103 -106
- package/lib/zudoku.plugins.js +2691 -2681
- package/package.json +1 -1
- package/src/app/App.tsx +2 -0
- package/src/lib/components/Layout.tsx +8 -9
- package/src/lib/components/navigation/SideNavigationItem.tsx +10 -7
- package/src/lib/plugins/api-key/SettingsApiKeys.tsx +9 -3
- package/src/lib/plugins/api-key/index.tsx +17 -19
- package/src/lib/plugins/index.ts +0 -1
- package/src/lib/plugins/openapi/MakeRequest.tsx +32 -25
- package/src/lib/plugins/openapi/playground/Playground.tsx +8 -8
- package/src/lib/plugins/openapi/playground/QueryParams.tsx +8 -3
- package/src/lib/plugins/redirect/index.tsx +1 -1
- package/src/lib/util/createVariantComponent.tsx +11 -8
package/package.json
CHANGED
package/src/app/App.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
|
|
|
8
8
|
import { configuredAuthProvider } from "virtual:zudoku-auth";
|
|
9
9
|
import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
|
|
10
10
|
import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
|
|
11
|
+
import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
|
|
11
12
|
|
|
12
13
|
// Base React Component
|
|
13
14
|
import { DevPortal } from "zudoku/components";
|
|
@@ -32,6 +33,7 @@ export default function App() {
|
|
|
32
33
|
...configuredDocsPlugins,
|
|
33
34
|
...configuredApiPlugins,
|
|
34
35
|
configuredApiKeysPlugin,
|
|
36
|
+
configuredRedirectPlugin,
|
|
35
37
|
]}
|
|
36
38
|
/>
|
|
37
39
|
);
|
|
@@ -41,20 +41,19 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
|
41
41
|
{meta?.favicon && <link rel="icon" href={meta.favicon} />}
|
|
42
42
|
</Helmet>
|
|
43
43
|
<Header />
|
|
44
|
+
|
|
44
45
|
<div className="max-w-screen-2xl mx-auto pt-[--header-height] px-10 lg:px-12">
|
|
45
|
-
<Suspense
|
|
46
|
-
fallback={<SideNavigationWrapper>Loading...</SideNavigationWrapper>}
|
|
47
|
-
>
|
|
46
|
+
<Suspense fallback={<div className="top-48">Warte kurz...</div>}>
|
|
48
47
|
<SideNavigation />
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
className="dark:border-white/10 translate-x-0
|
|
48
|
+
<main
|
|
49
|
+
className="dark:border-white/10 translate-x-0
|
|
52
50
|
lg:overflow-visible
|
|
53
51
|
lg:peer-data-[navigation=true]:w-[calc(100%-var(--side-nav-width))]
|
|
54
52
|
lg:peer-data-[navigation=true]:translate-x-[--side-nav-width] peer-data-[navigation=true]:pl-12"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
>
|
|
54
|
+
{children ?? <Outlet />}
|
|
55
|
+
</main>
|
|
56
|
+
</Suspense>
|
|
58
57
|
</div>
|
|
59
58
|
</>
|
|
60
59
|
);
|
|
@@ -15,7 +15,7 @@ import { DynamicIcon, isValidIcon } from "../DynamicIcon.js";
|
|
|
15
15
|
import { useNavigationCollapsibleState } from "./useNavigationCollapsibleState.js";
|
|
16
16
|
import { checkHasActiveItem, isLinkItem, isPathItem } from "./util.js";
|
|
17
17
|
|
|
18
|
-
export const
|
|
18
|
+
export const navigationListItem = cva(
|
|
19
19
|
"flex px-[--padding-nav-item] py-1.5 rounded-lg hover:bg-accent transition-colors duration-300",
|
|
20
20
|
{
|
|
21
21
|
variants: {
|
|
@@ -24,7 +24,7 @@ export const linkItem = cva(
|
|
|
24
24
|
false: "text-foreground/80",
|
|
25
25
|
},
|
|
26
26
|
isMuted: {
|
|
27
|
-
true: "
|
|
27
|
+
true: "text-foreground/30",
|
|
28
28
|
false: "",
|
|
29
29
|
},
|
|
30
30
|
},
|
|
@@ -58,9 +58,8 @@ export const SideNavigationItem = ({
|
|
|
58
58
|
if (isLinkItem(item)) {
|
|
59
59
|
const classes = cn(
|
|
60
60
|
"flex items-center gap-2",
|
|
61
|
-
|
|
61
|
+
navigationListItem({
|
|
62
62
|
isActive: item.href === location.pathname,
|
|
63
|
-
isMuted: true,
|
|
64
63
|
}),
|
|
65
64
|
);
|
|
66
65
|
return item.href.startsWith("http") ? (
|
|
@@ -108,7 +107,10 @@ export const SideNavigationItem = ({
|
|
|
108
107
|
className="flex flex-col"
|
|
109
108
|
>
|
|
110
109
|
<Collapsible.Trigger
|
|
111
|
-
className={cn(
|
|
110
|
+
className={cn(
|
|
111
|
+
"group text-start",
|
|
112
|
+
navigationListItem({ isActive: false }),
|
|
113
|
+
)}
|
|
112
114
|
>
|
|
113
115
|
{linkContent}
|
|
114
116
|
</Collapsible.Trigger>
|
|
@@ -131,15 +133,16 @@ export const SideNavigationItem = ({
|
|
|
131
133
|
<AnchorLink
|
|
132
134
|
to={item.path}
|
|
133
135
|
{...{ [DATA_ANCHOR_ATTR]: item.path }}
|
|
134
|
-
className={
|
|
136
|
+
className={navigationListItem({
|
|
135
137
|
isActive: item.path.slice(1) === activeAnchor,
|
|
138
|
+
isMuted: item.muted,
|
|
136
139
|
})}
|
|
137
140
|
>
|
|
138
141
|
{linkContent}
|
|
139
142
|
</AnchorLink>
|
|
140
143
|
) : (
|
|
141
144
|
<NavLink
|
|
142
|
-
className={({ isActive }) =>
|
|
145
|
+
className={({ isActive }) => navigationListItem({ isActive })}
|
|
143
146
|
to={currentPath}
|
|
144
147
|
>
|
|
145
148
|
{linkContent}
|
|
@@ -62,7 +62,7 @@ export const SettingsApiKeys = ({
|
|
|
62
62
|
<div>Expires on {key.expiresOn}</div>
|
|
63
63
|
) : (
|
|
64
64
|
key.createdOn && (
|
|
65
|
-
<div className="text-gray-500">
|
|
65
|
+
<div className="text-gray-500 whitespace-pre">
|
|
66
66
|
Created on {new Date(key.createdOn).toLocaleDateString()}
|
|
67
67
|
</div>
|
|
68
68
|
)
|
|
@@ -79,9 +79,15 @@ export const SettingsApiKeys = ({
|
|
|
79
79
|
)}
|
|
80
80
|
{service.deleteKey && (
|
|
81
81
|
<Button
|
|
82
|
-
variant="
|
|
82
|
+
variant="ghost"
|
|
83
83
|
size="icon"
|
|
84
|
-
onClick={() =>
|
|
84
|
+
onClick={() => {
|
|
85
|
+
if (!confirm("Do you want to delete this key?")) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
deleteKeyMutation.mutate(key.id);
|
|
90
|
+
}}
|
|
85
91
|
disabled={deleteKeyMutation.isPending}
|
|
86
92
|
>
|
|
87
93
|
<TrashIcon size={16} />
|
|
@@ -18,6 +18,7 @@ export type ApiKeyService = {
|
|
|
18
18
|
apiKey: { jd: string; description: string },
|
|
19
19
|
context: DevPortalContext,
|
|
20
20
|
) => Promise<void>;
|
|
21
|
+
getUsage?: (apiKeys: string[], context: DevPortalContext) => Promise<void>;
|
|
21
22
|
createKey?: (
|
|
22
23
|
apiKey: { description: string; expiresAt?: string },
|
|
23
24
|
context: DevPortalContext,
|
|
@@ -76,13 +77,13 @@ const createDefaultHandler = (endpoint: string): ApiKeyService => {
|
|
|
76
77
|
return [];
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
const
|
|
80
|
+
const keys = await fetch(endpoint + `/v1/developer/api-keys`, {
|
|
80
81
|
headers: {
|
|
81
82
|
Authorization: `Bearer ${accessToken}`,
|
|
82
83
|
},
|
|
83
84
|
});
|
|
84
85
|
|
|
85
|
-
return await
|
|
86
|
+
return await keys.json();
|
|
86
87
|
},
|
|
87
88
|
};
|
|
88
89
|
};
|
|
@@ -90,27 +91,24 @@ const createDefaultHandler = (endpoint: string): ApiKeyService => {
|
|
|
90
91
|
export const apiKeyPlugin = (
|
|
91
92
|
options: ApiKeyPluginOptions,
|
|
92
93
|
): DevPortalPlugin & ApiIdentityPlugin => {
|
|
94
|
+
const endpoint =
|
|
95
|
+
"endpoint" in options ? options.endpoint : DEFAULT_API_KEY_ENDPOINT;
|
|
96
|
+
|
|
93
97
|
const service =
|
|
94
|
-
"getKeys" in options
|
|
95
|
-
? options
|
|
96
|
-
: createDefaultHandler(
|
|
97
|
-
"endpoint" in options ? options.endpoint : DEFAULT_API_KEY_ENDPOINT,
|
|
98
|
-
);
|
|
98
|
+
"getKeys" in options ? options : createDefaultHandler(endpoint);
|
|
99
99
|
|
|
100
100
|
return {
|
|
101
101
|
getIdentities: async (context) => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// name: key.id,
|
|
113
|
-
// }));
|
|
102
|
+
const keys = await service.getKeys(context);
|
|
103
|
+
|
|
104
|
+
return keys.map((key) => ({
|
|
105
|
+
authorizeRequest: (request) => {
|
|
106
|
+
request.headers.set("Authorization", `Bearer ${key.key}`);
|
|
107
|
+
return request;
|
|
108
|
+
},
|
|
109
|
+
id: key.id,
|
|
110
|
+
name: key.id,
|
|
111
|
+
}));
|
|
114
112
|
},
|
|
115
113
|
getRoutes: () => {
|
|
116
114
|
return [
|
package/src/lib/plugins/index.ts
CHANGED
|
@@ -21,31 +21,38 @@ export const MakeRequest = ({
|
|
|
21
21
|
const variables = useOasConfig();
|
|
22
22
|
const [server] = useQuery({ query: GetServerQuery, variables });
|
|
23
23
|
|
|
24
|
+
const headers = operation.parameters
|
|
25
|
+
?.filter((p) => p.in === "header")
|
|
26
|
+
?.map((p) => ({
|
|
27
|
+
name: p.name,
|
|
28
|
+
value: "",
|
|
29
|
+
}));
|
|
30
|
+
const queryParams = operation.parameters
|
|
31
|
+
?.filter((p) => p.in === "query")
|
|
32
|
+
?.map((p) => ({
|
|
33
|
+
name: p.name,
|
|
34
|
+
value: "",
|
|
35
|
+
}));
|
|
36
|
+
const pathParams = operation.parameters
|
|
37
|
+
?.filter((p) => p.in === "path")
|
|
38
|
+
?.map((p) => ({
|
|
39
|
+
name: p.name,
|
|
40
|
+
value: "",
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
const hasParams =
|
|
44
|
+
operation.parameters?.some((p) => p.in === "query" || p.in === "path") ??
|
|
45
|
+
false;
|
|
46
|
+
|
|
24
47
|
return (
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
value: "",
|
|
35
|
-
}))}
|
|
36
|
-
queryParams={operation.parameters
|
|
37
|
-
?.filter((p) => p.in === "query")
|
|
38
|
-
.map((param) => ({
|
|
39
|
-
name: param.name,
|
|
40
|
-
value: "",
|
|
41
|
-
}))}
|
|
42
|
-
pathParams={operation.parameters
|
|
43
|
-
?.filter((p) => p.in === "path")
|
|
44
|
-
.map((param) => ({
|
|
45
|
-
name: param.name,
|
|
46
|
-
value: "",
|
|
47
|
-
}))}
|
|
48
|
-
/>
|
|
49
|
-
</div>
|
|
48
|
+
<Playground
|
|
49
|
+
host={server.data?.schema.url ?? ""}
|
|
50
|
+
method={operation.method}
|
|
51
|
+
url={operation.path}
|
|
52
|
+
headers={headers}
|
|
53
|
+
queryParams={queryParams}
|
|
54
|
+
pathParams={pathParams}
|
|
55
|
+
hasParams={hasParams}
|
|
56
|
+
/>
|
|
50
57
|
);
|
|
51
58
|
};
|
|
@@ -20,6 +20,7 @@ import { PathParams } from "./PathParams.js";
|
|
|
20
20
|
import { CirclePlayIcon, LoaderCircle, MonitorCheckIcon } from "lucide-react";
|
|
21
21
|
import { createUrl } from "./createUrl.js";
|
|
22
22
|
import { UrlDisplay } from "./UrlDisplay.js";
|
|
23
|
+
import { useApiIdentities } from "../../../components/context/DevPortalProvider.js";
|
|
23
24
|
|
|
24
25
|
function mimeTypeToLanguage(mimeType: string) {
|
|
25
26
|
const mimeTypeMapping = {
|
|
@@ -79,6 +80,7 @@ const Playground = ({
|
|
|
79
80
|
headers = [{ name: "", value: "" }],
|
|
80
81
|
queryParams = [],
|
|
81
82
|
pathParams = [],
|
|
83
|
+
hasParams,
|
|
82
84
|
}: {
|
|
83
85
|
host: string;
|
|
84
86
|
url: string;
|
|
@@ -86,6 +88,7 @@ const Playground = ({
|
|
|
86
88
|
headers?: Header[];
|
|
87
89
|
queryParams?: QueryParam[];
|
|
88
90
|
pathParams?: PathParam[];
|
|
91
|
+
hasParams: boolean;
|
|
89
92
|
}) => {
|
|
90
93
|
const { register, control, handleSubmit, watch, ...form } =
|
|
91
94
|
useForm<PlaygroundForm>({
|
|
@@ -97,6 +100,7 @@ const Playground = ({
|
|
|
97
100
|
},
|
|
98
101
|
});
|
|
99
102
|
const formState = watch();
|
|
103
|
+
const identities = useApiIdentities();
|
|
100
104
|
|
|
101
105
|
const queryMutation = useMutation({
|
|
102
106
|
mutationFn: async (data: PlaygroundForm) => {
|
|
@@ -153,12 +157,6 @@ const Playground = ({
|
|
|
153
157
|
|
|
154
158
|
const headerEntries = Array.from(queryMutation.data?.headers.entries() ?? []);
|
|
155
159
|
|
|
156
|
-
console.log(
|
|
157
|
-
"QP lol",
|
|
158
|
-
formState.queryParams,
|
|
159
|
-
formState.queryParams.filter((p) => p.active),
|
|
160
|
-
);
|
|
161
|
-
|
|
162
160
|
const urlQueryParams = formState.queryParams
|
|
163
161
|
.filter((p) => p.active)
|
|
164
162
|
.map((p) => (
|
|
@@ -201,9 +199,11 @@ const Playground = ({
|
|
|
201
199
|
Send
|
|
202
200
|
</Button>
|
|
203
201
|
</div>
|
|
204
|
-
<Tabs defaultValue="parameters">
|
|
202
|
+
<Tabs defaultValue={hasParams ? "parameters" : "headers"}>
|
|
205
203
|
<TabsList>
|
|
206
|
-
|
|
204
|
+
{hasParams && (
|
|
205
|
+
<TabsTrigger value="parameters">Parameters</TabsTrigger>
|
|
206
|
+
)}
|
|
207
207
|
<TabsTrigger value="headers">
|
|
208
208
|
Headers{" "}
|
|
209
209
|
{formState.headers.length > 0 &&
|
|
@@ -69,9 +69,14 @@ export const QueryParams = ({
|
|
|
69
69
|
control={control}
|
|
70
70
|
render={({ field }) => {
|
|
71
71
|
return (
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
<InlineInput asChild>
|
|
73
|
+
<label
|
|
74
|
+
className="flex items-center"
|
|
75
|
+
htmlFor={`queryParams.${i}.active`}
|
|
76
|
+
>
|
|
77
|
+
{field.value}
|
|
78
|
+
</label>
|
|
79
|
+
</InlineInput>
|
|
75
80
|
);
|
|
76
81
|
}}
|
|
77
82
|
name={`queryParams.${i}.name`}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { cva } from "class-variance-authority";
|
|
2
|
-
import { ClassValue } from "clsx";
|
|
3
1
|
import * as React from "react";
|
|
4
|
-
import {
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
4
|
+
import type { ClassValue } from "clsx";
|
|
5
|
+
import type { JSX } from "react/jsx-runtime";
|
|
5
6
|
import { cn } from "./cn.js";
|
|
6
7
|
|
|
7
8
|
const createVariantComponent = <
|
|
@@ -14,15 +15,17 @@ const createVariantComponent = <
|
|
|
14
15
|
) => {
|
|
15
16
|
const MyVariant = React.forwardRef<
|
|
16
17
|
HTMLElement,
|
|
17
|
-
JSX.IntrinsicElements[E] & { className?: ClassValue }
|
|
18
|
-
>(({ className, ...props }, ref) =>
|
|
19
|
-
|
|
18
|
+
JSX.IntrinsicElements[E] & { className?: ClassValue; asChild?: boolean }
|
|
19
|
+
>(({ className, asChild, ...props }, ref) => {
|
|
20
|
+
const Comp = asChild ? Slot : tag;
|
|
21
|
+
|
|
22
|
+
return React.createElement(Comp, {
|
|
20
23
|
...props,
|
|
21
24
|
ref,
|
|
22
25
|
className:
|
|
23
26
|
typeof cvx === "function" ? cvx({ className }) : cn(cvx, className),
|
|
24
|
-
})
|
|
25
|
-
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
26
29
|
|
|
27
30
|
MyVariant.displayName = `VariantComponent(${tag})`;
|
|
28
31
|
|