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.
Files changed (47) hide show
  1. package/dist/app/App.js +2 -0
  2. package/dist/app/App.js.map +1 -1
  3. package/dist/config/config.d.ts +2 -0
  4. package/dist/lib/components/Layout.js +1 -2
  5. package/dist/lib/components/Layout.js.map +1 -1
  6. package/dist/lib/components/navigation/SideNavigationItem.d.ts +1 -1
  7. package/dist/lib/components/navigation/SideNavigationItem.js +6 -6
  8. package/dist/lib/components/navigation/SideNavigationItem.js.map +1 -1
  9. package/dist/lib/plugins/api-key/SettingsApiKeys.js +6 -1
  10. package/dist/lib/plugins/api-key/SettingsApiKeys.js.map +1 -1
  11. package/dist/lib/plugins/api-key/index.d.ts +1 -0
  12. package/dist/lib/plugins/api-key/index.js +13 -17
  13. package/dist/lib/plugins/api-key/index.js.map +1 -1
  14. package/dist/lib/plugins/index.js +0 -1
  15. package/dist/lib/plugins/index.js.map +1 -1
  16. package/dist/lib/plugins/openapi/MakeRequest.js +21 -16
  17. package/dist/lib/plugins/openapi/MakeRequest.js.map +1 -1
  18. package/dist/lib/plugins/openapi/playground/InlineInput.d.ts +1 -0
  19. package/dist/lib/plugins/openapi/playground/Playground.d.ts +2 -1
  20. package/dist/lib/plugins/openapi/playground/Playground.js +4 -3
  21. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  22. package/dist/lib/plugins/openapi/playground/QueryParams.js +1 -1
  23. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  24. package/dist/lib/plugins/redirect/index.d.ts +1 -2
  25. package/dist/lib/util/createVariantComponent.d.ts +4 -3
  26. package/dist/lib/util/createVariantComponent.js +9 -5
  27. package/dist/lib/util/createVariantComponent.js.map +1 -1
  28. package/dist/vite/plugin-redirect.d.ts +4 -0
  29. package/dist/vite/plugin-redirect.js +32 -0
  30. package/dist/vite/plugin-redirect.js.map +1 -0
  31. package/dist/vite/plugin.js +2 -0
  32. package/dist/vite/plugin.js.map +1 -1
  33. package/lib/{util-CJko6Ria.js → util-BJVAslZ-.js} +358 -351
  34. package/lib/zudoku.components.js +103 -106
  35. package/lib/zudoku.plugins.js +2691 -2681
  36. package/package.json +1 -1
  37. package/src/app/App.tsx +2 -0
  38. package/src/lib/components/Layout.tsx +8 -9
  39. package/src/lib/components/navigation/SideNavigationItem.tsx +10 -7
  40. package/src/lib/plugins/api-key/SettingsApiKeys.tsx +9 -3
  41. package/src/lib/plugins/api-key/index.tsx +17 -19
  42. package/src/lib/plugins/index.ts +0 -1
  43. package/src/lib/plugins/openapi/MakeRequest.tsx +32 -25
  44. package/src/lib/plugins/openapi/playground/Playground.tsx +8 -8
  45. package/src/lib/plugins/openapi/playground/QueryParams.tsx +8 -3
  46. package/src/lib/plugins/redirect/index.tsx +1 -1
  47. package/src/lib/util/createVariantComponent.tsx +11 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.1.1-dev.32",
3
+ "version": "0.1.1-dev.34",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
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
- </Suspense>
50
- <main
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
- {children ?? <Outlet />}
57
- </main>
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 linkItem = cva(
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: "opacity-60",
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
- linkItem({
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("group text-start", linkItem({ isActive: false }))}
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={linkItem({
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 }) => linkItem({ 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="destructive"
82
+ variant="ghost"
83
83
  size="icon"
84
- onClick={() => deleteKeyMutation.mutate(key.id)}
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 consumers = await fetch(endpoint + `/v1/developer/api-keys`, {
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 consumers.json();
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
- return [];
103
- // throw new Error("Not implemented");
104
- // const keys = await getConsumers(context);
105
- // return (keys ?? { consumers: [] }).consumers
106
- // .flatMap((consumer) => consumer.apiKeys)
107
- // .map((key) => ({
108
- // authorizeRequest: (request: Request) => {
109
- // request.headers.set("Authorization", `Bearer ${key.key}`);
110
- // },
111
- // id: key.id,
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 [
@@ -1,4 +1,3 @@
1
- // Plugins
2
1
  export { apiKeyPlugin } from "./api-key/index.js";
3
2
  export { markdownPlugin } from "./markdown/index.js";
4
3
  export { openApiPlugin } from "./openapi/index.js";
@@ -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
- <div>
26
- <Playground
27
- host={server.data?.schema.url ?? ""}
28
- method={operation.method}
29
- url={operation.path}
30
- headers={operation.parameters
31
- ?.filter((p) => p.in === "header")
32
- .map((param) => ({
33
- name: param.name,
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
- <TabsTrigger value="parameters">Parameters</TabsTrigger>
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
- <div className="flex items-center px-2 bg-transparent h-6 font-mono text-xs m-2">
73
- {field.value}
74
- </div>
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,7 @@
1
1
  import { Navigate } from "react-router-dom";
2
2
  import type { DevPortalPlugin } from "../../core/plugins.js";
3
3
 
4
- type Redirect = {
4
+ export type Redirect = {
5
5
  from: string;
6
6
  to: string;
7
7
  replace?: boolean;
@@ -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 { JSX } from "react/jsx-runtime";
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
- React.createElement(tag, {
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