work-agent 0.1.0
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/README.md +234 -0
- package/app/(admin)/approvals/page.tsx +16 -0
- package/app/(admin)/audit/page.tsx +18 -0
- package/app/(admin)/layout.tsx +47 -0
- package/app/(admin)/scheduled-tasks/page.tsx +17 -0
- package/app/(admin)/settings/page.tsx +46 -0
- package/app/(admin)/skills/[name]/page.tsx +378 -0
- package/app/(admin)/skills/page.tsx +406 -0
- package/app/(admin)/statistics/page.tsx +416 -0
- package/app/(admin)/tickets/[id]/page.tsx +348 -0
- package/app/(admin)/tickets/new/page.tsx +309 -0
- package/app/(admin)/tickets/page.tsx +27 -0
- package/app/api/audit/route.ts +30 -0
- package/app/api/auth/feishu/callback/route.ts +72 -0
- package/app/api/auth/feishu/login/route.ts +17 -0
- package/app/api/auth/feishu/sso/route.ts +78 -0
- package/app/api/auth/login/route.ts +85 -0
- package/app/api/auth/oauth/route.ts +168 -0
- package/app/api/config/providers/route.ts +105 -0
- package/app/api/config/route.ts +115 -0
- package/app/api/config/status/route.ts +56 -0
- package/app/api/config/test/route.ts +212 -0
- package/app/api/documents/[id]/route.ts +88 -0
- package/app/api/documents/route.ts +53 -0
- package/app/api/health/route.ts +32 -0
- package/app/api/knowledge/[id]/route.ts +152 -0
- package/app/api/knowledge/from-session/route.ts +27 -0
- package/app/api/knowledge/route.ts +100 -0
- package/app/api/market/knowledge/[id]/route.ts +92 -0
- package/app/api/market/knowledge/route.ts +130 -0
- package/app/api/marketplace/skills/[id]/approve/route.ts +68 -0
- package/app/api/marketplace/skills/[id]/certify/route.ts +54 -0
- package/app/api/marketplace/skills/[id]/install/route.ts +180 -0
- package/app/api/marketplace/skills/[id]/promote-to-system/route.ts +219 -0
- package/app/api/marketplace/skills/[id]/rate/route.ts +90 -0
- package/app/api/marketplace/skills/[id]/ratings/route.ts +55 -0
- package/app/api/marketplace/skills/[id]/reject/route.ts +68 -0
- package/app/api/marketplace/skills/[id]/route.ts +177 -0
- package/app/api/marketplace/skills/route.ts +235 -0
- package/app/api/memory/route.ts +40 -0
- package/app/api/my/files/[id]/route.ts +52 -0
- package/app/api/my/files/route.ts +230 -0
- package/app/api/my/knowledge/route.ts +36 -0
- package/app/api/pi-chat/route.ts +443 -0
- package/app/api/recommend/route.ts +38 -0
- package/app/api/scheduled-tasks/[id]/execute/route.ts +132 -0
- package/app/api/scheduled-tasks/[id]/route.ts +165 -0
- package/app/api/scheduled-tasks/[id]/toggle/route.ts +53 -0
- package/app/api/scheduled-tasks/route.ts +101 -0
- package/app/api/sessions/[id]/messages/route.ts +212 -0
- package/app/api/sessions/route.ts +101 -0
- package/app/api/share/file/[id]/route.ts +37 -0
- package/app/api/skills/[name]/execute/route.ts +121 -0
- package/app/api/skills/[name]/route.ts +167 -0
- package/app/api/skills/create/route.ts +65 -0
- package/app/api/skills/generate/route.ts +405 -0
- package/app/api/skills/installed/route.ts +151 -0
- package/app/api/skills/route.ts +174 -0
- package/app/api/skills/translate/route.ts +40 -0
- package/app/api/skills/user/[name]/route.ts +159 -0
- package/app/api/skills/user/route.ts +90 -0
- package/app/api/statistics/route.ts +94 -0
- package/app/api/task-executions/[id]/route.ts +34 -0
- package/app/api/task-executions/route.ts +29 -0
- package/app/api/tickets/[id]/approve/route.ts +129 -0
- package/app/api/tickets/[id]/execute/route.ts +201 -0
- package/app/api/tickets/[id]/route.ts +127 -0
- package/app/api/tickets/route.ts +103 -0
- package/app/api/user/skills/route.ts +175 -0
- package/app/api/users/route.ts +80 -0
- package/app/chat/page.tsx +5 -0
- package/app/globals.css +84 -0
- package/app/h5/layout.tsx +5 -0
- package/app/h5/mobile-approvals-page.tsx +167 -0
- package/app/h5/mobile-chat-page.tsx +951 -0
- package/app/h5/mobile-profile-page.tsx +147 -0
- package/app/h5/mobile-tickets-page.tsx +121 -0
- package/app/h5/page.tsx +23 -0
- package/app/h5/ticket-action-buttons.tsx +80 -0
- package/app/layout.tsx +26 -0
- package/app/login/page.tsx +318 -0
- package/app/market/knowledge/[id]/page.tsx +77 -0
- package/app/market/knowledge/page.tsx +358 -0
- package/app/market/layout.tsx +29 -0
- package/app/market/page.tsx +18 -0
- package/app/market/skills/page.tsx +397 -0
- package/app/my/files/page.tsx +511 -0
- package/app/my/knowledge/[id]/page.tsx +271 -0
- package/app/my/knowledge/new/page.tsx +234 -0
- package/app/my/knowledge/page.tsx +248 -0
- package/app/my/layout.tsx +32 -0
- package/app/my/memory/page.tsx +164 -0
- package/app/my/page.tsx +18 -0
- package/app/my/scheduled-tasks/[id]/edit/page.tsx +290 -0
- package/app/my/scheduled-tasks/[id]/executions/page.tsx +275 -0
- package/app/my/scheduled-tasks/[id]/page.tsx +284 -0
- package/app/my/scheduled-tasks/new/page.tsx +230 -0
- package/app/my/scheduled-tasks/page.tsx +27 -0
- package/app/my/skills/[name]/page.tsx +320 -0
- package/app/my/skills/new/page.tsx +394 -0
- package/app/my/skills/page.tsx +303 -0
- package/app/page.tsx +2288 -0
- package/app/share/[sessionId]/page.tsx +226 -0
- package/app/share/file/[id]/page.tsx +140 -0
- package/bin/README.md +63 -0
- package/bin/generate-api-system +300 -0
- package/bin/postinstall.js +95 -0
- package/bin/work-agent.js +173 -0
- package/components/ai-elements/agent.tsx +142 -0
- package/components/ai-elements/artifact.tsx +149 -0
- package/components/ai-elements/attachments.tsx +427 -0
- package/components/ai-elements/audio-player.tsx +232 -0
- package/components/ai-elements/canvas.tsx +26 -0
- package/components/ai-elements/chain-of-thought.tsx +223 -0
- package/components/ai-elements/checkpoint.tsx +72 -0
- package/components/ai-elements/code-block.tsx +555 -0
- package/components/ai-elements/commit.tsx +449 -0
- package/components/ai-elements/confirmation.tsx +173 -0
- package/components/ai-elements/connection.tsx +28 -0
- package/components/ai-elements/context.tsx +410 -0
- package/components/ai-elements/controls.tsx +19 -0
- package/components/ai-elements/conversation.tsx +167 -0
- package/components/ai-elements/edge.tsx +144 -0
- package/components/ai-elements/environment-variables.tsx +325 -0
- package/components/ai-elements/file-tree.tsx +298 -0
- package/components/ai-elements/image.tsx +25 -0
- package/components/ai-elements/inline-citation.tsx +294 -0
- package/components/ai-elements/jsx-preview.tsx +250 -0
- package/components/ai-elements/message.tsx +367 -0
- package/components/ai-elements/mic-selector.tsx +372 -0
- package/components/ai-elements/model-selector.tsx +214 -0
- package/components/ai-elements/node.tsx +72 -0
- package/components/ai-elements/open-in-chat.tsx +367 -0
- package/components/ai-elements/package-info.tsx +235 -0
- package/components/ai-elements/panel.tsx +16 -0
- package/components/ai-elements/persona.tsx +280 -0
- package/components/ai-elements/plan.tsx +144 -0
- package/components/ai-elements/prompt-input.tsx +1341 -0
- package/components/ai-elements/queue.tsx +275 -0
- package/components/ai-elements/reasoning.tsx +355 -0
- package/components/ai-elements/sandbox.tsx +133 -0
- package/components/ai-elements/schema-display.tsx +473 -0
- package/components/ai-elements/shimmer.tsx +78 -0
- package/components/ai-elements/snippet.tsx +141 -0
- package/components/ai-elements/sources.tsx +78 -0
- package/components/ai-elements/speech-input.tsx +324 -0
- package/components/ai-elements/stack-trace.tsx +531 -0
- package/components/ai-elements/suggestion.tsx +58 -0
- package/components/ai-elements/task.tsx +88 -0
- package/components/ai-elements/terminal.tsx +277 -0
- package/components/ai-elements/test-results.tsx +497 -0
- package/components/ai-elements/tool.tsx +174 -0
- package/components/ai-elements/toolbar.tsx +17 -0
- package/components/ai-elements/transcription.tsx +126 -0
- package/components/ai-elements/voice-selector.tsx +525 -0
- package/components/ai-elements/web-preview.tsx +282 -0
- package/components/audit-log-list.tsx +114 -0
- package/components/chat/EmptyPreviewState.tsx +12 -0
- package/components/chat/KnowledgePickerDialog.tsx +464 -0
- package/components/chat/KnowledgePreview.tsx +70 -0
- package/components/chat/KnowledgePreviewPanel.tsx +86 -0
- package/components/chat/MentionInput.tsx +309 -0
- package/components/chat/OrganizeDialog.tsx +258 -0
- package/components/chat/RecommendationBanner.tsx +94 -0
- package/components/chat/SaveToKnowledgeDialog.tsx +193 -0
- package/components/chat/SkillSelector.tsx +305 -0
- package/components/chat/SkillSwitcher.tsx +163 -0
- package/components/client-layout.tsx +15 -0
- package/components/knowledge/KnowledgeMetadataPanel.tsx +293 -0
- package/components/layout-wrapper.tsx +18 -0
- package/components/mobile-layout.tsx +62 -0
- package/components/scheduled-task-list.tsx +356 -0
- package/components/setup-guide.tsx +484 -0
- package/components/sub-nav.tsx +54 -0
- package/components/ticket-detail-content.tsx +383 -0
- package/components/ticket-list.tsx +366 -0
- package/components/top-nav.tsx +132 -0
- package/components/ui/accordion.tsx +58 -0
- package/components/ui/alert.tsx +59 -0
- package/components/ui/avatar.tsx +50 -0
- package/components/ui/badge.tsx +36 -0
- package/components/ui/button-group.tsx +83 -0
- package/components/ui/button.tsx +57 -0
- package/components/ui/card.tsx +91 -0
- package/components/ui/carousel.tsx +262 -0
- package/components/ui/collapsible.tsx +11 -0
- package/components/ui/command.tsx +153 -0
- package/components/ui/dialog.tsx +122 -0
- package/components/ui/dropdown-menu.tsx +200 -0
- package/components/ui/hover-card.tsx +29 -0
- package/components/ui/input-group.tsx +170 -0
- package/components/ui/input.tsx +22 -0
- package/components/ui/label.tsx +26 -0
- package/components/ui/popover.tsx +31 -0
- package/components/ui/progress.tsx +28 -0
- package/components/ui/scroll-area.tsx +48 -0
- package/components/ui/select.tsx +174 -0
- package/components/ui/separator.tsx +31 -0
- package/components/ui/spinner.tsx +16 -0
- package/components/ui/switch.tsx +29 -0
- package/components/ui/table.tsx +120 -0
- package/components/ui/tabs.tsx +55 -0
- package/components/ui/textarea.tsx +22 -0
- package/components/ui/tooltip.tsx +30 -0
- package/components/welcome-guide.tsx +182 -0
- package/components.json +24 -0
- package/lib/command-parser.ts +331 -0
- package/lib/dangerous-commands.ts +672 -0
- package/lib/db.ts +2250 -0
- package/lib/feishu-auth.ts +135 -0
- package/lib/file-storage.ts +306 -0
- package/lib/file-tool.ts +583 -0
- package/lib/knowledge-tool.ts +152 -0
- package/lib/knowledge-types.ts +66 -0
- package/lib/market-client.ts +313 -0
- package/lib/market-db.ts +736 -0
- package/lib/market-types.ts +51 -0
- package/lib/memory-tool.ts +211 -0
- package/lib/memory.ts +197 -0
- package/lib/pi-config.ts +436 -0
- package/lib/pi-session.ts +799 -0
- package/lib/pinyin.ts +13 -0
- package/lib/recommendation.ts +227 -0
- package/lib/risk-estimator.ts +350 -0
- package/lib/scheduled-task-tool.ts +184 -0
- package/lib/scheduler-init.ts +43 -0
- package/lib/scheduler.ts +416 -0
- package/lib/secure-bash-tool.ts +413 -0
- package/lib/skill-engine.ts +396 -0
- package/lib/skill-generator.ts +269 -0
- package/lib/skill-loader.ts +234 -0
- package/lib/skill-tool.ts +188 -0
- package/lib/skill-types.ts +82 -0
- package/lib/skills-init.ts +58 -0
- package/lib/ticket-tool.ts +246 -0
- package/lib/user-skill-types.ts +30 -0
- package/lib/user-skills.ts +362 -0
- package/lib/utils.ts +6 -0
- package/lib/workflow.ts +154 -0
- package/lib/zip-tool.ts +191 -0
- package/next.config.js +8 -0
- package/package.json +106 -0
- package/public/.gitkeep +1 -0
- package/public/icon.svg +1 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ToolUIPart } from "ai";
|
|
4
|
+
import type { ComponentProps } from "react";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Collapsible,
|
|
8
|
+
CollapsibleContent,
|
|
9
|
+
CollapsibleTrigger,
|
|
10
|
+
} from "@/components/ui/collapsible";
|
|
11
|
+
import {
|
|
12
|
+
Tabs,
|
|
13
|
+
TabsContent,
|
|
14
|
+
TabsList,
|
|
15
|
+
TabsTrigger,
|
|
16
|
+
} from "@/components/ui/tabs";
|
|
17
|
+
import { cn } from "@/lib/utils";
|
|
18
|
+
import { ChevronDownIcon, Code } from "lucide-react";
|
|
19
|
+
|
|
20
|
+
import { getStatusBadge } from "./tool";
|
|
21
|
+
|
|
22
|
+
export type SandboxRootProps = ComponentProps<typeof Collapsible>;
|
|
23
|
+
|
|
24
|
+
export const Sandbox = ({ className, ...props }: SandboxRootProps) => (
|
|
25
|
+
<Collapsible
|
|
26
|
+
className={cn(
|
|
27
|
+
"not-prose group mb-4 w-full overflow-hidden rounded-md border",
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
30
|
+
defaultOpen
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export interface SandboxHeaderProps {
|
|
36
|
+
title?: string;
|
|
37
|
+
state: ToolUIPart["state"];
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const SandboxHeader = ({
|
|
42
|
+
className,
|
|
43
|
+
title,
|
|
44
|
+
state,
|
|
45
|
+
...props
|
|
46
|
+
}: SandboxHeaderProps) => (
|
|
47
|
+
<CollapsibleTrigger
|
|
48
|
+
className={cn(
|
|
49
|
+
"flex w-full items-center justify-between gap-4 p-3",
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
>
|
|
54
|
+
<div className="flex items-center gap-2">
|
|
55
|
+
<Code className="size-4 text-muted-foreground" />
|
|
56
|
+
<span className="font-medium text-sm">{title}</span>
|
|
57
|
+
{getStatusBadge(state)}
|
|
58
|
+
</div>
|
|
59
|
+
<ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
|
|
60
|
+
</CollapsibleTrigger>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export type SandboxContentProps = ComponentProps<typeof CollapsibleContent>;
|
|
64
|
+
|
|
65
|
+
export const SandboxContent = ({
|
|
66
|
+
className,
|
|
67
|
+
...props
|
|
68
|
+
}: SandboxContentProps) => (
|
|
69
|
+
<CollapsibleContent
|
|
70
|
+
className={cn(
|
|
71
|
+
"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
72
|
+
className
|
|
73
|
+
)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export type SandboxTabsProps = ComponentProps<typeof Tabs>;
|
|
79
|
+
|
|
80
|
+
export const SandboxTabs = ({ className, ...props }: SandboxTabsProps) => (
|
|
81
|
+
<Tabs className={cn("w-full gap-0", className)} {...props} />
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
export type SandboxTabsBarProps = ComponentProps<"div">;
|
|
85
|
+
|
|
86
|
+
export const SandboxTabsBar = ({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: SandboxTabsBarProps) => (
|
|
90
|
+
<div
|
|
91
|
+
className={cn(
|
|
92
|
+
"flex w-full items-center border-border border-t border-b",
|
|
93
|
+
className
|
|
94
|
+
)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export type SandboxTabsListProps = ComponentProps<typeof TabsList>;
|
|
100
|
+
|
|
101
|
+
export const SandboxTabsList = ({
|
|
102
|
+
className,
|
|
103
|
+
...props
|
|
104
|
+
}: SandboxTabsListProps) => (
|
|
105
|
+
<TabsList
|
|
106
|
+
className={cn("h-auto rounded-none border-0 bg-transparent p-0", className)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
export type SandboxTabsTriggerProps = ComponentProps<typeof TabsTrigger>;
|
|
112
|
+
|
|
113
|
+
export const SandboxTabsTrigger = ({
|
|
114
|
+
className,
|
|
115
|
+
...props
|
|
116
|
+
}: SandboxTabsTriggerProps) => (
|
|
117
|
+
<TabsTrigger
|
|
118
|
+
className={cn(
|
|
119
|
+
"rounded-none border-0 border-transparent border-b-2 px-4 py-2 font-medium text-muted-foreground text-sm transition-colors data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none",
|
|
120
|
+
className
|
|
121
|
+
)}
|
|
122
|
+
{...props}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
export type SandboxTabContentProps = ComponentProps<typeof TabsContent>;
|
|
127
|
+
|
|
128
|
+
export const SandboxTabContent = ({
|
|
129
|
+
className,
|
|
130
|
+
...props
|
|
131
|
+
}: SandboxTabContentProps) => (
|
|
132
|
+
<TabsContent className={cn("mt-0 text-sm", className)} {...props} />
|
|
133
|
+
);
|
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ComponentProps, HTMLAttributes } from "react";
|
|
4
|
+
|
|
5
|
+
import { Badge } from "@/components/ui/badge";
|
|
6
|
+
import {
|
|
7
|
+
Collapsible,
|
|
8
|
+
CollapsibleContent,
|
|
9
|
+
CollapsibleTrigger,
|
|
10
|
+
} from "@/components/ui/collapsible";
|
|
11
|
+
import { cn } from "@/lib/utils";
|
|
12
|
+
import { ChevronRightIcon } from "lucide-react";
|
|
13
|
+
import { createContext, useContext, useMemo } from "react";
|
|
14
|
+
|
|
15
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
16
|
+
|
|
17
|
+
interface SchemaParameter {
|
|
18
|
+
name: string;
|
|
19
|
+
type: string;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
description?: string;
|
|
22
|
+
location?: "path" | "query" | "header";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface SchemaProperty {
|
|
26
|
+
name: string;
|
|
27
|
+
type: string;
|
|
28
|
+
required?: boolean;
|
|
29
|
+
description?: string;
|
|
30
|
+
properties?: SchemaProperty[];
|
|
31
|
+
items?: SchemaProperty;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface SchemaDisplayContextType {
|
|
35
|
+
method: HttpMethod;
|
|
36
|
+
path: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
parameters?: SchemaParameter[];
|
|
39
|
+
requestBody?: SchemaProperty[];
|
|
40
|
+
responseBody?: SchemaProperty[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const SchemaDisplayContext = createContext<SchemaDisplayContextType>({
|
|
44
|
+
method: "GET",
|
|
45
|
+
path: "",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export type SchemaDisplayProps = HTMLAttributes<HTMLDivElement> & {
|
|
49
|
+
method: HttpMethod;
|
|
50
|
+
path: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
parameters?: SchemaParameter[];
|
|
53
|
+
requestBody?: SchemaProperty[];
|
|
54
|
+
responseBody?: SchemaProperty[];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const SchemaDisplay = ({
|
|
58
|
+
method,
|
|
59
|
+
path,
|
|
60
|
+
description,
|
|
61
|
+
parameters,
|
|
62
|
+
requestBody,
|
|
63
|
+
responseBody,
|
|
64
|
+
className,
|
|
65
|
+
children,
|
|
66
|
+
...props
|
|
67
|
+
}: SchemaDisplayProps) => {
|
|
68
|
+
const contextValue = useMemo(
|
|
69
|
+
() => ({
|
|
70
|
+
description,
|
|
71
|
+
method,
|
|
72
|
+
parameters,
|
|
73
|
+
path,
|
|
74
|
+
requestBody,
|
|
75
|
+
responseBody,
|
|
76
|
+
}),
|
|
77
|
+
[description, method, parameters, path, requestBody, responseBody]
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<SchemaDisplayContext.Provider value={contextValue}>
|
|
82
|
+
<div
|
|
83
|
+
className={cn(
|
|
84
|
+
"overflow-hidden rounded-lg border bg-background",
|
|
85
|
+
className
|
|
86
|
+
)}
|
|
87
|
+
{...props}
|
|
88
|
+
>
|
|
89
|
+
{children ?? (
|
|
90
|
+
<>
|
|
91
|
+
<SchemaDisplayHeader>
|
|
92
|
+
<div className="flex items-center gap-3">
|
|
93
|
+
<SchemaDisplayMethod />
|
|
94
|
+
<SchemaDisplayPath />
|
|
95
|
+
</div>
|
|
96
|
+
</SchemaDisplayHeader>
|
|
97
|
+
{description && <SchemaDisplayDescription />}
|
|
98
|
+
<SchemaDisplayContent>
|
|
99
|
+
{parameters && parameters.length > 0 && (
|
|
100
|
+
<SchemaDisplayParameters />
|
|
101
|
+
)}
|
|
102
|
+
{requestBody && requestBody.length > 0 && (
|
|
103
|
+
<SchemaDisplayRequest />
|
|
104
|
+
)}
|
|
105
|
+
{responseBody && responseBody.length > 0 && (
|
|
106
|
+
<SchemaDisplayResponse />
|
|
107
|
+
)}
|
|
108
|
+
</SchemaDisplayContent>
|
|
109
|
+
</>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
</SchemaDisplayContext.Provider>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export type SchemaDisplayHeaderProps = HTMLAttributes<HTMLDivElement>;
|
|
117
|
+
|
|
118
|
+
export const SchemaDisplayHeader = ({
|
|
119
|
+
className,
|
|
120
|
+
children,
|
|
121
|
+
...props
|
|
122
|
+
}: SchemaDisplayHeaderProps) => (
|
|
123
|
+
<div
|
|
124
|
+
className={cn("flex items-center gap-3 border-b px-4 py-3", className)}
|
|
125
|
+
{...props}
|
|
126
|
+
>
|
|
127
|
+
{children}
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const methodStyles: Record<HttpMethod, string> = {
|
|
132
|
+
DELETE: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
|
|
133
|
+
GET: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
|
|
134
|
+
PATCH:
|
|
135
|
+
"bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400",
|
|
136
|
+
POST: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
|
137
|
+
PUT: "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400",
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export type SchemaDisplayMethodProps = ComponentProps<typeof Badge>;
|
|
141
|
+
|
|
142
|
+
export const SchemaDisplayMethod = ({
|
|
143
|
+
className,
|
|
144
|
+
children,
|
|
145
|
+
...props
|
|
146
|
+
}: SchemaDisplayMethodProps) => {
|
|
147
|
+
const { method } = useContext(SchemaDisplayContext);
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<Badge
|
|
151
|
+
className={cn("font-mono text-xs", methodStyles[method], className)}
|
|
152
|
+
variant="secondary"
|
|
153
|
+
{...props}
|
|
154
|
+
>
|
|
155
|
+
{children ?? method}
|
|
156
|
+
</Badge>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export type SchemaDisplayPathProps = HTMLAttributes<HTMLSpanElement>;
|
|
161
|
+
|
|
162
|
+
export const SchemaDisplayPath = ({
|
|
163
|
+
className,
|
|
164
|
+
children,
|
|
165
|
+
...props
|
|
166
|
+
}: SchemaDisplayPathProps) => {
|
|
167
|
+
const { path } = useContext(SchemaDisplayContext);
|
|
168
|
+
|
|
169
|
+
// Highlight path parameters
|
|
170
|
+
const highlightedPath = path.replaceAll(
|
|
171
|
+
/\{([^}]+)\}/g,
|
|
172
|
+
'<span class="text-blue-600 dark:text-blue-400">{$1}</span>'
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<span
|
|
177
|
+
className={cn("font-mono text-sm", className)}
|
|
178
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: "needed for parameter highlighting"
|
|
179
|
+
// oxlint-disable-next-line eslint-plugin-react(no-danger)
|
|
180
|
+
dangerouslySetInnerHTML={{ __html: (children ?? highlightedPath) as string }}
|
|
181
|
+
{...props}
|
|
182
|
+
/>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export type SchemaDisplayDescriptionProps =
|
|
187
|
+
HTMLAttributes<HTMLParagraphElement>;
|
|
188
|
+
|
|
189
|
+
export const SchemaDisplayDescription = ({
|
|
190
|
+
className,
|
|
191
|
+
children,
|
|
192
|
+
...props
|
|
193
|
+
}: SchemaDisplayDescriptionProps) => {
|
|
194
|
+
const { description } = useContext(SchemaDisplayContext);
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<p
|
|
198
|
+
className={cn(
|
|
199
|
+
"border-b px-4 py-3 text-muted-foreground text-sm",
|
|
200
|
+
className
|
|
201
|
+
)}
|
|
202
|
+
{...props}
|
|
203
|
+
>
|
|
204
|
+
{children ?? description}
|
|
205
|
+
</p>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export type SchemaDisplayContentProps = HTMLAttributes<HTMLDivElement>;
|
|
210
|
+
|
|
211
|
+
export const SchemaDisplayContent = ({
|
|
212
|
+
className,
|
|
213
|
+
children,
|
|
214
|
+
...props
|
|
215
|
+
}: SchemaDisplayContentProps) => (
|
|
216
|
+
<div className={cn("divide-y", className)} {...props}>
|
|
217
|
+
{children}
|
|
218
|
+
</div>
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
export type SchemaDisplayParametersProps = ComponentProps<typeof Collapsible>;
|
|
222
|
+
|
|
223
|
+
export const SchemaDisplayParameters = ({
|
|
224
|
+
className,
|
|
225
|
+
children,
|
|
226
|
+
...props
|
|
227
|
+
}: SchemaDisplayParametersProps) => {
|
|
228
|
+
const { parameters } = useContext(SchemaDisplayContext);
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<Collapsible className={cn(className)} defaultOpen {...props}>
|
|
232
|
+
<CollapsibleTrigger className="group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50">
|
|
233
|
+
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
|
|
234
|
+
<span className="font-medium text-sm">Parameters</span>
|
|
235
|
+
<Badge className="ml-auto text-xs" variant="secondary">
|
|
236
|
+
{parameters?.length}
|
|
237
|
+
</Badge>
|
|
238
|
+
</CollapsibleTrigger>
|
|
239
|
+
<CollapsibleContent>
|
|
240
|
+
<div className="divide-y border-t">
|
|
241
|
+
{children ??
|
|
242
|
+
parameters?.map((param) => (
|
|
243
|
+
<SchemaDisplayParameter key={param.name} {...param} />
|
|
244
|
+
))}
|
|
245
|
+
</div>
|
|
246
|
+
</CollapsibleContent>
|
|
247
|
+
</Collapsible>
|
|
248
|
+
);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export type SchemaDisplayParameterProps = HTMLAttributes<HTMLDivElement> &
|
|
252
|
+
SchemaParameter;
|
|
253
|
+
|
|
254
|
+
export const SchemaDisplayParameter = ({
|
|
255
|
+
name,
|
|
256
|
+
type,
|
|
257
|
+
required,
|
|
258
|
+
description,
|
|
259
|
+
location,
|
|
260
|
+
className,
|
|
261
|
+
...props
|
|
262
|
+
}: SchemaDisplayParameterProps) => (
|
|
263
|
+
<div className={cn("px-4 py-3 pl-10", className)} {...props}>
|
|
264
|
+
<div className="flex items-center gap-2">
|
|
265
|
+
<span className="font-mono text-sm">{name}</span>
|
|
266
|
+
<Badge className="text-xs" variant="outline">
|
|
267
|
+
{type}
|
|
268
|
+
</Badge>
|
|
269
|
+
{location && (
|
|
270
|
+
<Badge className="text-xs" variant="secondary">
|
|
271
|
+
{location}
|
|
272
|
+
</Badge>
|
|
273
|
+
)}
|
|
274
|
+
{required && (
|
|
275
|
+
<Badge
|
|
276
|
+
className="bg-red-100 text-red-700 text-xs dark:bg-red-900/30 dark:text-red-400"
|
|
277
|
+
variant="secondary"
|
|
278
|
+
>
|
|
279
|
+
required
|
|
280
|
+
</Badge>
|
|
281
|
+
)}
|
|
282
|
+
</div>
|
|
283
|
+
{description && (
|
|
284
|
+
<p className="mt-1 text-muted-foreground text-sm">{description}</p>
|
|
285
|
+
)}
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
export type SchemaDisplayRequestProps = ComponentProps<typeof Collapsible>;
|
|
290
|
+
|
|
291
|
+
export const SchemaDisplayRequest = ({
|
|
292
|
+
className,
|
|
293
|
+
children,
|
|
294
|
+
...props
|
|
295
|
+
}: SchemaDisplayRequestProps) => {
|
|
296
|
+
const { requestBody } = useContext(SchemaDisplayContext);
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<Collapsible className={cn(className)} defaultOpen {...props}>
|
|
300
|
+
<CollapsibleTrigger className="group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50">
|
|
301
|
+
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
|
|
302
|
+
<span className="font-medium text-sm">Request Body</span>
|
|
303
|
+
</CollapsibleTrigger>
|
|
304
|
+
<CollapsibleContent>
|
|
305
|
+
<div className="border-t">
|
|
306
|
+
{children ??
|
|
307
|
+
requestBody?.map((prop) => (
|
|
308
|
+
<SchemaDisplayProperty key={prop.name} {...prop} depth={0} />
|
|
309
|
+
))}
|
|
310
|
+
</div>
|
|
311
|
+
</CollapsibleContent>
|
|
312
|
+
</Collapsible>
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export type SchemaDisplayResponseProps = ComponentProps<typeof Collapsible>;
|
|
317
|
+
|
|
318
|
+
export const SchemaDisplayResponse = ({
|
|
319
|
+
className,
|
|
320
|
+
children,
|
|
321
|
+
...props
|
|
322
|
+
}: SchemaDisplayResponseProps) => {
|
|
323
|
+
const { responseBody } = useContext(SchemaDisplayContext);
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<Collapsible className={cn(className)} defaultOpen {...props}>
|
|
327
|
+
<CollapsibleTrigger className="group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50">
|
|
328
|
+
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
|
|
329
|
+
<span className="font-medium text-sm">Response</span>
|
|
330
|
+
</CollapsibleTrigger>
|
|
331
|
+
<CollapsibleContent>
|
|
332
|
+
<div className="border-t">
|
|
333
|
+
{children ??
|
|
334
|
+
responseBody?.map((prop) => (
|
|
335
|
+
<SchemaDisplayProperty key={prop.name} {...prop} depth={0} />
|
|
336
|
+
))}
|
|
337
|
+
</div>
|
|
338
|
+
</CollapsibleContent>
|
|
339
|
+
</Collapsible>
|
|
340
|
+
);
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
export type SchemaDisplayBodyProps = HTMLAttributes<HTMLDivElement>;
|
|
344
|
+
|
|
345
|
+
export const SchemaDisplayBody = ({
|
|
346
|
+
className,
|
|
347
|
+
children,
|
|
348
|
+
...props
|
|
349
|
+
}: SchemaDisplayBodyProps) => (
|
|
350
|
+
<div className={cn("divide-y", className)} {...props}>
|
|
351
|
+
{children}
|
|
352
|
+
</div>
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
export type SchemaDisplayPropertyProps = HTMLAttributes<HTMLDivElement> &
|
|
356
|
+
SchemaProperty & {
|
|
357
|
+
depth?: number;
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
export const SchemaDisplayProperty = ({
|
|
361
|
+
name,
|
|
362
|
+
type,
|
|
363
|
+
required,
|
|
364
|
+
description,
|
|
365
|
+
properties,
|
|
366
|
+
items,
|
|
367
|
+
depth = 0,
|
|
368
|
+
className,
|
|
369
|
+
...props
|
|
370
|
+
}: SchemaDisplayPropertyProps) => {
|
|
371
|
+
const hasChildren = properties || items;
|
|
372
|
+
const paddingLeft = 40 + depth * 16;
|
|
373
|
+
|
|
374
|
+
if (hasChildren) {
|
|
375
|
+
return (
|
|
376
|
+
<Collapsible defaultOpen={depth < 2}>
|
|
377
|
+
<CollapsibleTrigger
|
|
378
|
+
className={cn(
|
|
379
|
+
"group flex w-full items-center gap-2 py-3 text-left transition-colors hover:bg-muted/50",
|
|
380
|
+
className
|
|
381
|
+
)}
|
|
382
|
+
style={{ paddingLeft }}
|
|
383
|
+
>
|
|
384
|
+
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
|
|
385
|
+
<span className="font-mono text-sm">{name}</span>
|
|
386
|
+
<Badge className="text-xs" variant="outline">
|
|
387
|
+
{type}
|
|
388
|
+
</Badge>
|
|
389
|
+
{required && (
|
|
390
|
+
<Badge
|
|
391
|
+
className="bg-red-100 text-red-700 text-xs dark:bg-red-900/30 dark:text-red-400"
|
|
392
|
+
variant="secondary"
|
|
393
|
+
>
|
|
394
|
+
required
|
|
395
|
+
</Badge>
|
|
396
|
+
)}
|
|
397
|
+
</CollapsibleTrigger>
|
|
398
|
+
{description && (
|
|
399
|
+
<p
|
|
400
|
+
className="pb-2 text-muted-foreground text-sm"
|
|
401
|
+
style={{ paddingLeft: paddingLeft + 24 }}
|
|
402
|
+
>
|
|
403
|
+
{description}
|
|
404
|
+
</p>
|
|
405
|
+
)}
|
|
406
|
+
<CollapsibleContent>
|
|
407
|
+
<div className="divide-y border-t">
|
|
408
|
+
{properties?.map((prop) => (
|
|
409
|
+
<SchemaDisplayProperty
|
|
410
|
+
key={prop.name}
|
|
411
|
+
{...prop}
|
|
412
|
+
depth={depth + 1}
|
|
413
|
+
/>
|
|
414
|
+
))}
|
|
415
|
+
{items && (
|
|
416
|
+
<SchemaDisplayProperty
|
|
417
|
+
{...items}
|
|
418
|
+
depth={depth + 1}
|
|
419
|
+
name={`${name}[]`}
|
|
420
|
+
/>
|
|
421
|
+
)}
|
|
422
|
+
</div>
|
|
423
|
+
</CollapsibleContent>
|
|
424
|
+
</Collapsible>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return (
|
|
429
|
+
<div
|
|
430
|
+
className={cn("py-3 pr-4", className)}
|
|
431
|
+
style={{ paddingLeft }}
|
|
432
|
+
{...props}
|
|
433
|
+
>
|
|
434
|
+
<div className="flex items-center gap-2">
|
|
435
|
+
{/* Spacer for alignment */}
|
|
436
|
+
<span className="size-4" />
|
|
437
|
+
<span className="font-mono text-sm">{name}</span>
|
|
438
|
+
<Badge className="text-xs" variant="outline">
|
|
439
|
+
{type}
|
|
440
|
+
</Badge>
|
|
441
|
+
{required && (
|
|
442
|
+
<Badge
|
|
443
|
+
className="bg-red-100 text-red-700 text-xs dark:bg-red-900/30 dark:text-red-400"
|
|
444
|
+
variant="secondary"
|
|
445
|
+
>
|
|
446
|
+
required
|
|
447
|
+
</Badge>
|
|
448
|
+
)}
|
|
449
|
+
</div>
|
|
450
|
+
{description && (
|
|
451
|
+
<p className="mt-1 pl-6 text-muted-foreground text-sm">{description}</p>
|
|
452
|
+
)}
|
|
453
|
+
</div>
|
|
454
|
+
);
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
export type SchemaDisplayExampleProps = HTMLAttributes<HTMLPreElement>;
|
|
458
|
+
|
|
459
|
+
export const SchemaDisplayExample = ({
|
|
460
|
+
className,
|
|
461
|
+
children,
|
|
462
|
+
...props
|
|
463
|
+
}: SchemaDisplayExampleProps) => (
|
|
464
|
+
<pre
|
|
465
|
+
className={cn(
|
|
466
|
+
"mx-4 mb-4 overflow-auto rounded-md bg-muted p-4 font-mono text-sm",
|
|
467
|
+
className
|
|
468
|
+
)}
|
|
469
|
+
{...props}
|
|
470
|
+
>
|
|
471
|
+
{children}
|
|
472
|
+
</pre>
|
|
473
|
+
);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { MotionProps } from "motion/react";
|
|
4
|
+
import type { CSSProperties, ElementType, JSX } from "react";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
import { motion } from "motion/react";
|
|
8
|
+
import { memo, useMemo } from "react";
|
|
9
|
+
|
|
10
|
+
type MotionHTMLProps = MotionProps & Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
// Cache motion components at module level to avoid creating during render
|
|
13
|
+
const motionComponentCache = new Map<
|
|
14
|
+
keyof JSX.IntrinsicElements,
|
|
15
|
+
React.ComponentType<MotionHTMLProps>
|
|
16
|
+
>();
|
|
17
|
+
|
|
18
|
+
const getMotionComponent = (element: keyof JSX.IntrinsicElements) => {
|
|
19
|
+
let component = motionComponentCache.get(element);
|
|
20
|
+
if (!component) {
|
|
21
|
+
component = motion.create(element);
|
|
22
|
+
motionComponentCache.set(element, component);
|
|
23
|
+
}
|
|
24
|
+
return component;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export interface TextShimmerProps {
|
|
28
|
+
children: string;
|
|
29
|
+
as?: ElementType;
|
|
30
|
+
className?: string;
|
|
31
|
+
duration?: number;
|
|
32
|
+
spread?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const ShimmerComponent = ({
|
|
36
|
+
children,
|
|
37
|
+
as: Component = "p",
|
|
38
|
+
className,
|
|
39
|
+
duration = 2,
|
|
40
|
+
spread = 2,
|
|
41
|
+
}: TextShimmerProps) => {
|
|
42
|
+
const MotionComponent = getMotionComponent(
|
|
43
|
+
Component as keyof JSX.IntrinsicElements
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const dynamicSpread = useMemo(
|
|
47
|
+
() => (children?.length ?? 0) * spread,
|
|
48
|
+
[children, spread]
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<MotionComponent
|
|
53
|
+
animate={{ backgroundPosition: "0% center" }}
|
|
54
|
+
className={cn(
|
|
55
|
+
"relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent",
|
|
56
|
+
"[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
initial={{ backgroundPosition: "100% center" }}
|
|
60
|
+
style={
|
|
61
|
+
{
|
|
62
|
+
"--spread": `${dynamicSpread}px`,
|
|
63
|
+
backgroundImage:
|
|
64
|
+
"var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))",
|
|
65
|
+
} as CSSProperties
|
|
66
|
+
}
|
|
67
|
+
transition={{
|
|
68
|
+
duration,
|
|
69
|
+
ease: "linear",
|
|
70
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</MotionComponent>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Shimmer = memo(ShimmerComponent);
|