@djangocfg/ui-tools 2.1.194 → 2.1.197

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.
@@ -1,8 +1,8 @@
1
- import { usePlaygroundContext, deduplicateEndpoints, getStatusColor, isValidJson, PrettyCode_default, getVersionById, getVersionStats, API_VERSIONS, getMethodColor, findApiKeyById, parseRequestHeaders } from './chunk-UX2MCSN5.mjs';
1
+ import { usePlaygroundContext, deduplicateEndpoints, getStatusColor, isValidJson, PrettyCode_default, findApiKeyById, parseRequestHeaders, getMethodColor } from './chunk-FXFTJW2Y.mjs';
2
2
  import { JsonTree_default } from './chunk-XXFYTIQK.mjs';
3
3
  import { __name } from './chunk-CGILA3WO.mjs';
4
- import { Menu, X, FileText, Send, Code, Check, ChevronLeft, ChevronRight, List, Grid3X3, Filter, Search, Download, XCircle, Key, Loader2, GitBranch, Info, Settings, BarChart3, Database, Users, Shield, ChevronDown, AlertCircle, HelpCircle } from 'lucide-react';
5
- import { Sheet, SheetTrigger, Button, SheetContent, Skeleton, Card, CardContent, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, CardHeader, CardTitle, CopyButton, Badge, Textarea, Collapsible, CollapsibleTrigger, CollapsibleContent, TooltipProvider, Tabs, TabsList, TabsTrigger, TabsContent, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Tooltip, TooltipTrigger, TooltipContent } from '@djangocfg/ui-core/components';
4
+ import { Menu, X, FileText, Send, Code, Check, ChevronLeft, ChevronRight, Search, Filter, List, Grid3X3, Download, XCircle, Key, Loader2, Database, ChevronDown, AlertCircle, HelpCircle } from 'lucide-react';
5
+ import { Sheet, SheetTrigger, Button, SheetContent, Skeleton, Card, CardContent, Combobox, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DownloadButton, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, CardHeader, CardTitle, CopyButton, Badge, Textarea, Collapsible, CollapsibleTrigger, CollapsibleContent, TooltipProvider, Tabs, TabsList, TabsTrigger, TabsContent, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Tooltip, TooltipTrigger, TooltipContent } from '@djangocfg/ui-core/components';
6
6
  import { useIsMobile } from '@djangocfg/ui-core/hooks';
7
7
  import React, { useState, useMemo, useEffect, useCallback } from 'react';
8
8
  import consola from 'consola';
@@ -15,19 +15,21 @@ var useMobile = /* @__PURE__ */ __name(() => {
15
15
  isDesktop: !isMobile
16
16
  };
17
17
  }, "useMobile");
18
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
18
19
  var extractEndpoints = /* @__PURE__ */ __name((schema) => {
19
- const endpointMap = /* @__PURE__ */ new Map();
20
+ const endpoints = [];
20
21
  if (!schema.paths) return [];
21
22
  const baseUrl = schema.servers && schema.servers.length > 0 ? schema.servers[0].url : "";
22
23
  for (const [path, methods] of Object.entries(schema.paths)) {
23
- const getOperation = methods.get;
24
- if (!getOperation) continue;
25
- const op = getOperation;
26
- const description = op.description || op.summary || `GET ${path}`;
27
- const category = op.tags?.[0] || "Other";
28
- const parameters = [];
29
- if (op.parameters) {
30
- for (const param of op.parameters) {
24
+ for (const method of HTTP_METHODS) {
25
+ const op = methods[method];
26
+ if (!op) continue;
27
+ const methodUpper = method.toUpperCase();
28
+ const description = op.description || op.summary || `${methodUpper} ${path}`;
29
+ const category = op.tags?.[0] || "Other";
30
+ const parameters = [];
31
+ const allParams = [...methods.parameters || [], ...op.parameters || []];
32
+ for (const param of allParams) {
31
33
  parameters.push({
32
34
  name: param.name,
33
35
  type: param.schema?.type || "string",
@@ -35,31 +37,38 @@ var extractEndpoints = /* @__PURE__ */ __name((schema) => {
35
37
  description: param.description
36
38
  });
37
39
  }
38
- }
39
- const responses = [];
40
- if (op.responses) {
41
- for (const [code, response] of Object.entries(op.responses)) {
42
- responses.push({
43
- code,
44
- description: response.description || `Response ${code}`
45
- });
40
+ const responses = [];
41
+ if (op.responses) {
42
+ for (const [code, response] of Object.entries(op.responses)) {
43
+ responses.push({
44
+ code,
45
+ description: response.description || `Response ${code}`
46
+ });
47
+ }
46
48
  }
49
+ let requestBody;
50
+ if (op.requestBody) {
51
+ const content = op.requestBody.content;
52
+ const mediaType = content?.["application/json"] || content?.[Object.keys(content || {})[0]];
53
+ requestBody = {
54
+ type: mediaType?.schema?.type || "object",
55
+ description: op.requestBody.description
56
+ };
57
+ }
58
+ const endpoint = {
59
+ name: path.split("/").pop() || path,
60
+ method: methodUpper,
61
+ path: baseUrl + path,
62
+ description,
63
+ category,
64
+ parameters: parameters.length > 0 ? parameters : void 0,
65
+ requestBody,
66
+ responses: responses.length > 0 ? responses : void 0
67
+ };
68
+ endpoints.push(endpoint);
47
69
  }
48
- const endpoint = {
49
- name: path.split("/").pop() || path,
50
- method: "GET",
51
- path: baseUrl + path,
52
- // Combine baseUrl with path
53
- description,
54
- category,
55
- parameters: parameters.length > 0 ? parameters : void 0,
56
- requestBody: void 0,
57
- // GET requests don't have request body
58
- responses: responses.length > 0 ? responses : void 0
59
- };
60
- endpointMap.set(path, endpoint);
61
70
  }
62
- return Array.from(endpointMap.values());
71
+ return endpoints;
63
72
  }, "extractEndpoints");
64
73
  var getCategories = /* @__PURE__ */ __name((endpoints) => {
65
74
  const categories = /* @__PURE__ */ new Set();
@@ -154,53 +163,16 @@ function useOpenApiSchema({
154
163
  };
155
164
  }
156
165
  __name(useOpenApiSchema, "useOpenApiSchema");
157
- var VersionSelector = /* @__PURE__ */ __name(() => {
158
- const { state, config, setSelectedVersion } = usePlaygroundContext();
159
- const { endpoints } = useOpenApiSchema({
160
- schemas: config.schemas,
161
- defaultSchemaId: config.defaultSchemaId
162
- });
163
- const currentVersion = getVersionById(state.selectedVersion);
164
- const versionStats = getVersionStats(endpoints);
165
- const handleVersionChange = /* @__PURE__ */ __name((versionId) => {
166
- setSelectedVersion(versionId);
167
- }, "handleVersionChange");
168
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
169
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
170
- /* @__PURE__ */ jsx(GitBranch, { className: "h-4 w-4 text-muted-foreground" }),
171
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: "API Version:" })
172
- ] }),
173
- /* @__PURE__ */ jsxs(Select, { value: state.selectedVersion, onValueChange: handleVersionChange, children: [
174
- /* @__PURE__ */ jsx(SelectTrigger, { className: "w-48", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
175
- /* @__PURE__ */ jsx(SelectContent, { children: API_VERSIONS.map((version) => /* @__PURE__ */ jsx(SelectItem, { value: version.id, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between w-full", children: [
176
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
177
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: version.name }),
178
- version.isDefault && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: "Default" })
179
- ] }),
180
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground ml-2", children: [
181
- versionStats[version.id] || 0,
182
- " endpoints"
183
- ] })
184
- ] }) }, version.id)) })
185
- ] }),
186
- currentVersion && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-1 text-xs text-muted-foreground", children: [
187
- /* @__PURE__ */ jsx(Info, { className: "h-3 w-3" }),
188
- /* @__PURE__ */ jsx("span", { children: currentVersion.description })
189
- ] })
190
- ] });
191
- }, "VersionSelector");
192
- var categoryIcons = {
193
- "Authentication": /* @__PURE__ */ jsx(Shield, { className: "h-4 w-4" }),
194
- "Users": /* @__PURE__ */ jsx(Users, { className: "h-4 w-4" }),
195
- "Data": /* @__PURE__ */ jsx(Database, { className: "h-4 w-4" }),
196
- "Analytics": /* @__PURE__ */ jsx(BarChart3, { className: "h-4 w-4" }),
197
- "Files": /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" }),
198
- "Settings": /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }),
199
- "Other": /* @__PURE__ */ jsx(Code, { className: "h-4 w-4" })
166
+ var METHOD_BADGE_VARIANTS = {
167
+ GET: "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 border-emerald-500/20",
168
+ POST: "bg-blue-500/15 text-blue-600 dark:text-blue-400 border-blue-500/20",
169
+ PUT: "bg-amber-500/15 text-amber-600 dark:text-amber-400 border-amber-500/20",
170
+ PATCH: "bg-orange-500/15 text-orange-600 dark:text-orange-400 border-orange-500/20",
171
+ DELETE: "bg-red-500/15 text-red-600 dark:text-red-400 border-red-500/20"
200
172
  };
201
173
  var EndpointsLibrary = /* @__PURE__ */ __name(() => {
202
174
  const { state, config, setSelectedEndpoint, setSelectedCategory, setSearchTerm } = usePlaygroundContext();
203
- const { endpoints, categories, loading, error } = useOpenApiSchema({
175
+ const { endpoints, categories, loading, error, schemas, currentSchema, setCurrentSchema } = useOpenApiSchema({
204
176
  schemas: config.schemas,
205
177
  defaultSchemaId: config.defaultSchemaId
206
178
  });
@@ -226,122 +198,142 @@ var EndpointsLibrary = /* @__PURE__ */ __name(() => {
226
198
  }
227
199
  return filtered;
228
200
  }, [endpoints, state.selectedCategory, state.searchTerm, state.selectedVersion]);
229
- const handleEndpointSelect = /* @__PURE__ */ __name((endpoint) => {
230
- setSelectedEndpoint(endpoint);
231
- }, "handleEndpointSelect");
232
- const getMethodBadges = /* @__PURE__ */ __name((methods) => {
233
- return methods.split(", ").map((method) => /* @__PURE__ */ jsx(Badge, { variant: getMethodColor(method) === "success" ? "default" : "secondary", className: "text-xs", children: method }, method));
234
- }, "getMethodBadges");
201
+ const schemaOptions = useMemo(
202
+ () => schemas.map((s) => ({ value: s.id, label: s.name })),
203
+ [schemas]
204
+ );
205
+ const getMethodBadge = /* @__PURE__ */ __name((method) => /* @__PURE__ */ jsx(
206
+ Badge,
207
+ {
208
+ variant: "outline",
209
+ className: `text-xs font-mono font-semibold ${METHOD_BADGE_VARIANTS[method.toUpperCase()] || ""}`,
210
+ children: method
211
+ },
212
+ method
213
+ ), "getMethodBadge");
235
214
  if (loading) {
236
- return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
237
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
238
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: "API Endpoints" }),
239
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
240
- /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-32" }),
241
- /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-48" })
242
- ] })
215
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
216
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
217
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-44" }),
218
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-9 flex-1 max-w-xs" }),
219
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
220
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-24" })
243
221
  ] }),
244
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-20 w-full" }, i)) })
222
+ /* @__PURE__ */ jsx("div", { className: "space-y-1", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }, i)) })
245
223
  ] });
246
224
  }
247
225
  if (error) {
248
- return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
249
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: "API Endpoints" }) }),
250
- /* @__PURE__ */ jsx(Card, { className: "bg-destructive/10 border-destructive/20", children: /* @__PURE__ */ jsx(CardContent, { className: "p-4", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
251
- "Error loading endpoints: ",
252
- error
253
- ] }) }) })
254
- ] });
226
+ return /* @__PURE__ */ jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsx(Card, { className: "bg-destructive/10 border-destructive/20", children: /* @__PURE__ */ jsx(CardContent, { className: "p-4", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
227
+ "Failed to load schema: ",
228
+ error
229
+ ] }) }) }) });
255
230
  }
256
- return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
257
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
258
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4", children: [
259
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: "API Endpoints" }),
260
- /* @__PURE__ */ jsx(VersionSelector, {})
231
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
232
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
233
+ schemas.length > 1 && /* @__PURE__ */ jsx(
234
+ Combobox,
235
+ {
236
+ options: schemaOptions,
237
+ value: currentSchema?.id || "",
238
+ onValueChange: (id) => id && setCurrentSchema(id),
239
+ placeholder: "Select API",
240
+ searchPlaceholder: "Search APIs...",
241
+ emptyText: "No APIs found",
242
+ className: "w-44"
243
+ }
244
+ ),
245
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1 max-w-xs", children: [
246
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
247
+ /* @__PURE__ */ jsx(
248
+ Input,
249
+ {
250
+ placeholder: "Search...",
251
+ value: state.searchTerm,
252
+ onChange: (e) => setSearchTerm(e.target.value),
253
+ className: "h-9 pl-8 text-sm"
254
+ }
255
+ )
261
256
  ] }),
262
- /* @__PURE__ */ jsx("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
263
- /* @__PURE__ */ jsxs("div", { className: "flex items-center border rounded-md", children: [
264
- /* @__PURE__ */ jsx(
265
- Button,
266
- {
267
- variant: viewMode === "table" ? "default" : "ghost",
268
- size: "sm",
269
- onClick: () => setViewMode("table"),
270
- className: "rounded-r-none",
271
- children: /* @__PURE__ */ jsx(List, { className: "h-4 w-4" })
272
- }
273
- ),
274
- /* @__PURE__ */ jsx(
275
- Button,
276
- {
277
- variant: viewMode === "grid" ? "default" : "ghost",
278
- size: "sm",
279
- onClick: () => setViewMode("grid"),
280
- className: "rounded-l-none",
281
- children: /* @__PURE__ */ jsx(Grid3X3, { className: "h-4 w-4" })
282
- }
283
- )
257
+ /* @__PURE__ */ jsxs(Select, { value: state.selectedCategory, onValueChange: setSelectedCategory, children: [
258
+ /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-auto h-9 gap-1.5", children: [
259
+ /* @__PURE__ */ jsx(Filter, { className: "h-3.5 w-3.5" }),
260
+ /* @__PURE__ */ jsx(SelectValue, {})
284
261
  ] }),
285
- /* @__PURE__ */ jsxs(Select, { value: state.selectedCategory, onValueChange: setSelectedCategory, children: [
286
- /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-32", children: [
287
- /* @__PURE__ */ jsx(Filter, { className: "h-4 w-4 mr-2" }),
288
- /* @__PURE__ */ jsx(SelectValue, {})
289
- ] }),
290
- /* @__PURE__ */ jsxs(SelectContent, { children: [
291
- /* @__PURE__ */ jsx(SelectItem, { value: "All", children: "All" }),
292
- categories.map((category) => /* @__PURE__ */ jsx(SelectItem, { value: category, children: category }, category))
293
- ] })
294
- ] }),
295
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
296
- /* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
297
- /* @__PURE__ */ jsx(
298
- Input,
299
- {
300
- placeholder: "Search endpoints...",
301
- value: state.searchTerm,
302
- onChange: (e) => setSearchTerm(e.target.value),
303
- className: "w-48 pl-8"
304
- }
305
- )
262
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
263
+ /* @__PURE__ */ jsx(SelectItem, { value: "All", children: "All" }),
264
+ categories.map((category) => /* @__PURE__ */ jsx(SelectItem, { value: category, children: category }, category))
306
265
  ] })
307
- ] }) })
266
+ ] }),
267
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
268
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground tabular-nums hidden sm:inline", children: [
269
+ filteredEndpoints.length,
270
+ " endpoint",
271
+ filteredEndpoints.length !== 1 ? "s" : ""
272
+ ] }),
273
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center border rounded-md", children: [
274
+ /* @__PURE__ */ jsx(
275
+ Button,
276
+ {
277
+ variant: viewMode === "table" ? "default" : "ghost",
278
+ size: "icon",
279
+ className: "h-8 w-8 rounded-r-none",
280
+ onClick: () => setViewMode("table"),
281
+ children: /* @__PURE__ */ jsx(List, { className: "h-3.5 w-3.5" })
282
+ }
283
+ ),
284
+ /* @__PURE__ */ jsx(
285
+ Button,
286
+ {
287
+ variant: viewMode === "grid" ? "default" : "ghost",
288
+ size: "icon",
289
+ className: "h-8 w-8 rounded-l-none",
290
+ onClick: () => setViewMode("grid"),
291
+ children: /* @__PURE__ */ jsx(Grid3X3, { className: "h-3.5 w-3.5" })
292
+ }
293
+ )
294
+ ] }),
295
+ currentSchema && /* @__PURE__ */ jsx(
296
+ DownloadButton,
297
+ {
298
+ url: currentSchema.url,
299
+ filename: `${currentSchema.id}-openapi.json`,
300
+ variant: "outline",
301
+ size: "sm",
302
+ className: "h-8",
303
+ children: /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Schema" })
304
+ }
305
+ )
308
306
  ] }),
309
307
  viewMode === "table" ? /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Table, { children: [
310
308
  /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
311
- /* @__PURE__ */ jsx(TableHead, { className: "text-foreground", children: "Methods" }),
309
+ /* @__PURE__ */ jsx(TableHead, { className: "w-20 text-foreground", children: "Method" }),
312
310
  /* @__PURE__ */ jsx(TableHead, { className: "text-foreground", children: "Path" }),
313
- /* @__PURE__ */ jsx(TableHead, { className: "text-foreground", children: "Description" })
311
+ /* @__PURE__ */ jsx(TableHead, { className: "text-foreground hidden lg:table-cell", children: "Description" })
314
312
  ] }) }),
315
- /* @__PURE__ */ jsx(TableBody, { children: filteredEndpoints.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: 3, className: "text-center py-8 text-muted-foreground", children: "No endpoints found" }) }) : filteredEndpoints.map((endpoint) => /* @__PURE__ */ jsxs(
313
+ /* @__PURE__ */ jsx(TableBody, { children: filteredEndpoints.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: 3, className: "text-center py-12 text-muted-foreground", children: "No endpoints found" }) }) : filteredEndpoints.map((endpoint) => /* @__PURE__ */ jsxs(
316
314
  TableRow,
317
315
  {
318
- className: `cursor-pointer transition-colors hover:bg-muted/50 ${state.selectedEndpoint?.path === endpoint.path ? "bg-primary/10" : ""}`,
319
- onClick: () => handleEndpointSelect(endpoint),
316
+ className: `cursor-pointer transition-colors hover:bg-muted/50 ${state.selectedEndpoint?.path === endpoint.path && state.selectedEndpoint?.method === endpoint.method ? "bg-primary/5" : ""}`,
317
+ onClick: () => setSelectedEndpoint(endpoint),
320
318
  children: [
321
- /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("div", { className: "flex space-x-1", children: getMethodBadges(endpoint.method) }) }),
322
- /* @__PURE__ */ jsx(TableCell, { className: "font-mono text-sm text-muted-foreground", children: getRelativePath(endpoint.path) }),
323
- /* @__PURE__ */ jsx(TableCell, { className: "text-sm text-muted-foreground max-w-xs truncate", children: endpoint.description })
319
+ /* @__PURE__ */ jsx(TableCell, { className: "py-2.5", children: getMethodBadge(endpoint.method) }),
320
+ /* @__PURE__ */ jsx(TableCell, { className: "font-mono text-sm text-muted-foreground py-2.5", children: getRelativePath(endpoint.path) }),
321
+ /* @__PURE__ */ jsx(TableCell, { className: "text-sm text-muted-foreground max-w-sm truncate py-2.5 hidden lg:table-cell", children: endpoint.description })
324
322
  ]
325
323
  },
326
324
  `${endpoint.method}-${endpoint.path}`
327
325
  )) })
328
- ] }) }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: filteredEndpoints.length === 0 ? /* @__PURE__ */ jsx("div", { className: "col-span-full text-center py-8 text-muted-foreground", children: "No endpoints found" }) : filteredEndpoints.map((endpoint) => /* @__PURE__ */ jsxs(
326
+ ] }) }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3", children: filteredEndpoints.length === 0 ? /* @__PURE__ */ jsx("div", { className: "col-span-full text-center py-12 text-muted-foreground", children: "No endpoints found" }) : filteredEndpoints.map((endpoint) => /* @__PURE__ */ jsxs(
329
327
  Card,
330
328
  {
331
- className: `cursor-pointer transition-all hover:shadow-md ${state.selectedEndpoint?.path === endpoint.path ? "ring-2 ring-primary" : ""}`,
332
- onClick: () => handleEndpointSelect(endpoint),
329
+ className: `cursor-pointer transition-all hover:shadow-md ${state.selectedEndpoint?.path === endpoint.path && state.selectedEndpoint?.method === endpoint.method ? "ring-2 ring-primary" : ""}`,
330
+ onClick: () => setSelectedEndpoint(endpoint),
333
331
  children: [
334
- /* @__PURE__ */ jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between text-sm", children: [
335
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
336
- categoryIcons[endpoint.category] || /* @__PURE__ */ jsx(Code, { className: "h-4 w-4" }),
337
- /* @__PURE__ */ jsx("span", { className: "truncate", children: endpoint.name })
338
- ] }),
339
- /* @__PURE__ */ jsx("div", { className: "flex space-x-1", children: getMethodBadges(endpoint.method) })
332
+ /* @__PURE__ */ jsx(CardHeader, { className: "pb-2 pt-3 px-4", children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between text-sm", children: [
333
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-muted-foreground truncate", children: getRelativePath(endpoint.path) }),
334
+ getMethodBadge(endpoint.method)
340
335
  ] }) }),
341
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-2", children: [
342
- /* @__PURE__ */ jsx("p", { className: "text-xs font-mono text-muted-foreground break-all", children: getRelativePath(endpoint.path) }),
343
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground line-clamp-2", children: endpoint.description })
344
- ] })
336
+ /* @__PURE__ */ jsx(CardContent, { className: "px-4 pb-3 pt-0", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground line-clamp-2", children: endpoint.description }) })
345
337
  ]
346
338
  },
347
339
  `${endpoint.method}-${endpoint.path}`
@@ -371,7 +363,7 @@ var PlaygroundStepper = /* @__PURE__ */ __name(() => {
371
363
  const currentIndex = steps.indexOf(currentStep);
372
364
  const canGoNext = currentIndex < steps.length - 1;
373
365
  const canGoPrevious = currentIndex > 0;
374
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b", children: [
366
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between w-full", children: [
375
367
  /* @__PURE__ */ jsx("div", { className: "flex items-center space-x-4", children: steps.map((step, index) => {
376
368
  const config = stepConfig[step];
377
369
  const Icon = config.icon;
@@ -930,26 +922,10 @@ var PlaygroundLayout = /* @__PURE__ */ __name(() => {
930
922
  return /* @__PURE__ */ jsx(EndpointsLibrary, {});
931
923
  }
932
924
  }, "renderStepContent");
933
- const getStepTitle = /* @__PURE__ */ __name(() => {
934
- switch (state.currentStep) {
935
- case "endpoints":
936
- return "API Endpoints";
937
- case "request":
938
- return "Request Builder";
939
- case "response":
940
- return "Response Viewer";
941
- default:
942
- return "API Playground";
943
- }
944
- }, "getStepTitle");
945
- return /* @__PURE__ */ jsxs("div", { className: "min-h-screen", children: [
946
- /* @__PURE__ */ jsx("div", { className: "border-b", children: /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
947
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-4", children: [
948
- /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold text-foreground", children: "API Playground" }),
949
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground hidden sm:block", children: "Test and explore API endpoints" })
950
- ] }),
951
- isMobile && /* @__PURE__ */ jsxs(Sheet, { open: state.sidebarOpen, onOpenChange: setSidebarOpen, children: [
952
- /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", children: /* @__PURE__ */ jsx(Menu, { className: "h-4 w-4" }) }) }),
925
+ return /* @__PURE__ */ jsxs("div", { children: [
926
+ /* @__PURE__ */ jsx("div", { className: "border-b", children: /* @__PURE__ */ jsx("div", { className: "container mx-auto px-6 py-3", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: isMobile ? /* @__PURE__ */ jsxs(Fragment, { children: [
927
+ /* @__PURE__ */ jsxs(Sheet, { open: state.sidebarOpen, onOpenChange: setSidebarOpen, children: [
928
+ /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(Menu, { className: "h-4 w-4" }) }) }),
953
929
  /* @__PURE__ */ jsx(SheetContent, { side: "left", className: "w-80", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
954
930
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
955
931
  /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Navigation" }),
@@ -965,27 +941,17 @@ var PlaygroundLayout = /* @__PURE__ */ __name(() => {
965
941
  ] }),
966
942
  /* @__PURE__ */ jsx(PlaygroundStepper, {})
967
943
  ] }) })
968
- ] })
969
- ] }) }) }),
970
- !isMobile && /* @__PURE__ */ jsx(PlaygroundStepper, {}),
971
- /* @__PURE__ */ jsxs("div", { className: "container mx-auto px-6 py-6", children: [
972
- /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
973
- /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold text-foreground", children: getStepTitle() }),
974
- /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground mt-1", children: [
975
- state.currentStep === "endpoints" && "Browse and select API endpoints",
976
- state.currentStep === "request" && "Configure your API request",
977
- state.currentStep === "response" && "View API response and details"
978
- ] })
979
944
  ] }),
980
- /* @__PURE__ */ jsx("div", { className: "space-y-6", children: renderStepContent() })
981
- ] }),
945
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground capitalize", children: state.currentStep }),
946
+ /* @__PURE__ */ jsx("div", { className: "w-8" }),
947
+ " "
948
+ ] }) : /* @__PURE__ */ jsx(PlaygroundStepper, {}) }) }) }),
949
+ /* @__PURE__ */ jsx("div", { className: "container mx-auto px-6 py-6", children: renderStepContent() }),
982
950
  isMobile && state.currentStep === "request" && /* @__PURE__ */ jsx("div", { className: "fixed bottom-4 right-4 z-50", children: /* @__PURE__ */ jsx(
983
951
  Button,
984
952
  {
985
953
  size: "lg",
986
954
  className: "rounded-full shadow-lg",
987
- onClick: () => {
988
- },
989
955
  children: "Send Request"
990
956
  }
991
957
  ) })
@@ -993,5 +959,5 @@ var PlaygroundLayout = /* @__PURE__ */ __name(() => {
993
959
  }, "PlaygroundLayout");
994
960
 
995
961
  export { PlaygroundLayout };
996
- //# sourceMappingURL=PlaygroundLayout-YH77POI4.mjs.map
997
- //# sourceMappingURL=PlaygroundLayout-YH77POI4.mjs.map
962
+ //# sourceMappingURL=PlaygroundLayout-DWRNA2QM.mjs.map
963
+ //# sourceMappingURL=PlaygroundLayout-DWRNA2QM.mjs.map