@rebasepro/studio 0.10.0 → 0.10.1-canary.14e53ae

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.
@@ -767,7 +767,9 @@ function ApiExplorer() {
767
767
  const specUrl = `${apiUrl.replace(/\/+$/, "")}/api/docs`;
768
768
  (async () => {
769
769
  try {
770
- const res = await fetch(specUrl);
770
+ const getAuthToken = apiConfig?.getAuthToken ?? authController.getAuthToken;
771
+ const token = getAuthToken ? await getAuthToken() : null;
772
+ const res = await fetch(specUrl, token ? { headers: { Authorization: `Bearer ${token}` } } : void 0);
771
773
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
772
774
  const data = await res.json();
773
775
  if (!cancelled) {
@@ -784,7 +786,11 @@ function ApiExplorer() {
784
786
  return () => {
785
787
  cancelled = true;
786
788
  };
787
- }, [apiUrl]);
789
+ }, [
790
+ apiUrl,
791
+ apiConfig,
792
+ authController
793
+ ]);
788
794
  const { groups, allEndpoints } = useMemo(() => {
789
795
  if (!spec) return {
790
796
  groups: [],
@@ -960,4 +966,4 @@ ApiExplorer.displayName = "ApiExplorer";
960
966
  //#endregion
961
967
  export { ApiExplorer };
962
968
 
963
- //# sourceMappingURL=ApiExplorer-B9M9-uy_.js.map
969
+ //# sourceMappingURL=ApiExplorer-VRKWqCVI.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApiExplorer-B9M9-uy_.js","names":[],"sources":["../src/components/ApiExplorer/parseSpec.ts","../src/components/ApiExplorer/EndpointDetail.tsx","../src/components/ApiExplorer/TryItPanel.tsx","../src/components/ApiExplorer/ApiExplorer.tsx"],"sourcesContent":["import type { OpenApiSpec, ParsedEndpoint, EndpointGroup } from \"./types\";\n\n/**\n * Parse an OpenAPI 3.x spec into grouped, sorted endpoints for the sidebar.\n */\nexport function parseOpenApiSpec(spec: OpenApiSpec): {\n groups: EndpointGroup[];\n allEndpoints: ParsedEndpoint[];\n} {\n const allEndpoints: ParsedEndpoint[] = [];\n const tagMap = new Map<string, ParsedEndpoint[]>();\n\n // Build tag description lookup\n const tagDescriptions = new Map<string, string>();\n for (const t of spec.tags ?? []) {\n tagDescriptions.set(t.name, t.description ?? \"\");\n }\n\n for (const [path, methods] of Object.entries(spec.paths ?? {})) {\n for (const [method, op] of Object.entries(methods)) {\n if ([\"get\", \"post\", \"put\", \"patch\", \"delete\"].indexOf(method) === -1) continue;\n\n const tags = op.tags?.length ? op.tags : [\"Other\"];\n const shortPath = path.replace(/^\\/api\\/data/, \"\");\n\n const endpoint: ParsedEndpoint = {\n id: `${method}:${path}`,\n method,\n path,\n shortPath: shortPath || \"/\",\n summary: op.summary ?? \"\",\n description: op.description ?? \"\",\n tags,\n parameters: op.parameters ?? [],\n requestBody: op.requestBody,\n responses: op.responses ?? {},\n security: op.security,\n operationId: op.operationId\n };\n\n allEndpoints.push(endpoint);\n for (const tag of tags) {\n if (!tagMap.has(tag)) tagMap.set(tag, []);\n tagMap.get(tag)!.push(endpoint);\n }\n }\n }\n\n // Method sort order\n const ORDER: Record<string, number> = { get: 0,\npost: 1,\nput: 2,\npatch: 3,\ndelete: 4 };\n\n const groups: EndpointGroup[] = [];\n // Sort tags: use spec.tags order if available, else alphabetical\n const tagOrder = (spec.tags ?? []).map((t) => t.name);\n const sortedTags = [...tagMap.keys()].sort((a, b) => {\n const ai = tagOrder.indexOf(a);\n const bi = tagOrder.indexOf(b);\n if (ai !== -1 && bi !== -1) return ai - bi;\n if (ai !== -1) return -1;\n if (bi !== -1) return 1;\n return a.localeCompare(b);\n });\n\n for (const tag of sortedTags) {\n const endpoints = tagMap.get(tag)!;\n endpoints.sort((a, b) => {\n const pa = a.path.localeCompare(b.path);\n if (pa !== 0) return pa;\n return (ORDER[a.method] ?? 99) - (ORDER[b.method] ?? 99);\n });\n groups.push({\n tag,\n description: tagDescriptions.get(tag),\n endpoints\n });\n }\n\n return { groups,\nallEndpoints };\n}\n\n/**\n * Resolve a $ref string (e.g. \"#/components/schemas/Author\") to a schema name.\n */\nexport function resolveRefName(ref: string): string {\n const parts = ref.split(\"/\");\n return parts[parts.length - 1];\n}\n\n/**\n * Resolve a $ref to its actual schema from the spec.\n */\nexport function resolveRef(spec: OpenApiSpec, ref: string): unknown {\n const parts = ref.replace(\"#/\", \"\").split(\"/\");\n let current: unknown = spec;\n for (const part of parts) {\n current = (current as Record<string, unknown>)?.[part];\n }\n return current ?? {};\n}\n","import React from \"react\";\nimport {\n ArrowRightFromLineIcon,\n Chip,\n cls,\n defaultBorderMixin,\n iconSize,\n SlidersHorizontalIcon,\n Typography,\n UploadIcon\n} from \"@rebasepro/ui\";\nimport type { ParsedEndpoint, OpenApiSpec, OpenApiSchema } from \"./types\";\nimport { resolveRef, resolveRefName } from \"./parseSpec\";\n\n/**\n * Renders the documentation view for a single API endpoint:\n * parameters, request body schema, response schemas.\n */\nexport function EndpointDetail({ endpoint, spec }: { endpoint: ParsedEndpoint; spec: OpenApiSpec }) {\n return (\n <div className=\"p-6 space-y-8 max-w-4xl\">\n {/* Summary / Description */}\n {(endpoint.summary || endpoint.description) && (\n <div>\n {endpoint.summary && (\n <Typography variant=\"h6\" className=\"font-semibold mb-1\">\n {endpoint.summary}\n </Typography>\n )}\n {endpoint.description && (\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {endpoint.description}\n </Typography>\n )}\n </div>\n )}\n\n {/* Parameters */}\n {endpoint.parameters.length > 0 && (\n <section>\n <SectionHeading icon={<SlidersHorizontalIcon size={iconSize.small} className=\"text-text-secondary dark:text-text-secondary-dark\" />} title=\"Parameters\"/>\n <div className={cls(\"rounded-lg border overflow-hidden\", defaultBorderMixin)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-surface-100 dark:bg-surface-900 text-left\">\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n Name\n </th>\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n In\n </th>\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n Type\n </th>\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n Description\n </th>\n </tr>\n </thead>\n <tbody>\n {endpoint.parameters.map((p, i) => (\n <tr\n key={p.name + i}\n className={cls(\"border-t\", defaultBorderMixin)}\n >\n <td className=\"px-4 py-2.5\">\n <code className=\"text-xs font-mono font-semibold\">{p.name}</code>\n {p.required && <span className=\"text-red-500 ml-1 text-xs\">*</span>}\n </td>\n <td className=\"px-4 py-2.5\">\n <Chip\n size=\"smallest\"\n colorScheme={p.in === \"path\" ? \"orangeDarker\" : \"cyanDarker\"}\n >\n {p.in}\n </Chip>\n </td>\n <td className=\"px-4 py-2.5 text-xs font-mono text-text-secondary dark:text-text-secondary-dark\">\n {schemaTypeLabel(p.schema)}\n </td>\n <td className=\"px-4 py-2.5 text-xs text-text-secondary dark:text-text-secondary-dark\">\n {p.description ?? \"—\"}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </section>\n )}\n\n {/* Request Body */}\n {endpoint.requestBody && (\n <section>\n <SectionHeading icon={<UploadIcon size={iconSize.small} className=\"text-text-secondary dark:text-text-secondary-dark\" />} title=\"Request Body\"/>\n {Object.entries(endpoint.requestBody.content ?? {}).map(([contentType, media]) => (\n <div key={contentType}>\n <Chip size=\"smallest\" colorScheme=\"blueDarker\" className=\"mb-3\">\n {contentType}\n </Chip>\n {media.schema && <SchemaBlock schema={media.schema} spec={spec} depth={0}/>}\n </div>\n ))}\n </section>\n )}\n\n {/* Responses */}\n <section>\n <SectionHeading icon={<ArrowRightFromLineIcon size={iconSize.small} className=\"text-text-secondary dark:text-text-secondary-dark\" />} title=\"Responses\"/>\n <div className=\"space-y-3\">\n {Object.entries(endpoint.responses).map(([code, res]) => (\n <div\n key={code}\n className={cls(\"rounded-lg border overflow-hidden\", defaultBorderMixin)}\n >\n <div\n className={cls(\n \"flex items-center gap-3 px-4 py-2.5\",\n \"bg-surface-50 dark:bg-surface-900/50\"\n )}\n >\n <StatusBadge code={code}/>\n <Typography\n variant=\"body2\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs\"\n >\n {res.description}\n </Typography>\n </div>\n {res.content &&\n Object.entries(res.content).map(\n ([ct, media]) =>\n media.schema && (\n <div\n key={ct}\n className={cls(\"px-4 py-3 border-t\", defaultBorderMixin)}\n >\n <SchemaBlock schema={media.schema} spec={spec} depth={0}/>\n </div>\n )\n )}\n </div>\n ))}\n </div>\n </section>\n </div>\n );\n}\n\n/* ── Schema Block ─────────────────────────────────────────────────── */\n\nfunction SchemaBlock({ schema, spec, depth }: { schema: OpenApiSchema; spec: OpenApiSpec; depth: number }) {\n // Resolve $ref\n if (schema.$ref) {\n const name = resolveRefName(schema.$ref);\n const resolved = resolveRef(spec, schema.$ref) as OpenApiSchema;\n return (\n <div>\n <Typography\n variant=\"caption\"\n className=\"text-primary dark:text-primary-dark font-mono text-xs mb-2 block\"\n >\n {name}\n </Typography>\n <SchemaBlock schema={resolved} spec={spec} depth={depth}/>\n </div>\n );\n }\n\n // Object with properties\n if (schema.properties) {\n const required = new Set(schema.required ?? []);\n return (\n <div\n className={cls(\n \"rounded-lg overflow-hidden\",\n depth > 0 && `border ml-4 mt-1 ${defaultBorderMixin}`\n )}\n >\n <table className=\"w-full text-xs\">\n <tbody>\n {Object.entries(schema.properties).map(([key, prop]) => (\n <tr\n key={key}\n className={cls(\"border-t first:border-t-0\", defaultBorderMixin)}\n >\n <td className=\"px-3 py-2 align-top w-36\">\n <code className=\"font-mono font-semibold text-text-primary dark:text-text-primary-dark\">\n {key}\n </code>\n {required.has(key) && <span className=\"text-red-500 ml-0.5\">*</span>}\n {prop.readOnly && (\n <span className=\"ml-1.5 text-[9px] text-text-secondary dark:text-text-secondary-dark italic\">\n read-only\n </span>\n )}\n </td>\n <td className=\"px-3 py-2 align-top w-28\">\n <span className=\"font-mono text-text-secondary dark:text-text-secondary-dark\">\n {schemaTypeLabel(prop)}\n </span>\n </td>\n <td className=\"px-3 py-2 align-top text-text-secondary dark:text-text-secondary-dark\">\n {prop.description ?? \"\"}\n {prop.enum && (\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {prop.enum.map((v) => (\n <span\n key={String(v)}\n className=\"px-1.5 py-0.5 rounded bg-surface-200 dark:bg-surface-800 text-[10px] font-mono\"\n >\n {String(v)}\n </span>\n ))}\n </div>\n )}\n {prop.properties && <SchemaBlock schema={prop} spec={spec} depth={depth + 1}/>}\n {prop.$ref && <SchemaBlock schema={prop} spec={spec} depth={depth + 1}/>}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n }\n\n // Array\n if (schema.type === \"array\" && schema.items) {\n return (\n <div>\n <span className=\"font-mono text-xs text-text-secondary dark:text-text-secondary-dark\">Array of:</span>\n <SchemaBlock schema={schema.items} spec={spec} depth={depth + 1}/>\n </div>\n );\n }\n\n // Primitive\n return (\n <span className=\"font-mono text-xs text-text-secondary dark:text-text-secondary-dark\">\n {schemaTypeLabel(schema)}\n </span>\n );\n}\n\n/* ── Helpers ──────────────────────────────────────────────────────── */\n\nfunction schemaTypeLabel(schema?: OpenApiSchema): string {\n if (!schema) return \"any\";\n if (schema.$ref) return resolveRefName(schema.$ref);\n if (schema.type === \"array\") return `${schemaTypeLabel(schema.items)}[]`;\n if (schema.format) return `${schema.type} (${schema.format})`;\n return schema.type ?? \"object\";\n}\n\nfunction SectionHeading({ icon, title }: { icon: React.ReactNode; title: string }) {\n return (\n <div className=\"flex items-center gap-2 mb-3\">\n {icon}\n <Typography variant=\"subtitle2\" className=\"font-semibold text-sm\">\n {title}\n </Typography>\n </div>\n );\n}\n\nfunction StatusBadge({ code }: { code: string }) {\n const n = parseInt(code, 10);\n const color =\n n < 300\n ? \"text-emerald-600 dark:text-emerald-400\"\n : n < 400\n ? \"text-blue-600 dark:text-blue-400\"\n : n < 500\n ? \"text-amber-600 dark:text-amber-400\"\n : \"text-red-600 dark:text-red-400\";\n\n return <span className={cls(\"text-xs font-bold font-mono\", color)}>{code}</span>;\n}\n","import React, { useState, useCallback, useMemo, useEffect } from \"react\";\nimport {\n Button,\n cls,\n defaultBorderMixin,\n IconButton,\n iconSize,\n LoaderIcon,\n PlusIcon,\n SendIcon,\n TextField,\n Typography,\n XIcon\n} from \"@rebasepro/ui\";\nimport { useRebaseContext, UserSelectPopover, SelectableUser } from \"@rebasepro/app\";\nimport { AuthSimulationSelector } from \"../AuthSimulationSelector\";\nimport type { ParsedEndpoint } from \"./types\";\nimport type { User } from \"@rebasepro/types\";\n\ninterface TryItPanelProps {\n endpoint: ParsedEndpoint;\n apiUrl: string;\n getAuthToken: () => Promise<string | null | undefined>;\n user: User | null;\n basePath?: string;\n}\n\n/**\n * Interactive \"Try It\" panel that lets the user execute API requests\n * using their current JWT token directly from the Studio.\n */\nexport function TryItPanel({ endpoint, apiUrl, getAuthToken, user, basePath = \"\" }: TryItPanelProps) {\n const storageKey = `rebase_apiexplorer_${endpoint.method}_${endpoint.path}`;\n\n const [pathParams, setPathParams] = useState<Record<string, string>>(() => {\n try { const v = localStorage.getItem(`${storageKey}_path`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return {};\n });\n const [queryParams, setQueryParams] = useState<Record<string, string>>(() => {\n try { const v = localStorage.getItem(`${storageKey}_query`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return {};\n });\n const [customHeaders, setCustomHeaders] = useState<Array<{ key: string; value: string }>>(() => {\n try { const v = localStorage.getItem(`${storageKey}_headers`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return [{ key: \"rebase-branch\",\nvalue: \"\" }];\n });\n const [body, setBody] = useState(() => {\n try { const v = localStorage.getItem(`${storageKey}_body`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return buildBodyTemplate(endpoint);\n });\n const [response, setResponse] = useState<{ status: number; statusText: string; body: string; time: number } | null>(\n null\n );\n const [loading, setLoading] = useState(false);\n const [authMode, setAuthMode] = useState<\"jwt\" | \"none\">(\"jwt\");\n const [validationError, setValidationError] = useState<string | null>(null);\n\n const rebaseContext = useRebaseContext();\n const currentUser = rebaseContext.authController?.user;\n\n const users = useMemo((): SelectableUser[] => {\n const managed: SelectableUser[] = [];\n if (currentUser) {\n managed.push({\n uid: currentUser.uid,\n displayName: currentUser.displayName,\n email: currentUser.email,\n photoURL: currentUser.photoURL,\n roles: currentUser.roles\n });\n }\n return managed;\n }, [currentUser]);\n\n const currentSelectableUser = useMemo((): SelectableUser | null => {\n if (!currentUser) return null;\n return {\n uid: currentUser.uid,\n displayName: currentUser.displayName,\n email: currentUser.email,\n photoURL: currentUser.photoURL,\n roles: currentUser.roles\n };\n }, [currentUser]);\n\n const [selectedUser, setSelectedUser] = useState<SelectableUser | null>(null);\n\n useEffect(() => {\n localStorage.setItem(`${storageKey}_path`, JSON.stringify(pathParams));\n localStorage.setItem(`${storageKey}_query`, JSON.stringify(queryParams));\n localStorage.setItem(`${storageKey}_headers`, JSON.stringify(customHeaders));\n localStorage.setItem(`${storageKey}_body`, JSON.stringify(body));\n }, [storageKey, pathParams, queryParams, customHeaders, body]);\n\n // Build the final URL\n const resolvedUrl = useMemo(() => {\n const base = basePath.startsWith(\"/\") ? basePath : `/${basePath}`;\n const cleanBase = base === \"/\" ? \"\" : base;\n let url = `${apiUrl.replace(/\\/+$/, \"\")}${cleanBase}${endpoint.path}`;\n // Replace path params\n for (const [key, val] of Object.entries(pathParams)) {\n url = url.replace(`{${key}}`, encodeURIComponent(val));\n }\n // Append query params\n const qp = Object.entries(queryParams).filter(([, v]) => v.trim() !== \"\");\n if (qp.length > 0) {\n url += \"?\" + qp.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join(\"&\");\n }\n return url;\n }, [apiUrl, basePath, endpoint.path, pathParams, queryParams]);\n\n const pathParamDefs = endpoint.parameters.filter((p) => p.in === \"path\");\n const queryParamDefs = endpoint.parameters.filter((p) => p.in === \"query\");\n const hasBody = [\"post\", \"put\", \"patch\"].includes(endpoint.method);\n\n const execute = useCallback(async () => {\n setValidationError(null);\n if (hasBody && body.trim()) {\n try {\n JSON.parse(body);\n } catch (err: unknown) {\n setValidationError(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);\n return;\n }\n }\n\n setLoading(true);\n setResponse(null);\n const start = performance.now();\n\n try {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n\n for (const h of customHeaders) {\n if (h.key.trim()) headers[h.key.trim()] = h.value;\n }\n\n if (authMode === \"jwt\") {\n const token = await getAuthToken();\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n if (selectedUser && selectedUser.uid !== currentUser?.uid) {\n headers[\"x-rebase-impersonate\"] = selectedUser.uid;\n }\n }\n\n const res = await fetch(resolvedUrl, {\n method: endpoint.method.toUpperCase(),\n headers,\n body: hasBody && body.trim() ? body : undefined\n });\n\n const elapsed = Math.round(performance.now() - start);\n let text: string;\n\n const rawText = await res.text();\n try {\n const json = JSON.parse(rawText);\n text = JSON.stringify(json, null, 2);\n } catch {\n text = rawText;\n }\n\n setResponse({ status: res.status,\nstatusText: res.statusText,\nbody: text,\ntime: elapsed });\n } catch (err: unknown) {\n setResponse({\n status: 0,\n statusText: \"Network Error\",\n body: err instanceof Error ? err.message : \"Request failed\",\n time: Math.round(performance.now() - start)\n });\n } finally {\n setLoading(false);\n }\n }, [resolvedUrl, endpoint.method, hasBody, body, authMode, getAuthToken, customHeaders, selectedUser, currentUser?.uid]);\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"p-5 space-y-5 overflow-y-auto flex-1\">\n {/* Auth Mode */}\n <AuthSimulationSelector\n authMode={authMode}\n setAuthMode={setAuthMode}\n selectedUser={selectedUser}\n setSelectedUser={setSelectedUser}\n users={users}\n loading={false}\n currentUser={currentSelectableUser}\n />\n\n {/* Path Params */}\n {pathParamDefs.length > 0 && (\n <ParamSection\n title=\"Path Parameters\"\n params={pathParamDefs}\n values={pathParams}\n onChange={(k, v) => setPathParams((prev) => ({ ...prev,\n[k]: v }))}\n />\n )}\n\n {/* Query Params */}\n {queryParamDefs.length > 0 && (\n <ParamSection\n title=\"Query Parameters\"\n params={queryParamDefs}\n values={queryParams}\n onChange={(k, v) => setQueryParams((prev) => ({ ...prev,\n[k]: v }))}\n />\n )}\n\n {/* Custom Headers */}\n <CustomKeyValueSection\n title=\"Custom Headers\"\n values={customHeaders}\n onChange={(i, k, v) => {\n const next = [...customHeaders];\n next[i] = { key: k,\nvalue: v };\n setCustomHeaders(next);\n }}\n onAdd={() => setCustomHeaders((prev) => [...prev, { key: \"\",\nvalue: \"\" }])}\n onRemove={(i) => {\n const next = [...customHeaders];\n next.splice(i, 1);\n setCustomHeaders(next);\n }}\n />\n\n {/* Request Body */}\n {hasBody && (\n <div>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider mb-2 block\"\n >\n Request Body\n </Typography>\n <TextField\n multiline\n minRows={10}\n value={body}\n onChange={(e) => { setBody(e.target.value); setValidationError(null); }}\n spellCheck={false}\n error={!!validationError}\n className=\"w-full\"\n inputClassName=\"font-mono text-xs p-3 resize-y\"\n />\n {validationError && (\n <Typography variant=\"caption\" className=\"text-red-500 mt-1 block text-xs\">\n {validationError}\n </Typography>\n )}\n </div>\n )}\n\n {/* URL Preview */}\n <div className=\"rounded-lg bg-surface-100 dark:bg-surface-900 p-3\">\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-[10px] uppercase tracking-wider block mb-1\"\n >\n Request URL\n </Typography>\n <code className=\"text-xs font-mono text-text-primary dark:text-text-primary-dark break-all\">\n {resolvedUrl}\n </code>\n </div>\n\n {/* Execute Button */}\n <Button variant=\"filled\" onClick={execute} disabled={loading} className=\"w-full\">\n {loading ? (\n <span className=\"flex items-center gap-2\">\n <LoaderIcon size={iconSize.small} className=\"animate-spin\" />\n Sending…\n </span>\n ) : (\n <span className=\"flex items-center gap-2\">\n <SendIcon size={iconSize.small} />\n Send Request\n </span>\n )}\n </Button>\n\n {/* Response */}\n {response && (\n <div className={cls(\"rounded-lg border overflow-hidden\", defaultBorderMixin)}>\n <div\n className={cls(\n \"flex items-center justify-between px-4 py-2.5\",\n \"bg-surface-50 dark:bg-surface-900/50\"\n )}\n >\n <div className=\"flex items-center gap-3\">\n <ResponseBadge status={response.status}/>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs\"\n >\n {response.statusText}\n </Typography>\n </div>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-mono\"\n >\n {response.time}ms\n </Typography>\n </div>\n <pre\n className={cls(\n \"p-4 text-xs font-mono overflow-auto max-h-96\",\n \"bg-surface-950 text-emerald-400\",\n \"dark:bg-surface-900 dark:text-emerald-400\"\n )}\n >\n {response.body}\n </pre>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/* ── Param Section ────────────────────────────────────────────────── */\n\nfunction ParamSection({\n title,\n params,\n values,\n onChange\n}: {\n title: string;\n params: ParsedEndpoint[\"parameters\"];\n values: Record<string, string>;\n onChange: (_key: string, _value: string) => void;\n}) {\n return (\n <div>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider mb-2 block\"\n >\n {title}\n </Typography>\n <div className=\"space-y-2\">\n {params.map((p) => (\n <div key={p.name} className=\"flex items-center gap-3\">\n <label className=\"w-32 shrink-0\">\n <code className=\"text-xs font-mono font-semibold\">{p.name}</code>\n {p.required && <span className=\"text-red-500 ml-0.5 text-xs\">*</span>}\n </label>\n <TextField\n size=\"small\"\n placeholder={p.description ?? p.name}\n value={values[p.name] ?? \"\"}\n onChange={(e) => onChange(p.name, e.target.value)}\n className=\"flex-1\"\n inputClassName=\"font-mono text-xs\"\n />\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nfunction CustomKeyValueSection({\n title,\n values,\n onChange,\n onAdd,\n onRemove\n}: {\n title: string;\n values: Array<{ key: string; value: string }>;\n onChange: (index: number, key: string, value: string) => void;\n onAdd: () => void;\n onRemove: (index: number) => void;\n}) {\n return (\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider block\"\n >\n {title}\n </Typography>\n <Button\n variant=\"text\"\n size=\"small\"\n color=\"primary\"\n onClick={onAdd}\n className=\"text-xs p-0 min-h-0\"\n >\n <PlusIcon size={iconSize.small} className=\"mr-1\" /> Add Header\n </Button>\n </div>\n <div className=\"space-y-2\">\n {values.map((v, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <TextField\n size=\"small\"\n placeholder=\"Header name\"\n value={v.key}\n onChange={(e) => onChange(i, e.target.value, v.value)}\n className=\"w-1/3\"\n inputClassName=\"font-mono text-xs\"\n />\n <TextField\n size=\"small\"\n placeholder=\"Value\"\n value={v.value}\n onChange={(e) => onChange(i, v.key, e.target.value)}\n className=\"flex-1\"\n inputClassName=\"font-mono text-xs\"\n />\n <IconButton\n size=\"small\"\n onClick={() => onRemove(i)}\n className=\"text-text-secondary hover:text-red-500 shrink-0\"\n title=\"Remove\"\n >\n <XIcon size={iconSize.small} />\n </IconButton>\n </div>\n ))}\n {values.length === 0 && (\n <Typography variant=\"caption\" className=\"text-text-secondary/50 italic text-xs\">\n No custom headers added.\n </Typography>\n )}\n </div>\n </div>\n );\n}\n\n/* ── Helpers ──────────────────────────────────────────────────────── */\n\nfunction ResponseBadge({ status }: { status: number }) {\n let colorClass = \"text-red-500\";\n if (status >= 200 && status < 300) colorClass = \"text-emerald-500\";\n else if (status >= 300 && status < 400) colorClass = \"text-blue-500\";\n else if (status >= 400 && status < 500) colorClass = \"text-amber-500\";\n\n return (\n <span className={cls(\"text-xs font-bold font-mono\", colorClass)}>\n {status || \"ERR\"}\n </span>\n );\n}\n\nfunction buildBodyTemplate(endpoint: ParsedEndpoint): string {\n if (!endpoint.requestBody?.content) return \"{\\n \\n}\";\n const json = endpoint.requestBody.content[\"application/json\"];\n if (!json?.schema?.properties) return \"{\\n \\n}\";\n\n const props = json.schema.properties;\n const lines: string[] = [\"{\"];\n const keys = Object.keys(props);\n keys.forEach((key, i) => {\n const prop = props[key];\n if (prop.readOnly) return;\n const comma = i < keys.length - 1 ? \",\" : \"\";\n const val = defaultValue(prop);\n lines.push(` \"${key}\": ${val}${comma}`);\n });\n lines.push(\"}\");\n return lines.join(\"\\n\");\n}\n\nfunction defaultValue(schema: { type?: string; format?: string; enum?: (string | number)[] }): string {\n if (schema.enum) return JSON.stringify(schema.enum[0]);\n switch (schema.type) {\n case \"string\":\n return schema.format === \"date-time\" ? `\"${new Date().toISOString()}\"` : '\"\"';\n case \"number\":\n case \"integer\":\n return \"0\";\n case \"boolean\":\n return \"false\";\n case \"array\":\n return \"[]\";\n default:\n return \"null\";\n }\n}\n","import React, { useState, useEffect, useMemo } from \"react\";\nimport { useApiConfig, useAuthController } from \"@rebasepro/app\";\nimport {\n CircularProgress,\n Typography,\n Alert,\n cls,\n Button,\n Chip,\n defaultBorderMixin,\n SearchBar,\n iconSize\n} from \"@rebasepro/ui\";\nimport { BookOpenIcon, PlayIcon } from \"@rebasepro/ui\";\nimport { EndpointDetail } from \"./EndpointDetail\";\nimport { TryItPanel } from \"./TryItPanel\";\nimport type { OpenApiSpec, ParsedEndpoint } from \"./types\";\nimport { parseOpenApiSpec } from \"./parseSpec\";\n\n/**\n * Custom-built API Explorer for Rebase Studio.\n * No external dependencies — renders the OpenAPI spec natively\n * with deep integration into the Rebase auth system.\n */\nexport function ApiExplorer() {\n const apiConfig = useApiConfig();\n const authController = useAuthController();\n const apiUrl = apiConfig?.apiUrl;\n\n const [spec, setSpec] = useState<OpenApiSpec | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const [selectedEndpoint, setSelectedEndpoint] = useState<ParsedEndpoint | null>(null);\n const [sidebarFilter, setSidebarFilter] = useState(\"\");\n const [tryItOpen, setTryItOpen] = useState(false);\n\n // Fetch OpenAPI spec\n useEffect(() => {\n if (!apiUrl) return;\n let cancelled = false;\n const specUrl = `${apiUrl.replace(/\\/+$/, \"\")}/api/docs`;\n\n (async () => {\n try {\n const res = await fetch(specUrl);\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\n const data = await res.json();\n if (!cancelled) {\n setSpec(data);\n setLoading(false);\n }\n } catch (err: unknown) {\n if (!cancelled) {\n setError(err instanceof Error ? err.message : \"Failed to load API spec\");\n setLoading(false);\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [apiUrl]);\n\n // Parse spec into grouped endpoints\n const { groups, allEndpoints } = useMemo(() => {\n if (!spec) return { groups: [],\nallEndpoints: [] };\n return parseOpenApiSpec(spec);\n }, [spec]);\n\n // Filter\n const filteredGroups = useMemo(() => {\n if (!sidebarFilter.trim()) return groups;\n const q = sidebarFilter.toLowerCase();\n return groups\n .map((g) => ({\n ...g,\n endpoints: g.endpoints.filter(\n (e) =>\n e.path.toLowerCase().includes(q) ||\n e.summary.toLowerCase().includes(q) ||\n e.method.toLowerCase().includes(q)\n )\n }))\n .filter((g) => g.endpoints.length > 0);\n }, [groups, sidebarFilter]);\n\n // Auto-select first endpoint\n useEffect(() => {\n if (!selectedEndpoint && allEndpoints.length > 0) {\n setSelectedEndpoint(allEndpoints[0]);\n }\n }, [allEndpoints, selectedEndpoint]);\n\n // ── States ───────────────────────────────────────────────────────\n if (!apiUrl) {\n return (\n <div className=\"flex items-center justify-center h-full w-full p-8\">\n <Alert color=\"warning\">\n <Typography variant=\"body2\">\n No API URL configured. Ensure your app provides an{\" \"}\n <code className=\"font-mono text-xs\">apiUrl</code>.\n </Typography>\n </Alert>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full w-full gap-4\">\n <CircularProgress size=\"medium\"/>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark animate-pulse\">\n Loading API specification…\n </Typography>\n </div>\n );\n }\n\n if (error || !spec) {\n return (\n <div className=\"flex items-center justify-center h-full w-full p-8\">\n <Alert color=\"error\">\n <Typography variant=\"body2\">{error ?? \"Unknown error\"}</Typography>\n </Alert>\n </div>\n );\n }\n\n const METHOD_COLORS: Record<string, string> = {\n get: \"text-blue-600 dark:text-blue-400\",\n post: \"text-emerald-600 dark:text-emerald-400\",\n put: \"text-amber-600 dark:text-amber-400\",\n patch: \"text-orange-600 dark:text-orange-400\",\n delete: \"text-red-600 dark:text-red-400\"\n };\n\n return (\n <div className=\"flex h-full w-full overflow-hidden\">\n {/* ── Sidebar ──────────────────────────────────────── */}\n <div\n className={cls(\n \"w-72 min-w-[272px] flex flex-col h-full overflow-hidden border-r\",\n defaultBorderMixin,\n \"bg-surface-50 dark:bg-surface-900\"\n )}\n >\n {/* Header */}\n <div className=\"p-4 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <BookOpenIcon size={iconSize.medium} className=\"text-primary dark:text-primary-dark\" />\n <Typography variant=\"subtitle2\" className=\"font-semibold\">\n {spec.info?.title ?? \"API Reference\"}\n </Typography>\n </div>\n {spec.info?.version && (\n <Chip size=\"smallest\" colorScheme=\"cyanDarker\">\n v{spec.info.version}\n </Chip>\n )}\n {/* Search */}\n <div className=\"mb-2\">\n <SearchBar\n placeholder=\"Filter endpoints…\"\n size=\"small\"\n onTextSearch={(val) => setSidebarFilter(val ?? \"\")}\n />\n </div>\n\n {/* Auth status removed to avoid redundancy with the AuthSimulationSelector */}\n </div>\n\n {/* Endpoint list */}\n <div className=\"flex-1 overflow-y-auto px-2 pb-4\">\n {filteredGroups.map((group) => (\n <div key={group.tag} className=\"mb-3\">\n <Typography\n variant=\"caption\"\n className=\"px-2 py-1.5 text-text-secondary dark:text-text-secondary-dark uppercase tracking-wider font-semibold text-[10px]\"\n >\n {group.tag}\n </Typography>\n {group.endpoints.map((ep) => {\n const isSelected = selectedEndpoint?.id === ep.id;\n return (\n <Button\n key={ep.id}\n variant=\"text\"\n color=\"neutral\"\n fullWidth\n onClick={() => {\n setSelectedEndpoint(ep);\n setTryItOpen(false);\n }}\n className={cls(\n \"!justify-between !px-2.5 !py-1.5 !text-left !text-sm\",\n isSelected\n ? \"bg-surface-200 dark:bg-surface-800 font-medium\"\n : \"text-text-primary dark:text-text-primary-dark\"\n )}\n >\n <span className=\"truncate text-[13px] opacity-90\">{ep.summary || ep.shortPath}</span>\n <span\n className={cls(\n \"text-[10px] font-bold uppercase shrink-0\",\n METHOD_COLORS[ep.method] ?? \"text-text-secondary\"\n )}\n >\n {ep.method}\n </span>\n </Button>\n );\n })}\n </div>\n ))}\n {filteredGroups.length === 0 && (\n <Typography\n variant=\"body2\"\n className=\"text-center text-text-secondary dark:text-text-secondary-dark py-8\"\n >\n No endpoints match\n </Typography>\n )}\n </div>\n </div>\n\n {/* ── Main content ─────────────────────────────────── */}\n <div className=\"flex-1 flex flex-col h-full overflow-hidden\">\n {selectedEndpoint ? (\n <>\n {/* Top bar */}\n <div\n className={cls(\n \"flex items-center justify-between px-5 py-3 gap-4 shrink-0 border-b z-10\",\n defaultBorderMixin,\n \"bg-surface-50/80 dark:bg-surface-950/80 backdrop-blur-md sticky top-0\"\n )}\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <span\n className={cls(\n \"text-xs font-bold uppercase\",\n METHOD_COLORS[selectedEndpoint.method] ?? \"\"\n )}\n >\n {selectedEndpoint.method}\n </span>\n <code className=\"text-sm font-mono text-text-primary dark:text-text-primary-dark truncate\">\n {selectedEndpoint.path}\n </code>\n </div>\n <Button\n variant={tryItOpen ? \"filled\" : \"outlined\"}\n size=\"small\"\n onClick={() => setTryItOpen((v) => !v)}\n >\n <PlayIcon size={iconSize.small} className=\"mr-1\" />\n Try It\n </Button>\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto\">\n {tryItOpen ? (\n <TryItPanel\n key={selectedEndpoint.operationId || selectedEndpoint.path}\n endpoint={selectedEndpoint}\n apiUrl={apiUrl}\n getAuthToken={apiConfig?.getAuthToken ?? authController.getAuthToken}\n user={authController.user}\n basePath={spec?.servers?.[0]?.url || \"\"}\n />\n ) : (\n <EndpointDetail endpoint={selectedEndpoint} spec={spec}/>\n )}\n </div>\n </>\n ) : (\n <div className=\"flex items-center justify-center h-full\">\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n Select an endpoint from the sidebar\n </Typography>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nApiExplorer.displayName = \"ApiExplorer\";\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"ApiExplorer-VRKWqCVI.js","names":[],"sources":["../src/components/ApiExplorer/parseSpec.ts","../src/components/ApiExplorer/EndpointDetail.tsx","../src/components/ApiExplorer/TryItPanel.tsx","../src/components/ApiExplorer/ApiExplorer.tsx"],"sourcesContent":["import type { OpenApiSpec, ParsedEndpoint, EndpointGroup } from \"./types\";\n\n/**\n * Parse an OpenAPI 3.x spec into grouped, sorted endpoints for the sidebar.\n */\nexport function parseOpenApiSpec(spec: OpenApiSpec): {\n groups: EndpointGroup[];\n allEndpoints: ParsedEndpoint[];\n} {\n const allEndpoints: ParsedEndpoint[] = [];\n const tagMap = new Map<string, ParsedEndpoint[]>();\n\n // Build tag description lookup\n const tagDescriptions = new Map<string, string>();\n for (const t of spec.tags ?? []) {\n tagDescriptions.set(t.name, t.description ?? \"\");\n }\n\n for (const [path, methods] of Object.entries(spec.paths ?? {})) {\n for (const [method, op] of Object.entries(methods)) {\n if ([\"get\", \"post\", \"put\", \"patch\", \"delete\"].indexOf(method) === -1) continue;\n\n const tags = op.tags?.length ? op.tags : [\"Other\"];\n const shortPath = path.replace(/^\\/api\\/data/, \"\");\n\n const endpoint: ParsedEndpoint = {\n id: `${method}:${path}`,\n method,\n path,\n shortPath: shortPath || \"/\",\n summary: op.summary ?? \"\",\n description: op.description ?? \"\",\n tags,\n parameters: op.parameters ?? [],\n requestBody: op.requestBody,\n responses: op.responses ?? {},\n security: op.security,\n operationId: op.operationId\n };\n\n allEndpoints.push(endpoint);\n for (const tag of tags) {\n if (!tagMap.has(tag)) tagMap.set(tag, []);\n tagMap.get(tag)!.push(endpoint);\n }\n }\n }\n\n // Method sort order\n const ORDER: Record<string, number> = { get: 0,\npost: 1,\nput: 2,\npatch: 3,\ndelete: 4 };\n\n const groups: EndpointGroup[] = [];\n // Sort tags: use spec.tags order if available, else alphabetical\n const tagOrder = (spec.tags ?? []).map((t) => t.name);\n const sortedTags = [...tagMap.keys()].sort((a, b) => {\n const ai = tagOrder.indexOf(a);\n const bi = tagOrder.indexOf(b);\n if (ai !== -1 && bi !== -1) return ai - bi;\n if (ai !== -1) return -1;\n if (bi !== -1) return 1;\n return a.localeCompare(b);\n });\n\n for (const tag of sortedTags) {\n const endpoints = tagMap.get(tag)!;\n endpoints.sort((a, b) => {\n const pa = a.path.localeCompare(b.path);\n if (pa !== 0) return pa;\n return (ORDER[a.method] ?? 99) - (ORDER[b.method] ?? 99);\n });\n groups.push({\n tag,\n description: tagDescriptions.get(tag),\n endpoints\n });\n }\n\n return { groups,\nallEndpoints };\n}\n\n/**\n * Resolve a $ref string (e.g. \"#/components/schemas/Author\") to a schema name.\n */\nexport function resolveRefName(ref: string): string {\n const parts = ref.split(\"/\");\n return parts[parts.length - 1];\n}\n\n/**\n * Resolve a $ref to its actual schema from the spec.\n */\nexport function resolveRef(spec: OpenApiSpec, ref: string): unknown {\n const parts = ref.replace(\"#/\", \"\").split(\"/\");\n let current: unknown = spec;\n for (const part of parts) {\n current = (current as Record<string, unknown>)?.[part];\n }\n return current ?? {};\n}\n","import React from \"react\";\nimport {\n ArrowRightFromLineIcon,\n Chip,\n cls,\n defaultBorderMixin,\n iconSize,\n SlidersHorizontalIcon,\n Typography,\n UploadIcon\n} from \"@rebasepro/ui\";\nimport type { ParsedEndpoint, OpenApiSpec, OpenApiSchema } from \"./types\";\nimport { resolveRef, resolveRefName } from \"./parseSpec\";\n\n/**\n * Renders the documentation view for a single API endpoint:\n * parameters, request body schema, response schemas.\n */\nexport function EndpointDetail({ endpoint, spec }: { endpoint: ParsedEndpoint; spec: OpenApiSpec }) {\n return (\n <div className=\"p-6 space-y-8 max-w-4xl\">\n {/* Summary / Description */}\n {(endpoint.summary || endpoint.description) && (\n <div>\n {endpoint.summary && (\n <Typography variant=\"h6\" className=\"font-semibold mb-1\">\n {endpoint.summary}\n </Typography>\n )}\n {endpoint.description && (\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {endpoint.description}\n </Typography>\n )}\n </div>\n )}\n\n {/* Parameters */}\n {endpoint.parameters.length > 0 && (\n <section>\n <SectionHeading icon={<SlidersHorizontalIcon size={iconSize.small} className=\"text-text-secondary dark:text-text-secondary-dark\" />} title=\"Parameters\"/>\n <div className={cls(\"rounded-lg border overflow-hidden\", defaultBorderMixin)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-surface-100 dark:bg-surface-900 text-left\">\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n Name\n </th>\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n In\n </th>\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n Type\n </th>\n <th className=\"px-4 py-2 font-medium text-text-secondary dark:text-text-secondary-dark\">\n Description\n </th>\n </tr>\n </thead>\n <tbody>\n {endpoint.parameters.map((p, i) => (\n <tr\n key={p.name + i}\n className={cls(\"border-t\", defaultBorderMixin)}\n >\n <td className=\"px-4 py-2.5\">\n <code className=\"text-xs font-mono font-semibold\">{p.name}</code>\n {p.required && <span className=\"text-red-500 ml-1 text-xs\">*</span>}\n </td>\n <td className=\"px-4 py-2.5\">\n <Chip\n size=\"smallest\"\n colorScheme={p.in === \"path\" ? \"orangeDarker\" : \"cyanDarker\"}\n >\n {p.in}\n </Chip>\n </td>\n <td className=\"px-4 py-2.5 text-xs font-mono text-text-secondary dark:text-text-secondary-dark\">\n {schemaTypeLabel(p.schema)}\n </td>\n <td className=\"px-4 py-2.5 text-xs text-text-secondary dark:text-text-secondary-dark\">\n {p.description ?? \"—\"}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </section>\n )}\n\n {/* Request Body */}\n {endpoint.requestBody && (\n <section>\n <SectionHeading icon={<UploadIcon size={iconSize.small} className=\"text-text-secondary dark:text-text-secondary-dark\" />} title=\"Request Body\"/>\n {Object.entries(endpoint.requestBody.content ?? {}).map(([contentType, media]) => (\n <div key={contentType}>\n <Chip size=\"smallest\" colorScheme=\"blueDarker\" className=\"mb-3\">\n {contentType}\n </Chip>\n {media.schema && <SchemaBlock schema={media.schema} spec={spec} depth={0}/>}\n </div>\n ))}\n </section>\n )}\n\n {/* Responses */}\n <section>\n <SectionHeading icon={<ArrowRightFromLineIcon size={iconSize.small} className=\"text-text-secondary dark:text-text-secondary-dark\" />} title=\"Responses\"/>\n <div className=\"space-y-3\">\n {Object.entries(endpoint.responses).map(([code, res]) => (\n <div\n key={code}\n className={cls(\"rounded-lg border overflow-hidden\", defaultBorderMixin)}\n >\n <div\n className={cls(\n \"flex items-center gap-3 px-4 py-2.5\",\n \"bg-surface-50 dark:bg-surface-900/50\"\n )}\n >\n <StatusBadge code={code}/>\n <Typography\n variant=\"body2\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs\"\n >\n {res.description}\n </Typography>\n </div>\n {res.content &&\n Object.entries(res.content).map(\n ([ct, media]) =>\n media.schema && (\n <div\n key={ct}\n className={cls(\"px-4 py-3 border-t\", defaultBorderMixin)}\n >\n <SchemaBlock schema={media.schema} spec={spec} depth={0}/>\n </div>\n )\n )}\n </div>\n ))}\n </div>\n </section>\n </div>\n );\n}\n\n/* ── Schema Block ─────────────────────────────────────────────────── */\n\nfunction SchemaBlock({ schema, spec, depth }: { schema: OpenApiSchema; spec: OpenApiSpec; depth: number }) {\n // Resolve $ref\n if (schema.$ref) {\n const name = resolveRefName(schema.$ref);\n const resolved = resolveRef(spec, schema.$ref) as OpenApiSchema;\n return (\n <div>\n <Typography\n variant=\"caption\"\n className=\"text-primary dark:text-primary-dark font-mono text-xs mb-2 block\"\n >\n {name}\n </Typography>\n <SchemaBlock schema={resolved} spec={spec} depth={depth}/>\n </div>\n );\n }\n\n // Object with properties\n if (schema.properties) {\n const required = new Set(schema.required ?? []);\n return (\n <div\n className={cls(\n \"rounded-lg overflow-hidden\",\n depth > 0 && `border ml-4 mt-1 ${defaultBorderMixin}`\n )}\n >\n <table className=\"w-full text-xs\">\n <tbody>\n {Object.entries(schema.properties).map(([key, prop]) => (\n <tr\n key={key}\n className={cls(\"border-t first:border-t-0\", defaultBorderMixin)}\n >\n <td className=\"px-3 py-2 align-top w-36\">\n <code className=\"font-mono font-semibold text-text-primary dark:text-text-primary-dark\">\n {key}\n </code>\n {required.has(key) && <span className=\"text-red-500 ml-0.5\">*</span>}\n {prop.readOnly && (\n <span className=\"ml-1.5 text-[9px] text-text-secondary dark:text-text-secondary-dark italic\">\n read-only\n </span>\n )}\n </td>\n <td className=\"px-3 py-2 align-top w-28\">\n <span className=\"font-mono text-text-secondary dark:text-text-secondary-dark\">\n {schemaTypeLabel(prop)}\n </span>\n </td>\n <td className=\"px-3 py-2 align-top text-text-secondary dark:text-text-secondary-dark\">\n {prop.description ?? \"\"}\n {prop.enum && (\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {prop.enum.map((v) => (\n <span\n key={String(v)}\n className=\"px-1.5 py-0.5 rounded bg-surface-200 dark:bg-surface-800 text-[10px] font-mono\"\n >\n {String(v)}\n </span>\n ))}\n </div>\n )}\n {prop.properties && <SchemaBlock schema={prop} spec={spec} depth={depth + 1}/>}\n {prop.$ref && <SchemaBlock schema={prop} spec={spec} depth={depth + 1}/>}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n }\n\n // Array\n if (schema.type === \"array\" && schema.items) {\n return (\n <div>\n <span className=\"font-mono text-xs text-text-secondary dark:text-text-secondary-dark\">Array of:</span>\n <SchemaBlock schema={schema.items} spec={spec} depth={depth + 1}/>\n </div>\n );\n }\n\n // Primitive\n return (\n <span className=\"font-mono text-xs text-text-secondary dark:text-text-secondary-dark\">\n {schemaTypeLabel(schema)}\n </span>\n );\n}\n\n/* ── Helpers ──────────────────────────────────────────────────────── */\n\nfunction schemaTypeLabel(schema?: OpenApiSchema): string {\n if (!schema) return \"any\";\n if (schema.$ref) return resolveRefName(schema.$ref);\n if (schema.type === \"array\") return `${schemaTypeLabel(schema.items)}[]`;\n if (schema.format) return `${schema.type} (${schema.format})`;\n return schema.type ?? \"object\";\n}\n\nfunction SectionHeading({ icon, title }: { icon: React.ReactNode; title: string }) {\n return (\n <div className=\"flex items-center gap-2 mb-3\">\n {icon}\n <Typography variant=\"subtitle2\" className=\"font-semibold text-sm\">\n {title}\n </Typography>\n </div>\n );\n}\n\nfunction StatusBadge({ code }: { code: string }) {\n const n = parseInt(code, 10);\n const color =\n n < 300\n ? \"text-emerald-600 dark:text-emerald-400\"\n : n < 400\n ? \"text-blue-600 dark:text-blue-400\"\n : n < 500\n ? \"text-amber-600 dark:text-amber-400\"\n : \"text-red-600 dark:text-red-400\";\n\n return <span className={cls(\"text-xs font-bold font-mono\", color)}>{code}</span>;\n}\n","import React, { useState, useCallback, useMemo, useEffect } from \"react\";\nimport {\n Button,\n cls,\n defaultBorderMixin,\n IconButton,\n iconSize,\n LoaderIcon,\n PlusIcon,\n SendIcon,\n TextField,\n Typography,\n XIcon\n} from \"@rebasepro/ui\";\nimport { useRebaseContext, UserSelectPopover, SelectableUser } from \"@rebasepro/app\";\nimport { AuthSimulationSelector } from \"../AuthSimulationSelector\";\nimport type { ParsedEndpoint } from \"./types\";\nimport type { User } from \"@rebasepro/types\";\n\ninterface TryItPanelProps {\n endpoint: ParsedEndpoint;\n apiUrl: string;\n getAuthToken: () => Promise<string | null | undefined>;\n user: User | null;\n basePath?: string;\n}\n\n/**\n * Interactive \"Try It\" panel that lets the user execute API requests\n * using their current JWT token directly from the Studio.\n */\nexport function TryItPanel({ endpoint, apiUrl, getAuthToken, user, basePath = \"\" }: TryItPanelProps) {\n const storageKey = `rebase_apiexplorer_${endpoint.method}_${endpoint.path}`;\n\n const [pathParams, setPathParams] = useState<Record<string, string>>(() => {\n try { const v = localStorage.getItem(`${storageKey}_path`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return {};\n });\n const [queryParams, setQueryParams] = useState<Record<string, string>>(() => {\n try { const v = localStorage.getItem(`${storageKey}_query`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return {};\n });\n const [customHeaders, setCustomHeaders] = useState<Array<{ key: string; value: string }>>(() => {\n try { const v = localStorage.getItem(`${storageKey}_headers`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return [{ key: \"rebase-branch\",\nvalue: \"\" }];\n });\n const [body, setBody] = useState(() => {\n try { const v = localStorage.getItem(`${storageKey}_body`); if (v) return JSON.parse(v); } catch { /* ignore */ }\n return buildBodyTemplate(endpoint);\n });\n const [response, setResponse] = useState<{ status: number; statusText: string; body: string; time: number } | null>(\n null\n );\n const [loading, setLoading] = useState(false);\n const [authMode, setAuthMode] = useState<\"jwt\" | \"none\">(\"jwt\");\n const [validationError, setValidationError] = useState<string | null>(null);\n\n const rebaseContext = useRebaseContext();\n const currentUser = rebaseContext.authController?.user;\n\n const users = useMemo((): SelectableUser[] => {\n const managed: SelectableUser[] = [];\n if (currentUser) {\n managed.push({\n uid: currentUser.uid,\n displayName: currentUser.displayName,\n email: currentUser.email,\n photoURL: currentUser.photoURL,\n roles: currentUser.roles\n });\n }\n return managed;\n }, [currentUser]);\n\n const currentSelectableUser = useMemo((): SelectableUser | null => {\n if (!currentUser) return null;\n return {\n uid: currentUser.uid,\n displayName: currentUser.displayName,\n email: currentUser.email,\n photoURL: currentUser.photoURL,\n roles: currentUser.roles\n };\n }, [currentUser]);\n\n const [selectedUser, setSelectedUser] = useState<SelectableUser | null>(null);\n\n useEffect(() => {\n localStorage.setItem(`${storageKey}_path`, JSON.stringify(pathParams));\n localStorage.setItem(`${storageKey}_query`, JSON.stringify(queryParams));\n localStorage.setItem(`${storageKey}_headers`, JSON.stringify(customHeaders));\n localStorage.setItem(`${storageKey}_body`, JSON.stringify(body));\n }, [storageKey, pathParams, queryParams, customHeaders, body]);\n\n // Build the final URL\n const resolvedUrl = useMemo(() => {\n const base = basePath.startsWith(\"/\") ? basePath : `/${basePath}`;\n const cleanBase = base === \"/\" ? \"\" : base;\n let url = `${apiUrl.replace(/\\/+$/, \"\")}${cleanBase}${endpoint.path}`;\n // Replace path params\n for (const [key, val] of Object.entries(pathParams)) {\n url = url.replace(`{${key}}`, encodeURIComponent(val));\n }\n // Append query params\n const qp = Object.entries(queryParams).filter(([, v]) => v.trim() !== \"\");\n if (qp.length > 0) {\n url += \"?\" + qp.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join(\"&\");\n }\n return url;\n }, [apiUrl, basePath, endpoint.path, pathParams, queryParams]);\n\n const pathParamDefs = endpoint.parameters.filter((p) => p.in === \"path\");\n const queryParamDefs = endpoint.parameters.filter((p) => p.in === \"query\");\n const hasBody = [\"post\", \"put\", \"patch\"].includes(endpoint.method);\n\n const execute = useCallback(async () => {\n setValidationError(null);\n if (hasBody && body.trim()) {\n try {\n JSON.parse(body);\n } catch (err: unknown) {\n setValidationError(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);\n return;\n }\n }\n\n setLoading(true);\n setResponse(null);\n const start = performance.now();\n\n try {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n\n for (const h of customHeaders) {\n if (h.key.trim()) headers[h.key.trim()] = h.value;\n }\n\n if (authMode === \"jwt\") {\n const token = await getAuthToken();\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n if (selectedUser && selectedUser.uid !== currentUser?.uid) {\n headers[\"x-rebase-impersonate\"] = selectedUser.uid;\n }\n }\n\n const res = await fetch(resolvedUrl, {\n method: endpoint.method.toUpperCase(),\n headers,\n body: hasBody && body.trim() ? body : undefined\n });\n\n const elapsed = Math.round(performance.now() - start);\n let text: string;\n\n const rawText = await res.text();\n try {\n const json = JSON.parse(rawText);\n text = JSON.stringify(json, null, 2);\n } catch {\n text = rawText;\n }\n\n setResponse({ status: res.status,\nstatusText: res.statusText,\nbody: text,\ntime: elapsed });\n } catch (err: unknown) {\n setResponse({\n status: 0,\n statusText: \"Network Error\",\n body: err instanceof Error ? err.message : \"Request failed\",\n time: Math.round(performance.now() - start)\n });\n } finally {\n setLoading(false);\n }\n }, [resolvedUrl, endpoint.method, hasBody, body, authMode, getAuthToken, customHeaders, selectedUser, currentUser?.uid]);\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"p-5 space-y-5 overflow-y-auto flex-1\">\n {/* Auth Mode */}\n <AuthSimulationSelector\n authMode={authMode}\n setAuthMode={setAuthMode}\n selectedUser={selectedUser}\n setSelectedUser={setSelectedUser}\n users={users}\n loading={false}\n currentUser={currentSelectableUser}\n />\n\n {/* Path Params */}\n {pathParamDefs.length > 0 && (\n <ParamSection\n title=\"Path Parameters\"\n params={pathParamDefs}\n values={pathParams}\n onChange={(k, v) => setPathParams((prev) => ({ ...prev,\n[k]: v }))}\n />\n )}\n\n {/* Query Params */}\n {queryParamDefs.length > 0 && (\n <ParamSection\n title=\"Query Parameters\"\n params={queryParamDefs}\n values={queryParams}\n onChange={(k, v) => setQueryParams((prev) => ({ ...prev,\n[k]: v }))}\n />\n )}\n\n {/* Custom Headers */}\n <CustomKeyValueSection\n title=\"Custom Headers\"\n values={customHeaders}\n onChange={(i, k, v) => {\n const next = [...customHeaders];\n next[i] = { key: k,\nvalue: v };\n setCustomHeaders(next);\n }}\n onAdd={() => setCustomHeaders((prev) => [...prev, { key: \"\",\nvalue: \"\" }])}\n onRemove={(i) => {\n const next = [...customHeaders];\n next.splice(i, 1);\n setCustomHeaders(next);\n }}\n />\n\n {/* Request Body */}\n {hasBody && (\n <div>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider mb-2 block\"\n >\n Request Body\n </Typography>\n <TextField\n multiline\n minRows={10}\n value={body}\n onChange={(e) => { setBody(e.target.value); setValidationError(null); }}\n spellCheck={false}\n error={!!validationError}\n className=\"w-full\"\n inputClassName=\"font-mono text-xs p-3 resize-y\"\n />\n {validationError && (\n <Typography variant=\"caption\" className=\"text-red-500 mt-1 block text-xs\">\n {validationError}\n </Typography>\n )}\n </div>\n )}\n\n {/* URL Preview */}\n <div className=\"rounded-lg bg-surface-100 dark:bg-surface-900 p-3\">\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-[10px] uppercase tracking-wider block mb-1\"\n >\n Request URL\n </Typography>\n <code className=\"text-xs font-mono text-text-primary dark:text-text-primary-dark break-all\">\n {resolvedUrl}\n </code>\n </div>\n\n {/* Execute Button */}\n <Button variant=\"filled\" onClick={execute} disabled={loading} className=\"w-full\">\n {loading ? (\n <span className=\"flex items-center gap-2\">\n <LoaderIcon size={iconSize.small} className=\"animate-spin\" />\n Sending…\n </span>\n ) : (\n <span className=\"flex items-center gap-2\">\n <SendIcon size={iconSize.small} />\n Send Request\n </span>\n )}\n </Button>\n\n {/* Response */}\n {response && (\n <div className={cls(\"rounded-lg border overflow-hidden\", defaultBorderMixin)}>\n <div\n className={cls(\n \"flex items-center justify-between px-4 py-2.5\",\n \"bg-surface-50 dark:bg-surface-900/50\"\n )}\n >\n <div className=\"flex items-center gap-3\">\n <ResponseBadge status={response.status}/>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs\"\n >\n {response.statusText}\n </Typography>\n </div>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-mono\"\n >\n {response.time}ms\n </Typography>\n </div>\n <pre\n className={cls(\n \"p-4 text-xs font-mono overflow-auto max-h-96\",\n \"bg-surface-950 text-emerald-400\",\n \"dark:bg-surface-900 dark:text-emerald-400\"\n )}\n >\n {response.body}\n </pre>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/* ── Param Section ────────────────────────────────────────────────── */\n\nfunction ParamSection({\n title,\n params,\n values,\n onChange\n}: {\n title: string;\n params: ParsedEndpoint[\"parameters\"];\n values: Record<string, string>;\n onChange: (_key: string, _value: string) => void;\n}) {\n return (\n <div>\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider mb-2 block\"\n >\n {title}\n </Typography>\n <div className=\"space-y-2\">\n {params.map((p) => (\n <div key={p.name} className=\"flex items-center gap-3\">\n <label className=\"w-32 shrink-0\">\n <code className=\"text-xs font-mono font-semibold\">{p.name}</code>\n {p.required && <span className=\"text-red-500 ml-0.5 text-xs\">*</span>}\n </label>\n <TextField\n size=\"small\"\n placeholder={p.description ?? p.name}\n value={values[p.name] ?? \"\"}\n onChange={(e) => onChange(p.name, e.target.value)}\n className=\"flex-1\"\n inputClassName=\"font-mono text-xs\"\n />\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nfunction CustomKeyValueSection({\n title,\n values,\n onChange,\n onAdd,\n onRemove\n}: {\n title: string;\n values: Array<{ key: string; value: string }>;\n onChange: (index: number, key: string, value: string) => void;\n onAdd: () => void;\n onRemove: (index: number) => void;\n}) {\n return (\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <Typography\n variant=\"caption\"\n className=\"text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider block\"\n >\n {title}\n </Typography>\n <Button\n variant=\"text\"\n size=\"small\"\n color=\"primary\"\n onClick={onAdd}\n className=\"text-xs p-0 min-h-0\"\n >\n <PlusIcon size={iconSize.small} className=\"mr-1\" /> Add Header\n </Button>\n </div>\n <div className=\"space-y-2\">\n {values.map((v, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <TextField\n size=\"small\"\n placeholder=\"Header name\"\n value={v.key}\n onChange={(e) => onChange(i, e.target.value, v.value)}\n className=\"w-1/3\"\n inputClassName=\"font-mono text-xs\"\n />\n <TextField\n size=\"small\"\n placeholder=\"Value\"\n value={v.value}\n onChange={(e) => onChange(i, v.key, e.target.value)}\n className=\"flex-1\"\n inputClassName=\"font-mono text-xs\"\n />\n <IconButton\n size=\"small\"\n onClick={() => onRemove(i)}\n className=\"text-text-secondary hover:text-red-500 shrink-0\"\n title=\"Remove\"\n >\n <XIcon size={iconSize.small} />\n </IconButton>\n </div>\n ))}\n {values.length === 0 && (\n <Typography variant=\"caption\" className=\"text-text-secondary/50 italic text-xs\">\n No custom headers added.\n </Typography>\n )}\n </div>\n </div>\n );\n}\n\n/* ── Helpers ──────────────────────────────────────────────────────── */\n\nfunction ResponseBadge({ status }: { status: number }) {\n let colorClass = \"text-red-500\";\n if (status >= 200 && status < 300) colorClass = \"text-emerald-500\";\n else if (status >= 300 && status < 400) colorClass = \"text-blue-500\";\n else if (status >= 400 && status < 500) colorClass = \"text-amber-500\";\n\n return (\n <span className={cls(\"text-xs font-bold font-mono\", colorClass)}>\n {status || \"ERR\"}\n </span>\n );\n}\n\nfunction buildBodyTemplate(endpoint: ParsedEndpoint): string {\n if (!endpoint.requestBody?.content) return \"{\\n \\n}\";\n const json = endpoint.requestBody.content[\"application/json\"];\n if (!json?.schema?.properties) return \"{\\n \\n}\";\n\n const props = json.schema.properties;\n const lines: string[] = [\"{\"];\n const keys = Object.keys(props);\n keys.forEach((key, i) => {\n const prop = props[key];\n if (prop.readOnly) return;\n const comma = i < keys.length - 1 ? \",\" : \"\";\n const val = defaultValue(prop);\n lines.push(` \"${key}\": ${val}${comma}`);\n });\n lines.push(\"}\");\n return lines.join(\"\\n\");\n}\n\nfunction defaultValue(schema: { type?: string; format?: string; enum?: (string | number)[] }): string {\n if (schema.enum) return JSON.stringify(schema.enum[0]);\n switch (schema.type) {\n case \"string\":\n return schema.format === \"date-time\" ? `\"${new Date().toISOString()}\"` : '\"\"';\n case \"number\":\n case \"integer\":\n return \"0\";\n case \"boolean\":\n return \"false\";\n case \"array\":\n return \"[]\";\n default:\n return \"null\";\n }\n}\n","import React, { useState, useEffect, useMemo } from \"react\";\nimport { useApiConfig, useAuthController } from \"@rebasepro/app\";\nimport {\n CircularProgress,\n Typography,\n Alert,\n cls,\n Button,\n Chip,\n defaultBorderMixin,\n SearchBar,\n iconSize\n} from \"@rebasepro/ui\";\nimport { BookOpenIcon, PlayIcon } from \"@rebasepro/ui\";\nimport { EndpointDetail } from \"./EndpointDetail\";\nimport { TryItPanel } from \"./TryItPanel\";\nimport type { OpenApiSpec, ParsedEndpoint } from \"./types\";\nimport { parseOpenApiSpec } from \"./parseSpec\";\n\n/**\n * Custom-built API Explorer for Rebase Studio.\n * No external dependencies — renders the OpenAPI spec natively\n * with deep integration into the Rebase auth system.\n */\nexport function ApiExplorer() {\n const apiConfig = useApiConfig();\n const authController = useAuthController();\n const apiUrl = apiConfig?.apiUrl;\n\n const [spec, setSpec] = useState<OpenApiSpec | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const [selectedEndpoint, setSelectedEndpoint] = useState<ParsedEndpoint | null>(null);\n const [sidebarFilter, setSidebarFilter] = useState(\"\");\n const [tryItOpen, setTryItOpen] = useState(false);\n\n // Fetch OpenAPI spec\n useEffect(() => {\n if (!apiUrl) return;\n let cancelled = false;\n const specUrl = `${apiUrl.replace(/\\/+$/, \"\")}/api/docs`;\n\n (async () => {\n try {\n // The spec endpoint itself is public on a stock backend, but\n // `apiUrl` may route through an authenticated proxy (the\n // console's Studio embed) — carry the token like every other\n // request in this view, and like LogsExplorer does.\n const getAuthToken = apiConfig?.getAuthToken ?? authController.getAuthToken;\n const token = getAuthToken ? await getAuthToken() : null;\n const res = await fetch(specUrl, token ? { headers: { Authorization: `Bearer ${token}` } } : undefined);\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\n const data = await res.json();\n if (!cancelled) {\n setSpec(data);\n setLoading(false);\n }\n } catch (err: unknown) {\n if (!cancelled) {\n setError(err instanceof Error ? err.message : \"Failed to load API spec\");\n setLoading(false);\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [apiUrl, apiConfig, authController]);\n\n // Parse spec into grouped endpoints\n const { groups, allEndpoints } = useMemo(() => {\n if (!spec) return { groups: [],\nallEndpoints: [] };\n return parseOpenApiSpec(spec);\n }, [spec]);\n\n // Filter\n const filteredGroups = useMemo(() => {\n if (!sidebarFilter.trim()) return groups;\n const q = sidebarFilter.toLowerCase();\n return groups\n .map((g) => ({\n ...g,\n endpoints: g.endpoints.filter(\n (e) =>\n e.path.toLowerCase().includes(q) ||\n e.summary.toLowerCase().includes(q) ||\n e.method.toLowerCase().includes(q)\n )\n }))\n .filter((g) => g.endpoints.length > 0);\n }, [groups, sidebarFilter]);\n\n // Auto-select first endpoint\n useEffect(() => {\n if (!selectedEndpoint && allEndpoints.length > 0) {\n setSelectedEndpoint(allEndpoints[0]);\n }\n }, [allEndpoints, selectedEndpoint]);\n\n // ── States ───────────────────────────────────────────────────────\n if (!apiUrl) {\n return (\n <div className=\"flex items-center justify-center h-full w-full p-8\">\n <Alert color=\"warning\">\n <Typography variant=\"body2\">\n No API URL configured. Ensure your app provides an{\" \"}\n <code className=\"font-mono text-xs\">apiUrl</code>.\n </Typography>\n </Alert>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full w-full gap-4\">\n <CircularProgress size=\"medium\"/>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark animate-pulse\">\n Loading API specification…\n </Typography>\n </div>\n );\n }\n\n if (error || !spec) {\n return (\n <div className=\"flex items-center justify-center h-full w-full p-8\">\n <Alert color=\"error\">\n <Typography variant=\"body2\">{error ?? \"Unknown error\"}</Typography>\n </Alert>\n </div>\n );\n }\n\n const METHOD_COLORS: Record<string, string> = {\n get: \"text-blue-600 dark:text-blue-400\",\n post: \"text-emerald-600 dark:text-emerald-400\",\n put: \"text-amber-600 dark:text-amber-400\",\n patch: \"text-orange-600 dark:text-orange-400\",\n delete: \"text-red-600 dark:text-red-400\"\n };\n\n return (\n <div className=\"flex h-full w-full overflow-hidden\">\n {/* ── Sidebar ──────────────────────────────────────── */}\n <div\n className={cls(\n \"w-72 min-w-[272px] flex flex-col h-full overflow-hidden border-r\",\n defaultBorderMixin,\n \"bg-surface-50 dark:bg-surface-900\"\n )}\n >\n {/* Header */}\n <div className=\"p-4 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <BookOpenIcon size={iconSize.medium} className=\"text-primary dark:text-primary-dark\" />\n <Typography variant=\"subtitle2\" className=\"font-semibold\">\n {spec.info?.title ?? \"API Reference\"}\n </Typography>\n </div>\n {spec.info?.version && (\n <Chip size=\"smallest\" colorScheme=\"cyanDarker\">\n v{spec.info.version}\n </Chip>\n )}\n {/* Search */}\n <div className=\"mb-2\">\n <SearchBar\n placeholder=\"Filter endpoints…\"\n size=\"small\"\n onTextSearch={(val) => setSidebarFilter(val ?? \"\")}\n />\n </div>\n\n {/* Auth status removed to avoid redundancy with the AuthSimulationSelector */}\n </div>\n\n {/* Endpoint list */}\n <div className=\"flex-1 overflow-y-auto px-2 pb-4\">\n {filteredGroups.map((group) => (\n <div key={group.tag} className=\"mb-3\">\n <Typography\n variant=\"caption\"\n className=\"px-2 py-1.5 text-text-secondary dark:text-text-secondary-dark uppercase tracking-wider font-semibold text-[10px]\"\n >\n {group.tag}\n </Typography>\n {group.endpoints.map((ep) => {\n const isSelected = selectedEndpoint?.id === ep.id;\n return (\n <Button\n key={ep.id}\n variant=\"text\"\n color=\"neutral\"\n fullWidth\n onClick={() => {\n setSelectedEndpoint(ep);\n setTryItOpen(false);\n }}\n className={cls(\n \"!justify-between !px-2.5 !py-1.5 !text-left !text-sm\",\n isSelected\n ? \"bg-surface-200 dark:bg-surface-800 font-medium\"\n : \"text-text-primary dark:text-text-primary-dark\"\n )}\n >\n <span className=\"truncate text-[13px] opacity-90\">{ep.summary || ep.shortPath}</span>\n <span\n className={cls(\n \"text-[10px] font-bold uppercase shrink-0\",\n METHOD_COLORS[ep.method] ?? \"text-text-secondary\"\n )}\n >\n {ep.method}\n </span>\n </Button>\n );\n })}\n </div>\n ))}\n {filteredGroups.length === 0 && (\n <Typography\n variant=\"body2\"\n className=\"text-center text-text-secondary dark:text-text-secondary-dark py-8\"\n >\n No endpoints match\n </Typography>\n )}\n </div>\n </div>\n\n {/* ── Main content ─────────────────────────────────── */}\n <div className=\"flex-1 flex flex-col h-full overflow-hidden\">\n {selectedEndpoint ? (\n <>\n {/* Top bar */}\n <div\n className={cls(\n \"flex items-center justify-between px-5 py-3 gap-4 shrink-0 border-b z-10\",\n defaultBorderMixin,\n \"bg-surface-50/80 dark:bg-surface-950/80 backdrop-blur-md sticky top-0\"\n )}\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <span\n className={cls(\n \"text-xs font-bold uppercase\",\n METHOD_COLORS[selectedEndpoint.method] ?? \"\"\n )}\n >\n {selectedEndpoint.method}\n </span>\n <code className=\"text-sm font-mono text-text-primary dark:text-text-primary-dark truncate\">\n {selectedEndpoint.path}\n </code>\n </div>\n <Button\n variant={tryItOpen ? \"filled\" : \"outlined\"}\n size=\"small\"\n onClick={() => setTryItOpen((v) => !v)}\n >\n <PlayIcon size={iconSize.small} className=\"mr-1\" />\n Try It\n </Button>\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto\">\n {tryItOpen ? (\n <TryItPanel\n key={selectedEndpoint.operationId || selectedEndpoint.path}\n endpoint={selectedEndpoint}\n apiUrl={apiUrl}\n getAuthToken={apiConfig?.getAuthToken ?? authController.getAuthToken}\n user={authController.user}\n basePath={spec?.servers?.[0]?.url || \"\"}\n />\n ) : (\n <EndpointDetail endpoint={selectedEndpoint} spec={spec}/>\n )}\n </div>\n </>\n ) : (\n <div className=\"flex items-center justify-center h-full\">\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n Select an endpoint from the sidebar\n </Typography>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nApiExplorer.displayName = \"ApiExplorer\";\n\n"],"mappings":"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"}
@@ -6,6 +6,14 @@ import { useSearchParams } from "react-router-dom";
6
6
  import { DEFAULT_STORAGE_SOURCE_KEY } from "@rebasepro/types";
7
7
  import { useDropzone } from "react-dropzone";
8
8
  //#region src/components/StorageView/StorageView.tsx
9
+ /**
10
+ * The query parameter holding the folder being browsed.
11
+ *
12
+ * Namespaced because Studio does not always own the URL it renders under: the
13
+ * SaaS console embeds this view in a page that keeps its own state in `?tab=`
14
+ * and `?sub=`, and a bare `path` is a name any host app might already be using.
15
+ */
16
+ var STORAGE_PATH_PARAM = "storagePath";
9
17
  function formatFileSize(bytes) {
10
18
  if (bytes < 1024) return `${bytes} B`;
11
19
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -420,7 +428,7 @@ var StorageView = () => {
420
428
  const [selectedSourceKey, setSelectedSourceKey] = useState(DEFAULT_STORAGE_SOURCE_KEY);
421
429
  const storageSource = storageSources.sources[selectedSourceKey] ?? defaultStorageSource;
422
430
  const [searchParams, setSearchParams] = useSearchParams();
423
- const currentPath = searchParams.get("path") || "";
431
+ const currentPath = searchParams.get(STORAGE_PATH_PARAM) || searchParams.get("path") || "";
424
432
  const [loading, setLoading] = useState(true);
425
433
  const [error, setError] = useState(null);
426
434
  const [folders, setFolders] = useState([]);
@@ -488,8 +496,12 @@ var StorageView = () => {
488
496
  selectedSourceKey
489
497
  ]);
490
498
  const handleNavigate = useCallback((path) => {
491
- if (!path) setSearchParams({});
492
- else setSearchParams({ path });
499
+ setSearchParams((prev) => {
500
+ const next = new URLSearchParams(prev);
501
+ if (path) next.set(STORAGE_PATH_PARAM, path);
502
+ else next.delete(STORAGE_PATH_PARAM);
503
+ return next;
504
+ }, { replace: true });
493
505
  setSelectedFile(null);
494
506
  setSelectedDownloadUrl(null);
495
507
  setSelectedPaths(/* @__PURE__ */ new Set());
@@ -1420,4 +1432,4 @@ var StorageView = () => {
1420
1432
  //#endregion
1421
1433
  export { StorageView };
1422
1434
 
1423
- //# sourceMappingURL=StorageView-UvyM2xdW.js.map
1435
+ //# sourceMappingURL=StorageView-bRwRfwku.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageView-bRwRfwku.js","names":[],"sources":["../src/components/StorageView/StorageView.tsx"],"sourcesContent":["\nimport React, { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport {\n ArrowLeftIcon,\n Button,\n Checkbox,\n CheckIcon,\n Chip,\n CircularProgress,\n cls,\n CopyIcon,\n defaultBorderMixin,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n DownloadIcon,\n FileIcon,\n FileTextIcon,\n FileUpload,\n FolderIcon,\n FolderPlusIcon,\n HomeIcon,\n IconButton,\n iconSize,\n ImageIcon,\n LayoutGridIcon,\n ListIcon,\n LoadingButton,\n Music2Icon,\n PlusIcon,\n RefreshCwIcon,\n ResizablePanels,\n Select,\n SelectItem,\n TextField,\n Tooltip,\n Trash2Icon,\n Typography,\n UploadCloudIcon,\n VideoIcon,\n XIcon\n} from \"@rebasepro/ui\";\nimport { useStorageSource, useStorageSources, useSnackbarController, ErrorView, useApiConfig } from \"@rebasepro/app\";\nimport { DEFAULT_STORAGE_SOURCE_KEY, type StorageListResult } from \"@rebasepro/types\";\nimport { useSearchParams } from \"react-router-dom\";\nimport { useDropzone } from \"react-dropzone\";\n\n// ──────────────────────────────────────────────\n// Types\n// ──────────────────────────────────────────────\n\ninterface StorageFile {\n name: string;\n fullPath: string;\n isFolder: boolean;\n /** Only populated when metadata is fetched */\n size?: number;\n contentType?: string;\n downloadUrl?: string;\n}\n\n// ──────────────────────────────────────────────\n// Helpers\n// ──────────────────────────────────────────────\n\n/**\n * The query parameter holding the folder being browsed.\n *\n * Namespaced because Studio does not always own the URL it renders under: the\n * SaaS console embeds this view in a page that keeps its own state in `?tab=`\n * and `?sub=`, and a bare `path` is a name any host app might already be using.\n */\nconst STORAGE_PATH_PARAM = \"storagePath\";\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\nfunction getFileIcon(contentType?: string) {\n if (!contentType) return FileTextIcon;\n if (contentType.startsWith(\"image/\")) return ImageIcon;\n if (contentType.startsWith(\"video/\")) return VideoIcon;\n if (contentType.startsWith(\"audio/\")) return Music2Icon;\n return FileTextIcon;\n}\n\nfunction getExtension(name: string): string {\n const parts = name.split(\".\");\n return parts.length > 1 ? parts[parts.length - 1].toUpperCase() : \"\";\n}\n\nfunction breadcrumbSegments(path: string): { label: string; path: string }[] {\n if (!path || path === \"/\") return [{ label: \"Root\",\npath: \"\" }];\n const parts = path.split(\"/\").filter(Boolean);\n const segments = [{ label: \"Root\",\npath: \"\" }];\n let accumulated = \"\";\n for (const part of parts) {\n accumulated = accumulated ? `${accumulated}/${part}` : part;\n segments.push({ label: part,\npath: accumulated });\n }\n return segments;\n}\n\n// ──────────────────────────────────────────────\n// Upload Dialog\n// ──────────────────────────────────────────────\n\nfunction UploadDialog({\n open,\n currentPath,\n onClose,\n onUpload\n}: {\n open: boolean;\n currentPath: string;\n onClose: () => void;\n onUpload: (files: File[]) => Promise<void>;\n}) {\n const [uploading, setUploading] = useState(false);\n const [selectedFiles, setSelectedFiles] = useState<File[]>([]);\n const [error, setError] = useState<string | null>(null);\n\n const handleFilesAdded = useCallback((files: File[]) => {\n setSelectedFiles(prev => [...prev, ...files]);\n }, []);\n\n const handleRemoveFile = useCallback((index: number) => {\n setSelectedFiles(prev => prev.filter((_, i) => i !== index));\n }, []);\n\n const handleUpload = useCallback(async () => {\n if (selectedFiles.length === 0) return;\n setUploading(true);\n setError(null);\n try {\n await onUpload(selectedFiles);\n setSelectedFiles([]);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Upload failed\");\n } finally {\n setUploading(false);\n }\n }, [selectedFiles, onUpload, onClose]);\n\n const handleClose = useCallback(() => {\n if (!uploading) {\n setSelectedFiles([]);\n setError(null);\n onClose();\n }\n }, [uploading, onClose]);\n\n return (\n <Dialog open={open} onOpenChange={(o) => !o && handleClose()} maxWidth=\"md\">\n <DialogTitle>\n Upload Files\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark mt-0.5 block\">\n to <span className=\"font-mono text-primary\">/{currentPath || \"root\"}</span>\n </Typography>\n </DialogTitle>\n <DialogContent className=\"space-y-4\">\n <FileUpload\n onFilesAdded={handleFilesAdded}\n size=\"large\"\n uploadDescription={\n <div className=\"flex flex-col items-center justify-center pointer-events-none\">\n <UploadCloudIcon className=\"text-surface-accent-400 mb-2 w-8 h-8\"/>\n <Typography variant=\"label\">\n Drop files here or click to browse\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\">\n Any file type supported\n </Typography>\n </div>\n }\n />\n\n {error && (\n <Typography variant=\"caption\" className=\"text-red-500 block whitespace-pre-line\">\n {error}\n </Typography>\n )}\n\n {selectedFiles.length > 0 && (\n <div className=\"space-y-2\">\n <Typography variant=\"caption\" color=\"secondary\">\n Selected files ({selectedFiles.length})\n </Typography>\n <div className=\"max-h-40 overflow-auto space-y-1\">\n {selectedFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center justify-between p-2 rounded bg-surface-100 dark:bg-surface-800\"\n >\n <div className=\"flex-1 min-w-0 mr-2\">\n <Typography variant=\"body2\" className=\"truncate\">\n {file.name}\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\">\n {formatFileSize(file.size)}\n </Typography>\n </div>\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n handleRemoveFile(index);\n }}\n disabled={uploading}\n >\n <XIcon size={14}/>\n </IconButton>\n </div>\n ))}\n </div>\n </div>\n )}\n </DialogContent>\n\n <DialogActions>\n <Button variant=\"text\" onClick={handleClose} disabled={uploading}>\n Cancel\n </Button>\n <Button\n variant=\"filled\"\n onClick={handleUpload}\n disabled={selectedFiles.length === 0 || uploading}\n startIcon={uploading ? <CircularProgress size=\"smallest\"/> : <UploadCloudIcon size={14}/>}\n >\n {uploading ? \"Uploading...\" : `Upload${selectedFiles.length > 0 ? ` (${selectedFiles.length})` : \"\"}`}\n </Button>\n </DialogActions>\n </Dialog>\n );\n}\n\n// ──────────────────────────────────────────────\n// FileIcon preview panel\n// ──────────────────────────────────────────────\n\nfunction FilePreviewPanel({\n file,\n onClose,\n onDelete,\n downloadUrl\n}: {\n file: StorageFile;\n onClose: () => void;\n onDelete: () => void;\n downloadUrl: string | null;\n}) {\n const isImage = file.contentType?.startsWith(\"image/\");\n const isVideo = file.contentType?.startsWith(\"video/\");\n const isAudio = file.contentType?.startsWith(\"audio/\");\n const FileIconComponent = getFileIcon(file.contentType);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [urlCopied, setUrlCopied] = useState(false);\n\n return (\n <>\n <div className={cls(\n \"flex flex-col h-full border-l\",\n defaultBorderMixin,\n \"bg-white dark:bg-surface-800\"\n )}>\n {/* Header */}\n <div className={cls(\"flex items-center justify-between p-3 border-b shrink-0\", defaultBorderMixin)}>\n <Typography variant=\"body2\" className=\"font-medium truncate flex-1 mr-2\">\n {file.name}\n </Typography>\n <div className=\"flex items-center gap-0.5\">\n {downloadUrl && (\n <Tooltip title=\"Download\">\n <IconButton\n size=\"small\"\n onClick={() => window.open(downloadUrl, \"_blank\")}\n >\n <DownloadIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n )}\n <Tooltip title=\"Delete\">\n <IconButton\n size=\"small\"\n onClick={() => setDeleteDialogOpen(true)}\n className=\"text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20\"\n >\n <Trash2Icon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n <IconButton size=\"small\" onClick={onClose}>\n <XIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n </div>\n\n {/* Preview */}\n <div className=\"flex-1 overflow-auto\">\n <div className={cls(\"flex flex-col items-center justify-center min-h-[200px] p-4 bg-surface-50 dark:bg-surface-800 border-b\", defaultBorderMixin)}>\n {(() => {\n const ext = getExtension(file.name)?.toLowerCase() || \"\";\n const isImage = file.contentType?.startsWith(\"image/\") || [\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"svg\"].includes(ext);\n const isVideo = file.contentType?.startsWith(\"video/\") || [\"mp4\", \"webm\", \"ogg\", \"mov\"].includes(ext);\n const isAudio = file.contentType?.startsWith(\"audio/\") || [\"mp3\", \"wav\", \"ogg\", \"m4a\"].includes(ext);\n const downloadUrl = file.downloadUrl;\n\n if (isImage && downloadUrl) {\n return (\n <img\n src={downloadUrl}\n alt={file.name}\n className=\"max-w-full max-h-[400px] object-contain rounded-md shadow-sm\"\n />\n );\n } else if (isVideo && downloadUrl) {\n return (\n <video\n src={downloadUrl}\n className=\"max-w-full max-h-[400px] rounded-md\"\n controls\n />\n );\n } else if (isAudio && downloadUrl) {\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Music2Icon className=\"text-surface-accent-400 w-10 h-10\"/>\n <audio src={downloadUrl} controls className=\"w-full max-w-xs\"/>\n </div>\n );\n } else {\n return (\n <div className=\"flex flex-col items-center gap-3 text-surface-accent-400\">\n <FileIconComponent className=\"w-10 h-10\"/>\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark\">\n No preview available\n </Typography>\n </div>\n );\n }\n })()}\n </div>\n </div>\n\n {/* Metadata */}\n <div className=\"p-4 space-y-3\">\n <div>\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark text-[10px] uppercase tracking-wider font-bold mb-1 block\">\n File Info\n </Typography>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Name\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px] break-all\">\n {file.name}\n </Typography>\n </div>\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Type\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px]\">\n {file.contentType || \"Unknown\"}\n </Typography>\n </div>\n {file.size !== undefined && (\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Size\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px]\">\n {formatFileSize(file.size)}\n </Typography>\n </div>\n )}\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Extension\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px] font-mono\">\n {getExtension(file.name) || \"—\"}\n </Typography>\n </div>\n <div className=\"col-span-2\">\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Path\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px] font-mono break-all\">\n {file.fullPath}\n </Typography>\n </div>\n </div>\n\n {downloadUrl && (\n <div className=\"pt-2\">\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px] block mb-1\">\n URL\n </Typography>\n <div\n className={cls(\n \"flex items-center gap-2 p-2 rounded cursor-pointer transition-colors\",\n \"bg-surface-100 dark:bg-surface-800 hover:bg-surface-200 dark:hover:bg-surface-700\"\n )}\n onClick={() => {\n const fullUrl = downloadUrl.startsWith(\"http\")\n ? downloadUrl\n : `${window.location.origin}${downloadUrl.startsWith(\"/\") ? \"\" : \"/\"}${downloadUrl}`;\n navigator.clipboard.writeText(fullUrl).then(() => {\n setUrlCopied(true);\n setTimeout(() => setUrlCopied(false), 2000);\n });\n }}\n >\n <Typography variant=\"caption\" className=\"font-mono text-[11px] truncate flex-1 min-w-0 text-primary\">\n {(() => {\n const fullUrl = downloadUrl.startsWith(\"http\")\n ? downloadUrl\n : `${window.location.origin}${downloadUrl.startsWith(\"/\") ? \"\" : \"/\"}${downloadUrl}`;\n return fullUrl;\n })()}\n </Typography>\n <Tooltip title={urlCopied ? \"Copied!\" : \"Copy URL\"}>\n <div className=\"shrink-0\">\n {urlCopied\n ? <CheckIcon size={14} className=\"text-green-500\"/>\n : <CopyIcon size={14} className=\"text-surface-accent-400\"/>\n }\n </div>\n </Tooltip>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Delete Confirmation */}\n <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <DialogTitle hidden>Delete File</DialogTitle>\n <DialogContent>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n Delete File?\n </Typography>\n <Typography className=\"text-surface-accent-600 dark:text-surface-accent-400\">\n Are you sure you want to delete &quot;{file.name}&quot;?\n This action cannot be undone.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button variant=\"text\" onClick={() => setDeleteDialogOpen(false)}>\n Cancel\n </Button>\n <Button\n variant=\"filled\"\n color=\"error\"\n onClick={() => {\n setDeleteDialogOpen(false);\n onDelete();\n }}\n >\n Delete\n </Button>\n </DialogActions>\n </Dialog>\n </>\n );\n}\n\n// ──────────────────────────────────────────────\n// Main StorageView Export\n// ──────────────────────────────────────────────\n\nexport const StorageView = () => {\n const defaultStorageSource = useStorageSource();\n const storageSources = useStorageSources();\n const snackbarController = useSnackbarController();\n\n // Available backends to browse. Always includes the default; named\n // sources come from `<Rebase storageSources={...}>`.\n const sourceKeys = useMemo(() => {\n const keys = Object.keys(storageSources.sources);\n if (!keys.includes(DEFAULT_STORAGE_SOURCE_KEY)) keys.unshift(DEFAULT_STORAGE_SOURCE_KEY);\n return keys;\n }, [storageSources.sources]);\n\n const [selectedSourceKey, setSelectedSourceKey] = useState<string>(DEFAULT_STORAGE_SOURCE_KEY);\n\n const storageSource = storageSources.sources[selectedSourceKey] ?? defaultStorageSource;\n\n // Navigation\n const [searchParams, setSearchParams] = useSearchParams();\n // Accepts the historical unqualified `path` so links already shared keep\n // working; only the namespaced one is ever written.\n const currentPath = searchParams.get(STORAGE_PATH_PARAM) || searchParams.get(\"path\") || \"\";\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n // Contents\n const [folders, setFolders] = useState<StorageFile[]>([]);\n const [files, setFiles] = useState<StorageFile[]>([]);\n\n // Selection and preview\n const [selectedFile, setSelectedFile] = useState<StorageFile | null>(null);\n const [selectedDownloadUrl, setSelectedDownloadUrl] = useState<string | null>(null);\n\n // Upload\n const [uploadDialogOpen, setUploadDialogOpen] = useState(false);\n\n // View mode\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n\n // Multi-selection\n const [selectedPaths, setSelectedPaths] = useState<Set<string>>(new Set());\n const lastClickedRef = useRef<string | null>(null);\n\n // Bulk / folder delete\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [deleteDialogTarget, setDeleteDialogTarget] = useState<\"selection\" | StorageFile | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n // New folder\n const [newFolderDialogOpen, setNewFolderDialogOpen] = useState(false);\n const [newFolderName, setNewFolderName] = useState(\"\");\n const [creatingFolder, setCreatingFolder] = useState(false);\n const apiConfig = useApiConfig();\n\n const storageSourceRef = React.useRef(storageSource);\n useEffect(() => {\n storageSourceRef.current = storageSource;\n }, [storageSource]);\n\n // ── Fetch directory contents ──\n const fetchContents = useCallback(async (path: string) => {\n setLoading(true);\n setError(null);\n try {\n const result: StorageListResult = await storageSourceRef.current.listObjects(path);\n\n const folderItems: StorageFile[] = (result.prefixes ?? []).map(ref => ({\n name: ref.name,\n fullPath: ref.fullPath,\n isFolder: true\n }));\n\n // Build file items and fetch metadata for each\n const fileItems: StorageFile[] = await Promise.all(\n (result.items ?? []).map(async (ref) => {\n try {\n const downloadConfig = await storageSourceRef.current.getSignedUrl(ref.fullPath);\n return {\n name: ref.name,\n fullPath: ref.fullPath,\n isFolder: false,\n size: downloadConfig.metadata?.size,\n contentType: downloadConfig.metadata?.contentType,\n downloadUrl: downloadConfig.url ?? undefined\n };\n } catch {\n return {\n name: ref.name,\n fullPath: ref.fullPath,\n isFolder: false\n };\n }\n })\n );\n\n setFolders(folderItems);\n setFiles(fileItems);\n } catch (e) {\n console.error(\"Storage list error:\", e);\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n // `selectedSourceKey` is a dep so switching backend re-lists; the\n // ref-sync effect above runs first, so `storageSourceRef` is current.\n fetchContents(currentPath);\n }, [currentPath, fetchContents, selectedSourceKey]);\n\n // Navigate to path\n //\n // Updates only this view's own parameter and leaves the rest of the query\n // string alone. It used to assign the whole thing (`setSearchParams({})`),\n // which is fine when Studio owns the URL but destructive when it is\n // embedded: the SaaS console keeps the open tab in `?tab=`, so opening a\n // folder erased it and bounced the user out of Storage entirely. The key is\n // namespaced for the same reason — a bare `path` is a name a host app can\n // easily be using for something else.\n const handleNavigate = useCallback((path: string) => {\n setSearchParams(prev => {\n const next = new URLSearchParams(prev);\n if (path) next.set(STORAGE_PATH_PARAM, path);\n else next.delete(STORAGE_PATH_PARAM);\n return next;\n }, { replace: true });\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n setSelectedPaths(new Set());\n lastClickedRef.current = null;\n }, [setSearchParams]);\n\n // Navigate up one level\n const handleNavigateUp = useCallback(() => {\n const parts = currentPath.split(\"/\").filter(Boolean);\n parts.pop();\n handleNavigate(parts.join(\"/\"));\n }, [currentPath, handleNavigate]);\n\n // All items (folders + files) in display order, for shift-range select\n const allItems = useMemo(() => [...folders, ...files], [folders, files]);\n\n // ── Multi-select click handler ──\n const handleItemClick = useCallback((item: StorageFile, e: React.MouseEvent) => {\n const path = item.fullPath;\n if (e.metaKey || e.ctrlKey) {\n // Toggle individual item\n setSelectedPaths(prev => {\n const next = new Set(prev);\n if (next.has(path)) next.delete(path);\n else next.add(path);\n return next;\n });\n lastClickedRef.current = path;\n } else if (e.shiftKey && lastClickedRef.current) {\n // Range select\n const allPaths = allItems.map(i => i.fullPath);\n const anchorIdx = allPaths.indexOf(lastClickedRef.current);\n const currentIdx = allPaths.indexOf(path);\n if (anchorIdx >= 0 && currentIdx >= 0) {\n const [start, end] = anchorIdx < currentIdx ? [anchorIdx, currentIdx] : [currentIdx, anchorIdx];\n setSelectedPaths(prev => {\n const next = new Set(prev);\n for (let i = start; i <= end; i++) next.add(allPaths[i]);\n return next;\n });\n }\n } else {\n // Exclusive select\n setSelectedPaths(new Set([path]));\n lastClickedRef.current = path;\n // Also open preview if it's a file\n if (!item.isFolder) {\n setSelectedFile(item);\n if (item.downloadUrl) {\n setSelectedDownloadUrl(item.downloadUrl);\n } else {\n storageSourceRef.current.getSignedUrl(item.fullPath)\n .then(config => setSelectedDownloadUrl(config.url))\n .catch(() => setSelectedDownloadUrl(null));\n }\n } else {\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }\n }\n }, [allItems]);\n\n // Double-click: open folder or preview file\n const handleItemDoubleClick = useCallback((item: StorageFile) => {\n if (item.isFolder) {\n handleNavigate(item.fullPath);\n } else {\n setSelectedFile(item);\n if (item.downloadUrl) {\n setSelectedDownloadUrl(item.downloadUrl);\n } else {\n storageSourceRef.current.getSignedUrl(item.fullPath)\n .then(config => setSelectedDownloadUrl(config.url))\n .catch(() => setSelectedDownloadUrl(null));\n }\n }\n }, [handleNavigate]);\n\n // Upload files\n const handleUpload = useCallback(async (uploadFiles: File[]) => {\n for (const file of uploadFiles) {\n const key = currentPath ? `${currentPath}/${file.name}` : file.name;\n await storageSourceRef.current.putObject({\n file,\n key\n });\n }\n snackbarController.open({\n type: \"success\",\n message: `${uploadFiles.length} file${uploadFiles.length > 1 ? \"s\" : \"\"} uploaded successfully`\n });\n await fetchContents(currentPath);\n }, [currentPath, snackbarController, fetchContents]);\n\n // Create new folder\n const handleCreateFolder = useCallback(async () => {\n if (!newFolderName.trim() || !apiConfig?.apiUrl) return;\n\n // Validate folder name\n const name = newFolderName.trim();\n if (name.includes(\"/\") || name.includes(\"\\\\\")) {\n snackbarController.open({ type: \"error\",\nmessage: \"Folder name cannot contain slashes\" });\n return;\n }\n\n // Check if folder already exists\n const existingFolder = folders.find(f => f.name === name);\n if (existingFolder) {\n snackbarController.open({ type: \"error\",\nmessage: `Folder \"${name}\" already exists` });\n return;\n }\n\n setCreatingFolder(true);\n try {\n const folderPath = currentPath ? `default/${currentPath}/${name}` : `default/${name}`;\n const token = apiConfig.getAuthToken ? await apiConfig.getAuthToken() : null;\n const response = await fetch(`${apiConfig.apiUrl}/api/storage/folder`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { \"Authorization\": `Bearer ${token}` } : {})\n },\n body: JSON.stringify({ path: folderPath })\n });\n\n if (!response.ok) {\n const err = await response.json().catch(() => ({ error: \"Failed to create folder\" }));\n throw new Error(err.error || \"Failed to create folder\");\n }\n\n snackbarController.open({ type: \"success\",\nmessage: `Folder \"${name}\" created` });\n setNewFolderDialogOpen(false);\n setNewFolderName(\"\");\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally {\n setCreatingFolder(false);\n }\n }, [newFolderName, currentPath, apiConfig, snackbarController, fetchContents, folders]);\n\n // Drag-and-drop on main view\n const handleDropFiles = useCallback(async (droppedFiles: File[]) => {\n if (droppedFiles.length === 0) return;\n try {\n for (const file of droppedFiles) {\n const key = currentPath ? `${currentPath}/${file.name}` : file.name;\n await storageSourceRef.current.putObject({ file,\nkey });\n }\n snackbarController.open({\n type: \"success\",\n message: `${droppedFiles.length} file${droppedFiles.length > 1 ? \"s\" : \"\"} uploaded successfully`\n });\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n }\n }, [currentPath, snackbarController, fetchContents]);\n\n const {\n getRootProps: getDropRootProps,\n getInputProps: getDropInputProps,\n isDragActive\n } = useDropzone({\n onDrop: handleDropFiles,\n noClick: true,\n noKeyboard: true,\n noDragEventsBubbling: true\n });\n\n // ── Recursive folder delete helper ──\n const deleteFolderRecursive = useCallback(async (prefix: string) => {\n const result = await storageSourceRef.current.listObjects(prefix);\n // Delete all files in this level\n for (const item of result.items ?? []) {\n await storageSourceRef.current.deleteObject(item.fullPath);\n }\n // Recurse into sub-folders\n for (const sub of result.prefixes ?? []) {\n await deleteFolderRecursive(sub.fullPath);\n }\n // Delete the folder entry itself (needed for local filesystem)\n try {\n await storageSourceRef.current.deleteObject(prefix);\n } catch {\n // Ignore — S3 folders are virtual and may not exist as objects\n }\n }, []);\n\n // Delete a single file\n const handleDeleteFile = useCallback(async (file: StorageFile) => {\n try {\n if (file.isFolder) {\n await deleteFolderRecursive(file.fullPath);\n } else {\n await storageSourceRef.current.deleteObject(file.fullPath);\n }\n snackbarController.open({ type: \"success\",\nmessage: `\"${file.name}\" deleted` });\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n setSelectedPaths(prev => {\n const next = new Set(prev);\n next.delete(file.fullPath);\n return next;\n });\n fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n }, [currentPath, snackbarController, fetchContents, deleteFolderRecursive]);\n\n // Bulk delete (selected items)\n const handleBulkDelete = useCallback(async () => {\n setDeleting(true);\n try {\n const items = allItems.filter(i => selectedPaths.has(i.fullPath));\n for (const item of items) {\n if (item.isFolder) {\n await deleteFolderRecursive(item.fullPath);\n } else {\n await storageSourceRef.current.deleteObject(item.fullPath);\n }\n }\n snackbarController.open({ type: \"success\",\nmessage: `${items.length} item${items.length !== 1 ? \"s\" : \"\"} deleted` });\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }\n }, [allItems, selectedPaths, currentPath, snackbarController, fetchContents, deleteFolderRecursive]);\n\n // Confirm delete for a single folder\n const handleConfirmDeleteFolder = useCallback(async () => {\n if (!deleteDialogTarget || deleteDialogTarget === \"selection\") return;\n setDeleting(true);\n try {\n await deleteFolderRecursive(deleteDialogTarget.fullPath);\n snackbarController.open({ type: \"success\",\nmessage: `Folder \"${deleteDialogTarget.name}\" deleted` });\n setSelectedPaths(prev => {\n const next = new Set(prev);\n next.delete(deleteDialogTarget.fullPath);\n return next;\n });\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }\n }, [deleteDialogTarget, currentPath, snackbarController, fetchContents, deleteFolderRecursive]);\n\n // Select all / deselect\n const handleSelectAll = useCallback(() => {\n if (selectedPaths.size === allItems.length) {\n setSelectedPaths(new Set());\n } else {\n setSelectedPaths(new Set(allItems.map(i => i.fullPath)));\n }\n }, [allItems, selectedPaths]);\n\n // ── Keyboard shortcuts ──\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n // Don't handle shortcuts when a dialog is open\n if (deleteDialogOpen || uploadDialogOpen || newFolderDialogOpen) return;\n // Cmd/Ctrl+A: select all\n if ((e.metaKey || e.ctrlKey) && e.key === \"a\") {\n e.preventDefault();\n handleSelectAll();\n }\n // Escape: deselect\n if (e.key === \"Escape\") {\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }\n // Delete / Backspace: delete selected\n if ((e.key === \"Delete\" || e.key === \"Backspace\") && selectedPaths.size > 0 && !e.metaKey && !e.ctrlKey) {\n // Don't trigger if user is typing in an input\n if ((e.target as HTMLElement)?.tagName === \"INPUT\" || (e.target as HTMLElement)?.tagName === \"TEXTAREA\") return;\n e.preventDefault();\n setDeleteDialogTarget(\"selection\");\n setDeleteDialogOpen(true);\n }\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [handleSelectAll, selectedPaths, deleteDialogOpen, uploadDialogOpen, newFolderDialogOpen]);\n\n // Handle refresh\n const handleRefresh = useCallback(() => {\n fetchContents(currentPath);\n }, [currentPath, fetchContents]);\n\n const segments = breadcrumbSegments(currentPath);\n\n\n // ── Render file grid/list ──\n const renderContents = () => {\n if (loading) {\n return (\n <div className=\"flex-grow flex items-center justify-center\">\n <div className=\"text-center\">\n <CircularProgress size=\"medium\"/>\n <Typography variant=\"body2\" className=\"mt-4 text-text-secondary dark:text-text-secondary-dark font-mono tracking-tight animate-pulse\">\n Loading...\n </Typography>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex-grow flex items-center justify-center p-6 overflow-auto\">\n <ErrorView title=\"Error loading storage\" error={error} onRetry={handleRefresh}/>\n </div>\n );\n }\n\n\n if (allItems.length === 0) {\n return (\n <div className=\"flex-grow flex items-center justify-center text-text-disabled dark:text-text-disabled-dark\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-4 opacity-50\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1} d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\"/>\n </svg>\n <Typography variant=\"body2\">\n This folder is empty\n </Typography>\n <div className=\"flex items-center gap-2 mt-3\">\n <Button variant=\"text\" onClick={() => {\n setNewFolderName(\"\");\n setNewFolderDialogOpen(true);\n }}>\n <FolderPlusIcon size={iconSize.smallest}/>\n New folder\n </Button>\n <Button onClick={() => setUploadDialogOpen(true)}>\n <PlusIcon size={iconSize.smallest}/>\n Upload files\n </Button>\n </div>\n </div>\n </div>\n );\n }\n\n if (viewMode === \"list\") {\n return (\n <div className=\"flex-grow overflow-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className={cls(\"border-b text-left text-[10px] uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark\", defaultBorderMixin)}>\n <th className=\"pl-3 pr-0 py-2 w-8\">\n <Checkbox\n size=\"small\"\n checked={allItems.length > 0 && selectedPaths.size === allItems.length}\n indeterminate={selectedPaths.size > 0 && selectedPaths.size < allItems.length}\n onCheckedChange={handleSelectAll}\n />\n </th>\n <th className=\"px-2 py-2 font-bold\">Name</th>\n <th className=\"px-4 py-2 font-bold w-24\">Type</th>\n <th className=\"px-4 py-2 font-bold w-24 text-right\">Size</th>\n <th className=\"px-2 py-2 w-10\"/>\n </tr>\n </thead>\n <tbody>\n {folders.map(folder => {\n const isChecked = selectedPaths.has(folder.fullPath);\n return (\n <tr\n key={folder.fullPath}\n data-storage-item\n className={cls(\n \"cursor-pointer transition-colors border-b group\",\n defaultBorderMixin,\n isChecked\n ? \"bg-primary/5 dark:bg-primary/10\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-800\"\n )}\n onClick={(e) => handleItemClick(folder, e)}\n onDoubleClick={() => handleItemDoubleClick(folder)}\n >\n <td className=\"pl-3 pr-0 py-2.5\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n size=\"small\"\n checked={isChecked}\n onCheckedChange={() => {\n setSelectedPaths(prev => {\n const next = new Set(prev);\n if (next.has(folder.fullPath)) next.delete(folder.fullPath);\n else next.add(folder.fullPath);\n return next;\n });\n }}\n />\n </td>\n <td className=\"px-2 py-2.5\">\n <div className=\"flex items-center gap-2\">\n <FolderIcon size={iconSize.smallest} className=\"text-amber-500 dark:text-amber-400 shrink-0\"/>\n <Typography variant=\"body2\" className=\"text-[13px] font-medium truncate\">\n {folder.name}\n </Typography>\n </div>\n </td>\n <td className=\"px-4 py-2.5\">\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n Folder\n </Typography>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark\">\n —\n </Typography>\n </td>\n <td className=\"px-2 py-2.5\"/>\n </tr>\n );\n })}\n {files.map(file => {\n const FileIconComp = getFileIcon(file.contentType);\n const isChecked = selectedPaths.has(file.fullPath);\n return (\n <tr\n key={file.fullPath}\n data-storage-item\n className={cls(\n \"cursor-pointer transition-colors border-b group\",\n defaultBorderMixin,\n isChecked\n ? \"bg-primary/5 dark:bg-primary/10\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-800\"\n )}\n onClick={(e) => handleItemClick(file, e)}\n onDoubleClick={() => handleItemDoubleClick(file)}\n >\n <td className=\"pl-3 pr-0 py-2.5\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n size=\"small\"\n checked={isChecked}\n onCheckedChange={() => {\n setSelectedPaths(prev => {\n const next = new Set(prev);\n if (next.has(file.fullPath)) next.delete(file.fullPath);\n else next.add(file.fullPath);\n return next;\n });\n }}\n />\n </td>\n <td className=\"px-2 py-2.5\">\n <div className=\"flex items-center gap-2\">\n <FileIconComp size={iconSize.smallest} className=\"text-surface-accent-400 shrink-0\"/>\n <Typography variant=\"body2\" className=\"text-[13px] truncate\">\n {file.name}\n </Typography>\n </div>\n </td>\n <td className=\"px-4 py-2.5\">\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {getExtension(file.name) || file.contentType?.split(\"/\")[1]?.toUpperCase() || \"—\"}\n </Typography>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark font-mono text-[11px]\">\n {file.size !== undefined ? formatFileSize(file.size) : \"—\"}\n </Typography>\n </td>\n <td className=\"px-2 py-2.5\" onClick={(e) => e.stopPropagation()}>\n <IconButton\n size=\"smallest\"\n className=\"opacity-0 group-hover:opacity-100 transition-opacity\"\n onClick={() => handleDeleteFile(file)}\n >\n <Trash2Icon size={14}/>\n </IconButton>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n }\n\n // Grid view\n return (\n <div className=\"flex-grow overflow-auto p-4\">\n {/* Folder cards */}\n {folders.length > 0 && (\n <div className=\"mb-4\">\n <Typography variant=\"caption\" className=\"text-[10px] uppercase tracking-wider font-bold text-text-disabled dark:text-text-disabled-dark mb-2 block\">\n Folders\n </Typography>\n <div className=\"grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]\">\n {folders.map(folder => {\n const isChecked = selectedPaths.has(folder.fullPath);\n return (\n <div\n key={folder.fullPath}\n data-storage-item\n className={cls(\n \"rounded-lg p-3 cursor-pointer border\",\n \"transition-colors duration-150\",\n defaultBorderMixin,\n \"hover:bg-surface-100 dark:hover:bg-surface-800 hover:shadow-sm\",\n \"flex items-center gap-2\",\n isChecked && \"ring-2 ring-primary bg-primary/5 dark:bg-primary/10\"\n )}\n onClick={(e) => handleItemClick(folder, e)}\n onDoubleClick={() => handleItemDoubleClick(folder)}\n >\n <FolderIcon size={iconSize.smallest} className=\"text-amber-500 dark:text-amber-400 shrink-0\"/>\n <Typography variant=\"body2\" className=\"text-[13px] font-medium truncate\">\n {folder.name}\n </Typography>\n </div>\n );\n })}\n </div>\n </div>\n )}\n\n {/* FileIcon cards */}\n {files.length > 0 && (\n <div>\n <Typography variant=\"caption\" className=\"text-[10px] uppercase tracking-wider font-bold text-text-disabled dark:text-text-disabled-dark mb-2 block\">\n Files ({files.length})\n </Typography>\n <div className=\"grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]\">\n {files.map(file => {\n const FileIconComp = getFileIcon(file.contentType);\n const ext = getExtension(file.name)?.toLowerCase() || \"\";\n const isImage = file.contentType?.startsWith(\"image/\") || [\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"svg\"].includes(ext);\n const isChecked = selectedPaths.has(file.fullPath);\n\n return (\n <div\n key={file.fullPath}\n data-storage-item\n className={cls(\n \"rounded-lg overflow-hidden cursor-pointer border\",\n \"transition-shadow duration-150\",\n defaultBorderMixin,\n \"hover:shadow-md\",\n isChecked && \"ring-2 ring-primary\"\n )}\n onClick={(e) => handleItemClick(file, e)}\n onDoubleClick={() => handleItemDoubleClick(file)}\n >\n {/* Thumbnail or icon */}\n <div className=\"aspect-square relative overflow-hidden bg-surface-100 dark:bg-surface-800 flex items-center justify-center\">\n {isImage && file.downloadUrl ? (\n <img\n src={file.downloadUrl}\n alt={file.name}\n className=\"w-full h-full object-cover\"\n loading=\"lazy\"\n />\n ) : (\n <FileIconComp className=\"text-surface-accent-400 dark:text-surface-accent-500 w-8 h-8\"/>\n )}\n\n {/* Extension badge */}\n {getExtension(file.name) && (\n <div className=\"absolute bottom-1.5 right-1.5 px-1.5 py-0.5 rounded text-[9px] font-bold uppercase bg-black/50 text-white backdrop-blur-sm\">\n {getExtension(file.name)}\n </div>\n )}\n </div>\n\n {/* Name & size */}\n <div className=\"p-2.5\">\n <Typography variant=\"body2\" className=\"text-[12px] font-medium truncate text-surface-900 dark:text-white\">\n {file.name}\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\" className=\"truncate block mt-0.5 text-[11px]\">\n {file.size !== undefined ? formatFileSize(file.size) : \"—\"}\n </Typography>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div className=\"flex h-full w-full bg-white dark:bg-surface-800 overflow-hidden text-text-primary dark:text-text-primary-dark\">\n <div className=\"flex h-full w-full\">\n {/* Main content */}\n <div className=\"flex-grow flex flex-col min-w-0 h-full\">\n {/* Toolbar */}\n <div className={cls(\"flex items-center justify-between pr-2 border-b bg-white dark:bg-surface-800 shrink-0 h-10\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-1.5 flex-grow overflow-hidden px-3 py-2\">\n {/* Breadcrumbs — always visible */}\n {currentPath && (\n <Tooltip title=\"Go up\">\n <IconButton size=\"small\" onClick={handleNavigateUp}>\n <ArrowLeftIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n )}\n <div className=\"flex items-center gap-0.5 overflow-x-auto no-scrollbar\">\n {segments.map((seg, i) => (\n <React.Fragment key={seg.path}>\n {i > 0 && (\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark mx-0.5\">/</Typography>\n )}\n <Button\n variant=\"text\"\n size=\"small\"\n className={cls(\n \"px-1.5 py-0.5 min-h-0 min-w-0 h-6 text-xs whitespace-nowrap normal-case font-normal\",\n i === segments.length - 1\n ? \"text-text-primary dark:text-text-primary-dark font-medium\"\n : \"text-text-secondary dark:text-text-secondary-dark\"\n )}\n onClick={() => handleNavigate(seg.path)}\n >\n {seg.label}\n </Button>\n </React.Fragment>\n ))}\n </div>\n\n <div className=\"flex-1\"/>\n\n {/* Selection actions or file count */}\n {selectedPaths.size > 0 ? (\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <Typography variant=\"body2\" className=\"text-[13px] font-medium whitespace-nowrap\">\n {selectedPaths.size} selected\n </Typography>\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => {\n setDeleteDialogTarget(\"selection\");\n setDeleteDialogOpen(true);\n }}\n >\n <Trash2Icon size={14} className=\"mr-1\"/>\n Delete\n </Button>\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => {\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }}\n >\n <XIcon size={14} className=\"mr-1\"/>\n Deselect\n </Button>\n </div>\n ) : !loading ? (\n <Chip size=\"small\" className=\"shrink-0 text-[10px]\">\n {files.length} file{files.length !== 1 ? \"s\" : \"\"}\n {folders.length > 0 ? `, ${folders.length} folder${folders.length !== 1 ? \"s\" : \"\"}` : \"\"}\n </Chip>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center justify-end gap-1.5 pr-1\">\n\n {/* Backend picker — only shown when more than one storage source is available */}\n {sourceKeys.length > 1 && (\n <Select\n size=\"small\"\n position=\"item-aligned\"\n value={selectedSourceKey}\n onValueChange={(value) => {\n if (value) setSelectedSourceKey(value);\n }}\n renderValue={(key) => {\n const label = storageSources.registry[key]?.label;\n return label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? \"Default\" : key);\n }}>\n {sourceKeys.map((key) => (\n <SelectItem key={key} value={key}>\n {storageSources.registry[key]?.label\n ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? \"Default\" : key)}\n </SelectItem>\n ))}\n </Select>\n )}\n\n <Tooltip title=\"Grid view\">\n <IconButton\n size=\"small\"\n onClick={() => setViewMode(\"grid\")}\n className={cls(viewMode === \"grid\" && \"bg-surface-100 dark:bg-surface-800\")}\n >\n <LayoutGridIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n <Tooltip title=\"List view\">\n <IconButton\n size=\"small\"\n onClick={() => setViewMode(\"list\")}\n className={cls(viewMode === \"list\" && \"bg-surface-100 dark:bg-surface-800\")}\n >\n <ListIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n\n <div className={cls(\"h-4 w-px mx-0.5\", defaultBorderMixin, \"bg-surface-200 dark:bg-surface-700\")}/>\n\n <Tooltip title=\"Refresh\">\n <IconButton size=\"small\" onClick={handleRefresh} disabled={loading}>\n <RefreshCwIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n\n <Tooltip title=\"New folder\">\n <IconButton\n size=\"small\"\n onClick={() => {\n setNewFolderName(\"\");\n setNewFolderDialogOpen(true);\n }}\n >\n <FolderPlusIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => setUploadDialogOpen(true)}\n >\n <UploadCloudIcon size={iconSize.smallest} className=\"mr-1\"/>\n Upload\n </Button>\n </div>\n </div>\n\n {/* File grid / list — drop zone */}\n <div {...getDropRootProps()}\n className=\"flex-grow flex flex-col overflow-hidden min-h-0 relative\"\n onClick={(e) => {\n const target = e.target as HTMLElement;\n if (!target.closest(\"[data-storage-item]\") && selectedPaths.size > 0) {\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }\n }}\n >\n <input {...getDropInputProps()} />\n {renderContents()}\n {/* Drag overlay */}\n {isDragActive && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-primary/5 dark:bg-primary/10 backdrop-blur-[2px]\">\n <div className=\"flex flex-col items-center gap-2 p-6 rounded-xl border-2 border-dashed border-primary bg-white/80 dark:bg-surface-900/80\">\n <UploadCloudIcon className=\"w-10 h-10 text-primary\"/>\n <Typography variant=\"subtitle2\" className=\"text-primary font-semibold\">\n Drop files to upload\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\">\n to /{currentPath || \"root\"}\n </Typography>\n </div>\n </div>\n )}\n </div>\n\n {/* Status bar */}\n <div className={cls(\"px-4 py-1.5 border-t bg-surface-50 dark:bg-surface-800 flex items-center justify-between shrink-0\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-4 text-[11px]\">\n <span className=\"text-text-disabled dark:text-text-disabled-dark font-bold uppercase tracking-tighter\">\n Path\n </span>\n <span className=\"font-mono text-text-secondary dark:text-text-secondary-dark\">\n /{currentPath || \"\"}\n </span>\n </div>\n {selectedPaths.size > 0 ? (\n <div className=\"text-[11px] text-text-secondary dark:text-text-secondary-dark\">\n {selectedPaths.size} item{selectedPaths.size !== 1 ? \"s\" : \"\"} selected\n </div>\n ) : selectedFile ? (\n <div className=\"text-[11px] text-text-secondary dark:text-text-secondary-dark\">\n Selected: <span className=\"font-mono\">{selectedFile.name}</span>\n </div>\n ) : null}\n </div>\n </div>\n\n {/* Preview panel */}\n {selectedFile && (\n <div className=\"w-80 lg:w-96 shrink-0\">\n <FilePreviewPanel\n file={selectedFile}\n downloadUrl={selectedDownloadUrl}\n onClose={() => {\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }}\n onDelete={() => handleDeleteFile(selectedFile)}\n />\n </div>\n )}\n </div>\n\n {/* Upload Dialog */}\n <UploadDialog\n open={uploadDialogOpen}\n currentPath={currentPath}\n onClose={() => setUploadDialogOpen(false)}\n onUpload={handleUpload}\n />\n\n {/* Delete confirmation dialog */}\n <Dialog\n open={deleteDialogOpen}\n onOpenChange={(open) => {\n if (!open && !deleting) {\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }\n }}\n >\n <DialogTitle hidden>Delete Confirmation</DialogTitle>\n <DialogContent>\n <Typography variant=\"subtitle1\" className=\"font-semibold mb-2\">\n {deleteDialogTarget === \"selection\"\n ? `Delete ${selectedPaths.size} item${selectedPaths.size !== 1 ? \"s\" : \"\"}?`\n : deleteDialogTarget\n ? `Delete folder \"${deleteDialogTarget.name}\"?`\n : \"Delete?\"}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {deleteDialogTarget === \"selection\"\n ? \"This will permanently delete all selected files and folders, including their contents. This action cannot be undone.\"\n : \"This will permanently delete the folder and all of its contents. This action cannot be undone.\"}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button\n variant=\"text\"\n onClick={() => {\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }}\n disabled={deleting}\n >\n Cancel\n </Button>\n <LoadingButton\n color=\"error\"\n loading={deleting}\n onClick={deleteDialogTarget === \"selection\" ? handleBulkDelete : handleConfirmDeleteFolder}\n >\n <Trash2Icon size={14} className=\"mr-1\"/>\n Delete\n </LoadingButton>\n </DialogActions>\n </Dialog>\n\n {/* New Folder Dialog */}\n <Dialog\n open={newFolderDialogOpen}\n onOpenChange={(open) => {\n if (!open && !creatingFolder) {\n setNewFolderDialogOpen(false);\n setNewFolderName(\"\");\n }\n }}\n >\n <DialogTitle hidden>New Folder</DialogTitle>\n <DialogContent>\n <TextField\n autoFocus\n size=\"small\"\n label=\"Folder name\"\n value={newFolderName}\n onChange={(e) => setNewFolderName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && newFolderName.trim()) {\n e.preventDefault();\n handleCreateFolder();\n }\n }}\n disabled={creatingFolder}\n placeholder=\"Enter folder name\"\n />\n {currentPath && (\n <Typography variant=\"caption\" color=\"secondary\" className=\"mt-2\">\n Will be created in <span className=\"font-mono\">/{currentPath}/</span>\n </Typography>\n )}\n </DialogContent>\n <DialogActions>\n <Button\n variant=\"text\"\n onClick={() => {\n setNewFolderDialogOpen(false);\n setNewFolderName(\"\");\n }}\n disabled={creatingFolder}\n >\n Cancel\n </Button>\n <LoadingButton\n color=\"primary\"\n loading={creatingFolder}\n disabled={!newFolderName.trim()}\n onClick={handleCreateFolder}\n >\n <FolderPlusIcon size={14} className=\"mr-1\"/>\n Create\n </LoadingButton>\n </DialogActions>\n </Dialog>\n </div>\n );\n};\n"],"mappings":"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"}
package/dist/index.es.js CHANGED
@@ -552,12 +552,12 @@ function SyntaxHighlightedSnippet() {
552
552
  var SQLEditor = lazy(() => import("./SQLEditor-_dCqVAN_.js").then((m) => ({ default: m.SQLEditor })));
553
553
  var JSEditor = lazy(() => import("./JSEditor-BeHHuxhA.js").then((m) => ({ default: m.JSEditor })));
554
554
  var RLSEditor = lazy(() => import("./RLSEditor-rLlMcZPG.js").then((m) => ({ default: m.RLSEditor })));
555
- var StorageView = lazy(() => import("./StorageView-UvyM2xdW.js").then((m) => ({ default: m.StorageView })));
555
+ var StorageView = lazy(() => import("./StorageView-bRwRfwku.js").then((m) => ({ default: m.StorageView })));
556
556
  var CronJobsView = lazy(() => import("./CronJobsView-B59i3Mis.js").then((m) => ({ default: m.CronJobsView })));
557
557
  var SchemaVisualizer = lazy(() => import("./SchemaVisualizer-C_ErehfH.js").then((m) => ({ default: m.SchemaVisualizer })));
558
558
  var BranchesView = lazy(() => import("./BranchesView-DH0qnU9J.js").then((m) => ({ default: m.BranchesView })));
559
559
  var BackupsView = lazy(() => import("./BackupsView-DNS6LdVg.js").then((m) => ({ default: m.BackupsView })));
560
- var ApiExplorer = lazy(() => import("./ApiExplorer-B9M9-uy_.js").then((m) => ({ default: m.ApiExplorer })));
560
+ var ApiExplorer = lazy(() => import("./ApiExplorer-VRKWqCVI.js").then((m) => ({ default: m.ApiExplorer })));
561
561
  var LogsExplorer = lazy(() => import("./LogsExplorer-BCXoGREr.js").then((m) => ({ default: m.LogsExplorer })));
562
562
  var ApiKeysView = lazy(() => import("./ApiKeysView-vQKqt2wl.js").then((m) => ({ default: m.ApiKeysView })));
563
563
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/studio",
3
3
  "type": "module",
4
- "version": "0.10.0",
4
+ "version": "0.10.1-canary.14e53ae",
5
5
  "main": "./dist/index.es.js",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "./dist/index.d.ts",
@@ -15,19 +15,19 @@
15
15
  "pgsql-ast-parser": "12.0.2",
16
16
  "prism-react-renderer": "^2.4.1",
17
17
  "react-dropzone": "^15.0.0",
18
- "@rebasepro/client": "0.10.0",
19
- "@rebasepro/app": "0.10.0",
20
- "@rebasepro/types": "0.10.0",
21
- "@rebasepro/common": "0.10.0",
22
- "@rebasepro/ui": "0.10.0",
23
- "@rebasepro/utils": "0.10.0"
18
+ "@rebasepro/client": "0.10.1-canary.14e53ae",
19
+ "@rebasepro/app": "0.10.1-canary.14e53ae",
20
+ "@rebasepro/common": "0.10.1-canary.14e53ae",
21
+ "@rebasepro/types": "0.10.1-canary.14e53ae",
22
+ "@rebasepro/utils": "0.10.1-canary.14e53ae",
23
+ "@rebasepro/ui": "0.10.1-canary.14e53ae"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "react": ">=19.0.0",
27
27
  "react-dom": ">=19.0.0",
28
28
  "react-router": "^7.0.0",
29
29
  "react-router-dom": "^7.0.0",
30
- "@rebasepro/admin": "0.10.0"
30
+ "@rebasepro/admin": "0.10.1-canary.14e53ae"
31
31
  },
32
32
  "peerDependenciesMeta": {
33
33
  "@rebasepro/admin": {
@@ -43,7 +43,13 @@ export function ApiExplorer() {
43
43
 
44
44
  (async () => {
45
45
  try {
46
- const res = await fetch(specUrl);
46
+ // The spec endpoint itself is public on a stock backend, but
47
+ // `apiUrl` may route through an authenticated proxy (the
48
+ // console's Studio embed) — carry the token like every other
49
+ // request in this view, and like LogsExplorer does.
50
+ const getAuthToken = apiConfig?.getAuthToken ?? authController.getAuthToken;
51
+ const token = getAuthToken ? await getAuthToken() : null;
52
+ const res = await fetch(specUrl, token ? { headers: { Authorization: `Bearer ${token}` } } : undefined);
47
53
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
48
54
  const data = await res.json();
49
55
  if (!cancelled) {
@@ -60,7 +66,7 @@ export function ApiExplorer() {
60
66
  return () => {
61
67
  cancelled = true;
62
68
  };
63
- }, [apiUrl]);
69
+ }, [apiUrl, apiConfig, authController]);
64
70
 
65
71
  // Parse spec into grouped endpoints
66
72
  const { groups, allEndpoints } = useMemo(() => {
@@ -64,6 +64,15 @@ interface StorageFile {
64
64
  // Helpers
65
65
  // ──────────────────────────────────────────────
66
66
 
67
+ /**
68
+ * The query parameter holding the folder being browsed.
69
+ *
70
+ * Namespaced because Studio does not always own the URL it renders under: the
71
+ * SaaS console embeds this view in a page that keeps its own state in `?tab=`
72
+ * and `?sub=`, and a bare `path` is a name any host app might already be using.
73
+ */
74
+ const STORAGE_PATH_PARAM = "storagePath";
75
+
67
76
  function formatFileSize(bytes: number): string {
68
77
  if (bytes < 1024) return `${bytes} B`;
69
78
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -489,7 +498,9 @@ export const StorageView = () => {
489
498
 
490
499
  // Navigation
491
500
  const [searchParams, setSearchParams] = useSearchParams();
492
- const currentPath = searchParams.get("path") || "";
501
+ // Accepts the historical unqualified `path` so links already shared keep
502
+ // working; only the namespaced one is ever written.
503
+ const currentPath = searchParams.get(STORAGE_PATH_PARAM) || searchParams.get("path") || "";
493
504
  const [loading, setLoading] = useState(true);
494
505
  const [error, setError] = useState<string | null>(null);
495
506
 
@@ -580,12 +591,21 @@ export const StorageView = () => {
580
591
  }, [currentPath, fetchContents, selectedSourceKey]);
581
592
 
582
593
  // Navigate to path
594
+ //
595
+ // Updates only this view's own parameter and leaves the rest of the query
596
+ // string alone. It used to assign the whole thing (`setSearchParams({})`),
597
+ // which is fine when Studio owns the URL but destructive when it is
598
+ // embedded: the SaaS console keeps the open tab in `?tab=`, so opening a
599
+ // folder erased it and bounced the user out of Storage entirely. The key is
600
+ // namespaced for the same reason — a bare `path` is a name a host app can
601
+ // easily be using for something else.
583
602
  const handleNavigate = useCallback((path: string) => {
584
- if (!path) {
585
- setSearchParams({});
586
- } else {
587
- setSearchParams({ path });
588
- }
603
+ setSearchParams(prev => {
604
+ const next = new URLSearchParams(prev);
605
+ if (path) next.set(STORAGE_PATH_PARAM, path);
606
+ else next.delete(STORAGE_PATH_PARAM);
607
+ return next;
608
+ }, { replace: true });
589
609
  setSelectedFile(null);
590
610
  setSelectedDownloadUrl(null);
591
611
  setSelectedPaths(new Set());
@@ -1 +0,0 @@
1
- {"version":3,"file":"StorageView-UvyM2xdW.js","names":[],"sources":["../src/components/StorageView/StorageView.tsx"],"sourcesContent":["\nimport React, { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport {\n ArrowLeftIcon,\n Button,\n Checkbox,\n CheckIcon,\n Chip,\n CircularProgress,\n cls,\n CopyIcon,\n defaultBorderMixin,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n DownloadIcon,\n FileIcon,\n FileTextIcon,\n FileUpload,\n FolderIcon,\n FolderPlusIcon,\n HomeIcon,\n IconButton,\n iconSize,\n ImageIcon,\n LayoutGridIcon,\n ListIcon,\n LoadingButton,\n Music2Icon,\n PlusIcon,\n RefreshCwIcon,\n ResizablePanels,\n Select,\n SelectItem,\n TextField,\n Tooltip,\n Trash2Icon,\n Typography,\n UploadCloudIcon,\n VideoIcon,\n XIcon\n} from \"@rebasepro/ui\";\nimport { useStorageSource, useStorageSources, useSnackbarController, ErrorView, useApiConfig } from \"@rebasepro/app\";\nimport { DEFAULT_STORAGE_SOURCE_KEY, type StorageListResult } from \"@rebasepro/types\";\nimport { useSearchParams } from \"react-router-dom\";\nimport { useDropzone } from \"react-dropzone\";\n\n// ──────────────────────────────────────────────\n// Types\n// ──────────────────────────────────────────────\n\ninterface StorageFile {\n name: string;\n fullPath: string;\n isFolder: boolean;\n /** Only populated when metadata is fetched */\n size?: number;\n contentType?: string;\n downloadUrl?: string;\n}\n\n// ──────────────────────────────────────────────\n// Helpers\n// ──────────────────────────────────────────────\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\nfunction getFileIcon(contentType?: string) {\n if (!contentType) return FileTextIcon;\n if (contentType.startsWith(\"image/\")) return ImageIcon;\n if (contentType.startsWith(\"video/\")) return VideoIcon;\n if (contentType.startsWith(\"audio/\")) return Music2Icon;\n return FileTextIcon;\n}\n\nfunction getExtension(name: string): string {\n const parts = name.split(\".\");\n return parts.length > 1 ? parts[parts.length - 1].toUpperCase() : \"\";\n}\n\nfunction breadcrumbSegments(path: string): { label: string; path: string }[] {\n if (!path || path === \"/\") return [{ label: \"Root\",\npath: \"\" }];\n const parts = path.split(\"/\").filter(Boolean);\n const segments = [{ label: \"Root\",\npath: \"\" }];\n let accumulated = \"\";\n for (const part of parts) {\n accumulated = accumulated ? `${accumulated}/${part}` : part;\n segments.push({ label: part,\npath: accumulated });\n }\n return segments;\n}\n\n// ──────────────────────────────────────────────\n// Upload Dialog\n// ──────────────────────────────────────────────\n\nfunction UploadDialog({\n open,\n currentPath,\n onClose,\n onUpload\n}: {\n open: boolean;\n currentPath: string;\n onClose: () => void;\n onUpload: (files: File[]) => Promise<void>;\n}) {\n const [uploading, setUploading] = useState(false);\n const [selectedFiles, setSelectedFiles] = useState<File[]>([]);\n const [error, setError] = useState<string | null>(null);\n\n const handleFilesAdded = useCallback((files: File[]) => {\n setSelectedFiles(prev => [...prev, ...files]);\n }, []);\n\n const handleRemoveFile = useCallback((index: number) => {\n setSelectedFiles(prev => prev.filter((_, i) => i !== index));\n }, []);\n\n const handleUpload = useCallback(async () => {\n if (selectedFiles.length === 0) return;\n setUploading(true);\n setError(null);\n try {\n await onUpload(selectedFiles);\n setSelectedFiles([]);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Upload failed\");\n } finally {\n setUploading(false);\n }\n }, [selectedFiles, onUpload, onClose]);\n\n const handleClose = useCallback(() => {\n if (!uploading) {\n setSelectedFiles([]);\n setError(null);\n onClose();\n }\n }, [uploading, onClose]);\n\n return (\n <Dialog open={open} onOpenChange={(o) => !o && handleClose()} maxWidth=\"md\">\n <DialogTitle>\n Upload Files\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark mt-0.5 block\">\n to <span className=\"font-mono text-primary\">/{currentPath || \"root\"}</span>\n </Typography>\n </DialogTitle>\n <DialogContent className=\"space-y-4\">\n <FileUpload\n onFilesAdded={handleFilesAdded}\n size=\"large\"\n uploadDescription={\n <div className=\"flex flex-col items-center justify-center pointer-events-none\">\n <UploadCloudIcon className=\"text-surface-accent-400 mb-2 w-8 h-8\"/>\n <Typography variant=\"label\">\n Drop files here or click to browse\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\">\n Any file type supported\n </Typography>\n </div>\n }\n />\n\n {error && (\n <Typography variant=\"caption\" className=\"text-red-500 block whitespace-pre-line\">\n {error}\n </Typography>\n )}\n\n {selectedFiles.length > 0 && (\n <div className=\"space-y-2\">\n <Typography variant=\"caption\" color=\"secondary\">\n Selected files ({selectedFiles.length})\n </Typography>\n <div className=\"max-h-40 overflow-auto space-y-1\">\n {selectedFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center justify-between p-2 rounded bg-surface-100 dark:bg-surface-800\"\n >\n <div className=\"flex-1 min-w-0 mr-2\">\n <Typography variant=\"body2\" className=\"truncate\">\n {file.name}\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\">\n {formatFileSize(file.size)}\n </Typography>\n </div>\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n handleRemoveFile(index);\n }}\n disabled={uploading}\n >\n <XIcon size={14}/>\n </IconButton>\n </div>\n ))}\n </div>\n </div>\n )}\n </DialogContent>\n\n <DialogActions>\n <Button variant=\"text\" onClick={handleClose} disabled={uploading}>\n Cancel\n </Button>\n <Button\n variant=\"filled\"\n onClick={handleUpload}\n disabled={selectedFiles.length === 0 || uploading}\n startIcon={uploading ? <CircularProgress size=\"smallest\"/> : <UploadCloudIcon size={14}/>}\n >\n {uploading ? \"Uploading...\" : `Upload${selectedFiles.length > 0 ? ` (${selectedFiles.length})` : \"\"}`}\n </Button>\n </DialogActions>\n </Dialog>\n );\n}\n\n// ──────────────────────────────────────────────\n// FileIcon preview panel\n// ──────────────────────────────────────────────\n\nfunction FilePreviewPanel({\n file,\n onClose,\n onDelete,\n downloadUrl\n}: {\n file: StorageFile;\n onClose: () => void;\n onDelete: () => void;\n downloadUrl: string | null;\n}) {\n const isImage = file.contentType?.startsWith(\"image/\");\n const isVideo = file.contentType?.startsWith(\"video/\");\n const isAudio = file.contentType?.startsWith(\"audio/\");\n const FileIconComponent = getFileIcon(file.contentType);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [urlCopied, setUrlCopied] = useState(false);\n\n return (\n <>\n <div className={cls(\n \"flex flex-col h-full border-l\",\n defaultBorderMixin,\n \"bg-white dark:bg-surface-800\"\n )}>\n {/* Header */}\n <div className={cls(\"flex items-center justify-between p-3 border-b shrink-0\", defaultBorderMixin)}>\n <Typography variant=\"body2\" className=\"font-medium truncate flex-1 mr-2\">\n {file.name}\n </Typography>\n <div className=\"flex items-center gap-0.5\">\n {downloadUrl && (\n <Tooltip title=\"Download\">\n <IconButton\n size=\"small\"\n onClick={() => window.open(downloadUrl, \"_blank\")}\n >\n <DownloadIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n )}\n <Tooltip title=\"Delete\">\n <IconButton\n size=\"small\"\n onClick={() => setDeleteDialogOpen(true)}\n className=\"text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20\"\n >\n <Trash2Icon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n <IconButton size=\"small\" onClick={onClose}>\n <XIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n </div>\n\n {/* Preview */}\n <div className=\"flex-1 overflow-auto\">\n <div className={cls(\"flex flex-col items-center justify-center min-h-[200px] p-4 bg-surface-50 dark:bg-surface-800 border-b\", defaultBorderMixin)}>\n {(() => {\n const ext = getExtension(file.name)?.toLowerCase() || \"\";\n const isImage = file.contentType?.startsWith(\"image/\") || [\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"svg\"].includes(ext);\n const isVideo = file.contentType?.startsWith(\"video/\") || [\"mp4\", \"webm\", \"ogg\", \"mov\"].includes(ext);\n const isAudio = file.contentType?.startsWith(\"audio/\") || [\"mp3\", \"wav\", \"ogg\", \"m4a\"].includes(ext);\n const downloadUrl = file.downloadUrl;\n\n if (isImage && downloadUrl) {\n return (\n <img\n src={downloadUrl}\n alt={file.name}\n className=\"max-w-full max-h-[400px] object-contain rounded-md shadow-sm\"\n />\n );\n } else if (isVideo && downloadUrl) {\n return (\n <video\n src={downloadUrl}\n className=\"max-w-full max-h-[400px] rounded-md\"\n controls\n />\n );\n } else if (isAudio && downloadUrl) {\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Music2Icon className=\"text-surface-accent-400 w-10 h-10\"/>\n <audio src={downloadUrl} controls className=\"w-full max-w-xs\"/>\n </div>\n );\n } else {\n return (\n <div className=\"flex flex-col items-center gap-3 text-surface-accent-400\">\n <FileIconComponent className=\"w-10 h-10\"/>\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark\">\n No preview available\n </Typography>\n </div>\n );\n }\n })()}\n </div>\n </div>\n\n {/* Metadata */}\n <div className=\"p-4 space-y-3\">\n <div>\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark text-[10px] uppercase tracking-wider font-bold mb-1 block\">\n File Info\n </Typography>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Name\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px] break-all\">\n {file.name}\n </Typography>\n </div>\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Type\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px]\">\n {file.contentType || \"Unknown\"}\n </Typography>\n </div>\n {file.size !== undefined && (\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Size\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px]\">\n {formatFileSize(file.size)}\n </Typography>\n </div>\n )}\n <div>\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Extension\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px] font-mono\">\n {getExtension(file.name) || \"—\"}\n </Typography>\n </div>\n <div className=\"col-span-2\">\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px]\">\n Path\n </Typography>\n <Typography variant=\"body2\" className=\"text-[13px] font-mono break-all\">\n {file.fullPath}\n </Typography>\n </div>\n </div>\n\n {downloadUrl && (\n <div className=\"pt-2\">\n <Typography variant=\"caption\" className=\"text-surface-accent-500 text-[11px] block mb-1\">\n URL\n </Typography>\n <div\n className={cls(\n \"flex items-center gap-2 p-2 rounded cursor-pointer transition-colors\",\n \"bg-surface-100 dark:bg-surface-800 hover:bg-surface-200 dark:hover:bg-surface-700\"\n )}\n onClick={() => {\n const fullUrl = downloadUrl.startsWith(\"http\")\n ? downloadUrl\n : `${window.location.origin}${downloadUrl.startsWith(\"/\") ? \"\" : \"/\"}${downloadUrl}`;\n navigator.clipboard.writeText(fullUrl).then(() => {\n setUrlCopied(true);\n setTimeout(() => setUrlCopied(false), 2000);\n });\n }}\n >\n <Typography variant=\"caption\" className=\"font-mono text-[11px] truncate flex-1 min-w-0 text-primary\">\n {(() => {\n const fullUrl = downloadUrl.startsWith(\"http\")\n ? downloadUrl\n : `${window.location.origin}${downloadUrl.startsWith(\"/\") ? \"\" : \"/\"}${downloadUrl}`;\n return fullUrl;\n })()}\n </Typography>\n <Tooltip title={urlCopied ? \"Copied!\" : \"Copy URL\"}>\n <div className=\"shrink-0\">\n {urlCopied\n ? <CheckIcon size={14} className=\"text-green-500\"/>\n : <CopyIcon size={14} className=\"text-surface-accent-400\"/>\n }\n </div>\n </Tooltip>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Delete Confirmation */}\n <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <DialogTitle hidden>Delete File</DialogTitle>\n <DialogContent>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n Delete File?\n </Typography>\n <Typography className=\"text-surface-accent-600 dark:text-surface-accent-400\">\n Are you sure you want to delete &quot;{file.name}&quot;?\n This action cannot be undone.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button variant=\"text\" onClick={() => setDeleteDialogOpen(false)}>\n Cancel\n </Button>\n <Button\n variant=\"filled\"\n color=\"error\"\n onClick={() => {\n setDeleteDialogOpen(false);\n onDelete();\n }}\n >\n Delete\n </Button>\n </DialogActions>\n </Dialog>\n </>\n );\n}\n\n// ──────────────────────────────────────────────\n// Main StorageView Export\n// ──────────────────────────────────────────────\n\nexport const StorageView = () => {\n const defaultStorageSource = useStorageSource();\n const storageSources = useStorageSources();\n const snackbarController = useSnackbarController();\n\n // Available backends to browse. Always includes the default; named\n // sources come from `<Rebase storageSources={...}>`.\n const sourceKeys = useMemo(() => {\n const keys = Object.keys(storageSources.sources);\n if (!keys.includes(DEFAULT_STORAGE_SOURCE_KEY)) keys.unshift(DEFAULT_STORAGE_SOURCE_KEY);\n return keys;\n }, [storageSources.sources]);\n\n const [selectedSourceKey, setSelectedSourceKey] = useState<string>(DEFAULT_STORAGE_SOURCE_KEY);\n\n const storageSource = storageSources.sources[selectedSourceKey] ?? defaultStorageSource;\n\n // Navigation\n const [searchParams, setSearchParams] = useSearchParams();\n const currentPath = searchParams.get(\"path\") || \"\";\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n // Contents\n const [folders, setFolders] = useState<StorageFile[]>([]);\n const [files, setFiles] = useState<StorageFile[]>([]);\n\n // Selection and preview\n const [selectedFile, setSelectedFile] = useState<StorageFile | null>(null);\n const [selectedDownloadUrl, setSelectedDownloadUrl] = useState<string | null>(null);\n\n // Upload\n const [uploadDialogOpen, setUploadDialogOpen] = useState(false);\n\n // View mode\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n\n // Multi-selection\n const [selectedPaths, setSelectedPaths] = useState<Set<string>>(new Set());\n const lastClickedRef = useRef<string | null>(null);\n\n // Bulk / folder delete\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [deleteDialogTarget, setDeleteDialogTarget] = useState<\"selection\" | StorageFile | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n // New folder\n const [newFolderDialogOpen, setNewFolderDialogOpen] = useState(false);\n const [newFolderName, setNewFolderName] = useState(\"\");\n const [creatingFolder, setCreatingFolder] = useState(false);\n const apiConfig = useApiConfig();\n\n const storageSourceRef = React.useRef(storageSource);\n useEffect(() => {\n storageSourceRef.current = storageSource;\n }, [storageSource]);\n\n // ── Fetch directory contents ──\n const fetchContents = useCallback(async (path: string) => {\n setLoading(true);\n setError(null);\n try {\n const result: StorageListResult = await storageSourceRef.current.listObjects(path);\n\n const folderItems: StorageFile[] = (result.prefixes ?? []).map(ref => ({\n name: ref.name,\n fullPath: ref.fullPath,\n isFolder: true\n }));\n\n // Build file items and fetch metadata for each\n const fileItems: StorageFile[] = await Promise.all(\n (result.items ?? []).map(async (ref) => {\n try {\n const downloadConfig = await storageSourceRef.current.getSignedUrl(ref.fullPath);\n return {\n name: ref.name,\n fullPath: ref.fullPath,\n isFolder: false,\n size: downloadConfig.metadata?.size,\n contentType: downloadConfig.metadata?.contentType,\n downloadUrl: downloadConfig.url ?? undefined\n };\n } catch {\n return {\n name: ref.name,\n fullPath: ref.fullPath,\n isFolder: false\n };\n }\n })\n );\n\n setFolders(folderItems);\n setFiles(fileItems);\n } catch (e) {\n console.error(\"Storage list error:\", e);\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n // `selectedSourceKey` is a dep so switching backend re-lists; the\n // ref-sync effect above runs first, so `storageSourceRef` is current.\n fetchContents(currentPath);\n }, [currentPath, fetchContents, selectedSourceKey]);\n\n // Navigate to path\n const handleNavigate = useCallback((path: string) => {\n if (!path) {\n setSearchParams({});\n } else {\n setSearchParams({ path });\n }\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n setSelectedPaths(new Set());\n lastClickedRef.current = null;\n }, [setSearchParams]);\n\n // Navigate up one level\n const handleNavigateUp = useCallback(() => {\n const parts = currentPath.split(\"/\").filter(Boolean);\n parts.pop();\n handleNavigate(parts.join(\"/\"));\n }, [currentPath, handleNavigate]);\n\n // All items (folders + files) in display order, for shift-range select\n const allItems = useMemo(() => [...folders, ...files], [folders, files]);\n\n // ── Multi-select click handler ──\n const handleItemClick = useCallback((item: StorageFile, e: React.MouseEvent) => {\n const path = item.fullPath;\n if (e.metaKey || e.ctrlKey) {\n // Toggle individual item\n setSelectedPaths(prev => {\n const next = new Set(prev);\n if (next.has(path)) next.delete(path);\n else next.add(path);\n return next;\n });\n lastClickedRef.current = path;\n } else if (e.shiftKey && lastClickedRef.current) {\n // Range select\n const allPaths = allItems.map(i => i.fullPath);\n const anchorIdx = allPaths.indexOf(lastClickedRef.current);\n const currentIdx = allPaths.indexOf(path);\n if (anchorIdx >= 0 && currentIdx >= 0) {\n const [start, end] = anchorIdx < currentIdx ? [anchorIdx, currentIdx] : [currentIdx, anchorIdx];\n setSelectedPaths(prev => {\n const next = new Set(prev);\n for (let i = start; i <= end; i++) next.add(allPaths[i]);\n return next;\n });\n }\n } else {\n // Exclusive select\n setSelectedPaths(new Set([path]));\n lastClickedRef.current = path;\n // Also open preview if it's a file\n if (!item.isFolder) {\n setSelectedFile(item);\n if (item.downloadUrl) {\n setSelectedDownloadUrl(item.downloadUrl);\n } else {\n storageSourceRef.current.getSignedUrl(item.fullPath)\n .then(config => setSelectedDownloadUrl(config.url))\n .catch(() => setSelectedDownloadUrl(null));\n }\n } else {\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }\n }\n }, [allItems]);\n\n // Double-click: open folder or preview file\n const handleItemDoubleClick = useCallback((item: StorageFile) => {\n if (item.isFolder) {\n handleNavigate(item.fullPath);\n } else {\n setSelectedFile(item);\n if (item.downloadUrl) {\n setSelectedDownloadUrl(item.downloadUrl);\n } else {\n storageSourceRef.current.getSignedUrl(item.fullPath)\n .then(config => setSelectedDownloadUrl(config.url))\n .catch(() => setSelectedDownloadUrl(null));\n }\n }\n }, [handleNavigate]);\n\n // Upload files\n const handleUpload = useCallback(async (uploadFiles: File[]) => {\n for (const file of uploadFiles) {\n const key = currentPath ? `${currentPath}/${file.name}` : file.name;\n await storageSourceRef.current.putObject({\n file,\n key\n });\n }\n snackbarController.open({\n type: \"success\",\n message: `${uploadFiles.length} file${uploadFiles.length > 1 ? \"s\" : \"\"} uploaded successfully`\n });\n await fetchContents(currentPath);\n }, [currentPath, snackbarController, fetchContents]);\n\n // Create new folder\n const handleCreateFolder = useCallback(async () => {\n if (!newFolderName.trim() || !apiConfig?.apiUrl) return;\n\n // Validate folder name\n const name = newFolderName.trim();\n if (name.includes(\"/\") || name.includes(\"\\\\\")) {\n snackbarController.open({ type: \"error\",\nmessage: \"Folder name cannot contain slashes\" });\n return;\n }\n\n // Check if folder already exists\n const existingFolder = folders.find(f => f.name === name);\n if (existingFolder) {\n snackbarController.open({ type: \"error\",\nmessage: `Folder \"${name}\" already exists` });\n return;\n }\n\n setCreatingFolder(true);\n try {\n const folderPath = currentPath ? `default/${currentPath}/${name}` : `default/${name}`;\n const token = apiConfig.getAuthToken ? await apiConfig.getAuthToken() : null;\n const response = await fetch(`${apiConfig.apiUrl}/api/storage/folder`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { \"Authorization\": `Bearer ${token}` } : {})\n },\n body: JSON.stringify({ path: folderPath })\n });\n\n if (!response.ok) {\n const err = await response.json().catch(() => ({ error: \"Failed to create folder\" }));\n throw new Error(err.error || \"Failed to create folder\");\n }\n\n snackbarController.open({ type: \"success\",\nmessage: `Folder \"${name}\" created` });\n setNewFolderDialogOpen(false);\n setNewFolderName(\"\");\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally {\n setCreatingFolder(false);\n }\n }, [newFolderName, currentPath, apiConfig, snackbarController, fetchContents, folders]);\n\n // Drag-and-drop on main view\n const handleDropFiles = useCallback(async (droppedFiles: File[]) => {\n if (droppedFiles.length === 0) return;\n try {\n for (const file of droppedFiles) {\n const key = currentPath ? `${currentPath}/${file.name}` : file.name;\n await storageSourceRef.current.putObject({ file,\nkey });\n }\n snackbarController.open({\n type: \"success\",\n message: `${droppedFiles.length} file${droppedFiles.length > 1 ? \"s\" : \"\"} uploaded successfully`\n });\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n }\n }, [currentPath, snackbarController, fetchContents]);\n\n const {\n getRootProps: getDropRootProps,\n getInputProps: getDropInputProps,\n isDragActive\n } = useDropzone({\n onDrop: handleDropFiles,\n noClick: true,\n noKeyboard: true,\n noDragEventsBubbling: true\n });\n\n // ── Recursive folder delete helper ──\n const deleteFolderRecursive = useCallback(async (prefix: string) => {\n const result = await storageSourceRef.current.listObjects(prefix);\n // Delete all files in this level\n for (const item of result.items ?? []) {\n await storageSourceRef.current.deleteObject(item.fullPath);\n }\n // Recurse into sub-folders\n for (const sub of result.prefixes ?? []) {\n await deleteFolderRecursive(sub.fullPath);\n }\n // Delete the folder entry itself (needed for local filesystem)\n try {\n await storageSourceRef.current.deleteObject(prefix);\n } catch {\n // Ignore — S3 folders are virtual and may not exist as objects\n }\n }, []);\n\n // Delete a single file\n const handleDeleteFile = useCallback(async (file: StorageFile) => {\n try {\n if (file.isFolder) {\n await deleteFolderRecursive(file.fullPath);\n } else {\n await storageSourceRef.current.deleteObject(file.fullPath);\n }\n snackbarController.open({ type: \"success\",\nmessage: `\"${file.name}\" deleted` });\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n setSelectedPaths(prev => {\n const next = new Set(prev);\n next.delete(file.fullPath);\n return next;\n });\n fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n }, [currentPath, snackbarController, fetchContents, deleteFolderRecursive]);\n\n // Bulk delete (selected items)\n const handleBulkDelete = useCallback(async () => {\n setDeleting(true);\n try {\n const items = allItems.filter(i => selectedPaths.has(i.fullPath));\n for (const item of items) {\n if (item.isFolder) {\n await deleteFolderRecursive(item.fullPath);\n } else {\n await storageSourceRef.current.deleteObject(item.fullPath);\n }\n }\n snackbarController.open({ type: \"success\",\nmessage: `${items.length} item${items.length !== 1 ? \"s\" : \"\"} deleted` });\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }\n }, [allItems, selectedPaths, currentPath, snackbarController, fetchContents, deleteFolderRecursive]);\n\n // Confirm delete for a single folder\n const handleConfirmDeleteFolder = useCallback(async () => {\n if (!deleteDialogTarget || deleteDialogTarget === \"selection\") return;\n setDeleting(true);\n try {\n await deleteFolderRecursive(deleteDialogTarget.fullPath);\n snackbarController.open({ type: \"success\",\nmessage: `Folder \"${deleteDialogTarget.name}\" deleted` });\n setSelectedPaths(prev => {\n const next = new Set(prev);\n next.delete(deleteDialogTarget.fullPath);\n return next;\n });\n await fetchContents(currentPath);\n } catch (e) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }\n }, [deleteDialogTarget, currentPath, snackbarController, fetchContents, deleteFolderRecursive]);\n\n // Select all / deselect\n const handleSelectAll = useCallback(() => {\n if (selectedPaths.size === allItems.length) {\n setSelectedPaths(new Set());\n } else {\n setSelectedPaths(new Set(allItems.map(i => i.fullPath)));\n }\n }, [allItems, selectedPaths]);\n\n // ── Keyboard shortcuts ──\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n // Don't handle shortcuts when a dialog is open\n if (deleteDialogOpen || uploadDialogOpen || newFolderDialogOpen) return;\n // Cmd/Ctrl+A: select all\n if ((e.metaKey || e.ctrlKey) && e.key === \"a\") {\n e.preventDefault();\n handleSelectAll();\n }\n // Escape: deselect\n if (e.key === \"Escape\") {\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }\n // Delete / Backspace: delete selected\n if ((e.key === \"Delete\" || e.key === \"Backspace\") && selectedPaths.size > 0 && !e.metaKey && !e.ctrlKey) {\n // Don't trigger if user is typing in an input\n if ((e.target as HTMLElement)?.tagName === \"INPUT\" || (e.target as HTMLElement)?.tagName === \"TEXTAREA\") return;\n e.preventDefault();\n setDeleteDialogTarget(\"selection\");\n setDeleteDialogOpen(true);\n }\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [handleSelectAll, selectedPaths, deleteDialogOpen, uploadDialogOpen, newFolderDialogOpen]);\n\n // Handle refresh\n const handleRefresh = useCallback(() => {\n fetchContents(currentPath);\n }, [currentPath, fetchContents]);\n\n const segments = breadcrumbSegments(currentPath);\n\n\n // ── Render file grid/list ──\n const renderContents = () => {\n if (loading) {\n return (\n <div className=\"flex-grow flex items-center justify-center\">\n <div className=\"text-center\">\n <CircularProgress size=\"medium\"/>\n <Typography variant=\"body2\" className=\"mt-4 text-text-secondary dark:text-text-secondary-dark font-mono tracking-tight animate-pulse\">\n Loading...\n </Typography>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex-grow flex items-center justify-center p-6 overflow-auto\">\n <ErrorView title=\"Error loading storage\" error={error} onRetry={handleRefresh}/>\n </div>\n );\n }\n\n\n if (allItems.length === 0) {\n return (\n <div className=\"flex-grow flex items-center justify-center text-text-disabled dark:text-text-disabled-dark\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-4 opacity-50\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1} d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\"/>\n </svg>\n <Typography variant=\"body2\">\n This folder is empty\n </Typography>\n <div className=\"flex items-center gap-2 mt-3\">\n <Button variant=\"text\" onClick={() => {\n setNewFolderName(\"\");\n setNewFolderDialogOpen(true);\n }}>\n <FolderPlusIcon size={iconSize.smallest}/>\n New folder\n </Button>\n <Button onClick={() => setUploadDialogOpen(true)}>\n <PlusIcon size={iconSize.smallest}/>\n Upload files\n </Button>\n </div>\n </div>\n </div>\n );\n }\n\n if (viewMode === \"list\") {\n return (\n <div className=\"flex-grow overflow-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className={cls(\"border-b text-left text-[10px] uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark\", defaultBorderMixin)}>\n <th className=\"pl-3 pr-0 py-2 w-8\">\n <Checkbox\n size=\"small\"\n checked={allItems.length > 0 && selectedPaths.size === allItems.length}\n indeterminate={selectedPaths.size > 0 && selectedPaths.size < allItems.length}\n onCheckedChange={handleSelectAll}\n />\n </th>\n <th className=\"px-2 py-2 font-bold\">Name</th>\n <th className=\"px-4 py-2 font-bold w-24\">Type</th>\n <th className=\"px-4 py-2 font-bold w-24 text-right\">Size</th>\n <th className=\"px-2 py-2 w-10\"/>\n </tr>\n </thead>\n <tbody>\n {folders.map(folder => {\n const isChecked = selectedPaths.has(folder.fullPath);\n return (\n <tr\n key={folder.fullPath}\n data-storage-item\n className={cls(\n \"cursor-pointer transition-colors border-b group\",\n defaultBorderMixin,\n isChecked\n ? \"bg-primary/5 dark:bg-primary/10\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-800\"\n )}\n onClick={(e) => handleItemClick(folder, e)}\n onDoubleClick={() => handleItemDoubleClick(folder)}\n >\n <td className=\"pl-3 pr-0 py-2.5\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n size=\"small\"\n checked={isChecked}\n onCheckedChange={() => {\n setSelectedPaths(prev => {\n const next = new Set(prev);\n if (next.has(folder.fullPath)) next.delete(folder.fullPath);\n else next.add(folder.fullPath);\n return next;\n });\n }}\n />\n </td>\n <td className=\"px-2 py-2.5\">\n <div className=\"flex items-center gap-2\">\n <FolderIcon size={iconSize.smallest} className=\"text-amber-500 dark:text-amber-400 shrink-0\"/>\n <Typography variant=\"body2\" className=\"text-[13px] font-medium truncate\">\n {folder.name}\n </Typography>\n </div>\n </td>\n <td className=\"px-4 py-2.5\">\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n Folder\n </Typography>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark\">\n —\n </Typography>\n </td>\n <td className=\"px-2 py-2.5\"/>\n </tr>\n );\n })}\n {files.map(file => {\n const FileIconComp = getFileIcon(file.contentType);\n const isChecked = selectedPaths.has(file.fullPath);\n return (\n <tr\n key={file.fullPath}\n data-storage-item\n className={cls(\n \"cursor-pointer transition-colors border-b group\",\n defaultBorderMixin,\n isChecked\n ? \"bg-primary/5 dark:bg-primary/10\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-800\"\n )}\n onClick={(e) => handleItemClick(file, e)}\n onDoubleClick={() => handleItemDoubleClick(file)}\n >\n <td className=\"pl-3 pr-0 py-2.5\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n size=\"small\"\n checked={isChecked}\n onCheckedChange={() => {\n setSelectedPaths(prev => {\n const next = new Set(prev);\n if (next.has(file.fullPath)) next.delete(file.fullPath);\n else next.add(file.fullPath);\n return next;\n });\n }}\n />\n </td>\n <td className=\"px-2 py-2.5\">\n <div className=\"flex items-center gap-2\">\n <FileIconComp size={iconSize.smallest} className=\"text-surface-accent-400 shrink-0\"/>\n <Typography variant=\"body2\" className=\"text-[13px] truncate\">\n {file.name}\n </Typography>\n </div>\n </td>\n <td className=\"px-4 py-2.5\">\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {getExtension(file.name) || file.contentType?.split(\"/\")[1]?.toUpperCase() || \"—\"}\n </Typography>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark font-mono text-[11px]\">\n {file.size !== undefined ? formatFileSize(file.size) : \"—\"}\n </Typography>\n </td>\n <td className=\"px-2 py-2.5\" onClick={(e) => e.stopPropagation()}>\n <IconButton\n size=\"smallest\"\n className=\"opacity-0 group-hover:opacity-100 transition-opacity\"\n onClick={() => handleDeleteFile(file)}\n >\n <Trash2Icon size={14}/>\n </IconButton>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n }\n\n // Grid view\n return (\n <div className=\"flex-grow overflow-auto p-4\">\n {/* Folder cards */}\n {folders.length > 0 && (\n <div className=\"mb-4\">\n <Typography variant=\"caption\" className=\"text-[10px] uppercase tracking-wider font-bold text-text-disabled dark:text-text-disabled-dark mb-2 block\">\n Folders\n </Typography>\n <div className=\"grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]\">\n {folders.map(folder => {\n const isChecked = selectedPaths.has(folder.fullPath);\n return (\n <div\n key={folder.fullPath}\n data-storage-item\n className={cls(\n \"rounded-lg p-3 cursor-pointer border\",\n \"transition-colors duration-150\",\n defaultBorderMixin,\n \"hover:bg-surface-100 dark:hover:bg-surface-800 hover:shadow-sm\",\n \"flex items-center gap-2\",\n isChecked && \"ring-2 ring-primary bg-primary/5 dark:bg-primary/10\"\n )}\n onClick={(e) => handleItemClick(folder, e)}\n onDoubleClick={() => handleItemDoubleClick(folder)}\n >\n <FolderIcon size={iconSize.smallest} className=\"text-amber-500 dark:text-amber-400 shrink-0\"/>\n <Typography variant=\"body2\" className=\"text-[13px] font-medium truncate\">\n {folder.name}\n </Typography>\n </div>\n );\n })}\n </div>\n </div>\n )}\n\n {/* FileIcon cards */}\n {files.length > 0 && (\n <div>\n <Typography variant=\"caption\" className=\"text-[10px] uppercase tracking-wider font-bold text-text-disabled dark:text-text-disabled-dark mb-2 block\">\n Files ({files.length})\n </Typography>\n <div className=\"grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]\">\n {files.map(file => {\n const FileIconComp = getFileIcon(file.contentType);\n const ext = getExtension(file.name)?.toLowerCase() || \"\";\n const isImage = file.contentType?.startsWith(\"image/\") || [\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"svg\"].includes(ext);\n const isChecked = selectedPaths.has(file.fullPath);\n\n return (\n <div\n key={file.fullPath}\n data-storage-item\n className={cls(\n \"rounded-lg overflow-hidden cursor-pointer border\",\n \"transition-shadow duration-150\",\n defaultBorderMixin,\n \"hover:shadow-md\",\n isChecked && \"ring-2 ring-primary\"\n )}\n onClick={(e) => handleItemClick(file, e)}\n onDoubleClick={() => handleItemDoubleClick(file)}\n >\n {/* Thumbnail or icon */}\n <div className=\"aspect-square relative overflow-hidden bg-surface-100 dark:bg-surface-800 flex items-center justify-center\">\n {isImage && file.downloadUrl ? (\n <img\n src={file.downloadUrl}\n alt={file.name}\n className=\"w-full h-full object-cover\"\n loading=\"lazy\"\n />\n ) : (\n <FileIconComp className=\"text-surface-accent-400 dark:text-surface-accent-500 w-8 h-8\"/>\n )}\n\n {/* Extension badge */}\n {getExtension(file.name) && (\n <div className=\"absolute bottom-1.5 right-1.5 px-1.5 py-0.5 rounded text-[9px] font-bold uppercase bg-black/50 text-white backdrop-blur-sm\">\n {getExtension(file.name)}\n </div>\n )}\n </div>\n\n {/* Name & size */}\n <div className=\"p-2.5\">\n <Typography variant=\"body2\" className=\"text-[12px] font-medium truncate text-surface-900 dark:text-white\">\n {file.name}\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\" className=\"truncate block mt-0.5 text-[11px]\">\n {file.size !== undefined ? formatFileSize(file.size) : \"—\"}\n </Typography>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div className=\"flex h-full w-full bg-white dark:bg-surface-800 overflow-hidden text-text-primary dark:text-text-primary-dark\">\n <div className=\"flex h-full w-full\">\n {/* Main content */}\n <div className=\"flex-grow flex flex-col min-w-0 h-full\">\n {/* Toolbar */}\n <div className={cls(\"flex items-center justify-between pr-2 border-b bg-white dark:bg-surface-800 shrink-0 h-10\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-1.5 flex-grow overflow-hidden px-3 py-2\">\n {/* Breadcrumbs — always visible */}\n {currentPath && (\n <Tooltip title=\"Go up\">\n <IconButton size=\"small\" onClick={handleNavigateUp}>\n <ArrowLeftIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n )}\n <div className=\"flex items-center gap-0.5 overflow-x-auto no-scrollbar\">\n {segments.map((seg, i) => (\n <React.Fragment key={seg.path}>\n {i > 0 && (\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark mx-0.5\">/</Typography>\n )}\n <Button\n variant=\"text\"\n size=\"small\"\n className={cls(\n \"px-1.5 py-0.5 min-h-0 min-w-0 h-6 text-xs whitespace-nowrap normal-case font-normal\",\n i === segments.length - 1\n ? \"text-text-primary dark:text-text-primary-dark font-medium\"\n : \"text-text-secondary dark:text-text-secondary-dark\"\n )}\n onClick={() => handleNavigate(seg.path)}\n >\n {seg.label}\n </Button>\n </React.Fragment>\n ))}\n </div>\n\n <div className=\"flex-1\"/>\n\n {/* Selection actions or file count */}\n {selectedPaths.size > 0 ? (\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <Typography variant=\"body2\" className=\"text-[13px] font-medium whitespace-nowrap\">\n {selectedPaths.size} selected\n </Typography>\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => {\n setDeleteDialogTarget(\"selection\");\n setDeleteDialogOpen(true);\n }}\n >\n <Trash2Icon size={14} className=\"mr-1\"/>\n Delete\n </Button>\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => {\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }}\n >\n <XIcon size={14} className=\"mr-1\"/>\n Deselect\n </Button>\n </div>\n ) : !loading ? (\n <Chip size=\"small\" className=\"shrink-0 text-[10px]\">\n {files.length} file{files.length !== 1 ? \"s\" : \"\"}\n {folders.length > 0 ? `, ${folders.length} folder${folders.length !== 1 ? \"s\" : \"\"}` : \"\"}\n </Chip>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center justify-end gap-1.5 pr-1\">\n\n {/* Backend picker — only shown when more than one storage source is available */}\n {sourceKeys.length > 1 && (\n <Select\n size=\"small\"\n position=\"item-aligned\"\n value={selectedSourceKey}\n onValueChange={(value) => {\n if (value) setSelectedSourceKey(value);\n }}\n renderValue={(key) => {\n const label = storageSources.registry[key]?.label;\n return label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? \"Default\" : key);\n }}>\n {sourceKeys.map((key) => (\n <SelectItem key={key} value={key}>\n {storageSources.registry[key]?.label\n ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? \"Default\" : key)}\n </SelectItem>\n ))}\n </Select>\n )}\n\n <Tooltip title=\"Grid view\">\n <IconButton\n size=\"small\"\n onClick={() => setViewMode(\"grid\")}\n className={cls(viewMode === \"grid\" && \"bg-surface-100 dark:bg-surface-800\")}\n >\n <LayoutGridIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n <Tooltip title=\"List view\">\n <IconButton\n size=\"small\"\n onClick={() => setViewMode(\"list\")}\n className={cls(viewMode === \"list\" && \"bg-surface-100 dark:bg-surface-800\")}\n >\n <ListIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n\n <div className={cls(\"h-4 w-px mx-0.5\", defaultBorderMixin, \"bg-surface-200 dark:bg-surface-700\")}/>\n\n <Tooltip title=\"Refresh\">\n <IconButton size=\"small\" onClick={handleRefresh} disabled={loading}>\n <RefreshCwIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n\n <Tooltip title=\"New folder\">\n <IconButton\n size=\"small\"\n onClick={() => {\n setNewFolderName(\"\");\n setNewFolderDialogOpen(true);\n }}\n >\n <FolderPlusIcon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => setUploadDialogOpen(true)}\n >\n <UploadCloudIcon size={iconSize.smallest} className=\"mr-1\"/>\n Upload\n </Button>\n </div>\n </div>\n\n {/* File grid / list — drop zone */}\n <div {...getDropRootProps()}\n className=\"flex-grow flex flex-col overflow-hidden min-h-0 relative\"\n onClick={(e) => {\n const target = e.target as HTMLElement;\n if (!target.closest(\"[data-storage-item]\") && selectedPaths.size > 0) {\n setSelectedPaths(new Set());\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }\n }}\n >\n <input {...getDropInputProps()} />\n {renderContents()}\n {/* Drag overlay */}\n {isDragActive && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-primary/5 dark:bg-primary/10 backdrop-blur-[2px]\">\n <div className=\"flex flex-col items-center gap-2 p-6 rounded-xl border-2 border-dashed border-primary bg-white/80 dark:bg-surface-900/80\">\n <UploadCloudIcon className=\"w-10 h-10 text-primary\"/>\n <Typography variant=\"subtitle2\" className=\"text-primary font-semibold\">\n Drop files to upload\n </Typography>\n <Typography variant=\"caption\" color=\"secondary\">\n to /{currentPath || \"root\"}\n </Typography>\n </div>\n </div>\n )}\n </div>\n\n {/* Status bar */}\n <div className={cls(\"px-4 py-1.5 border-t bg-surface-50 dark:bg-surface-800 flex items-center justify-between shrink-0\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-4 text-[11px]\">\n <span className=\"text-text-disabled dark:text-text-disabled-dark font-bold uppercase tracking-tighter\">\n Path\n </span>\n <span className=\"font-mono text-text-secondary dark:text-text-secondary-dark\">\n /{currentPath || \"\"}\n </span>\n </div>\n {selectedPaths.size > 0 ? (\n <div className=\"text-[11px] text-text-secondary dark:text-text-secondary-dark\">\n {selectedPaths.size} item{selectedPaths.size !== 1 ? \"s\" : \"\"} selected\n </div>\n ) : selectedFile ? (\n <div className=\"text-[11px] text-text-secondary dark:text-text-secondary-dark\">\n Selected: <span className=\"font-mono\">{selectedFile.name}</span>\n </div>\n ) : null}\n </div>\n </div>\n\n {/* Preview panel */}\n {selectedFile && (\n <div className=\"w-80 lg:w-96 shrink-0\">\n <FilePreviewPanel\n file={selectedFile}\n downloadUrl={selectedDownloadUrl}\n onClose={() => {\n setSelectedFile(null);\n setSelectedDownloadUrl(null);\n }}\n onDelete={() => handleDeleteFile(selectedFile)}\n />\n </div>\n )}\n </div>\n\n {/* Upload Dialog */}\n <UploadDialog\n open={uploadDialogOpen}\n currentPath={currentPath}\n onClose={() => setUploadDialogOpen(false)}\n onUpload={handleUpload}\n />\n\n {/* Delete confirmation dialog */}\n <Dialog\n open={deleteDialogOpen}\n onOpenChange={(open) => {\n if (!open && !deleting) {\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }\n }}\n >\n <DialogTitle hidden>Delete Confirmation</DialogTitle>\n <DialogContent>\n <Typography variant=\"subtitle1\" className=\"font-semibold mb-2\">\n {deleteDialogTarget === \"selection\"\n ? `Delete ${selectedPaths.size} item${selectedPaths.size !== 1 ? \"s\" : \"\"}?`\n : deleteDialogTarget\n ? `Delete folder \"${deleteDialogTarget.name}\"?`\n : \"Delete?\"}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {deleteDialogTarget === \"selection\"\n ? \"This will permanently delete all selected files and folders, including their contents. This action cannot be undone.\"\n : \"This will permanently delete the folder and all of its contents. This action cannot be undone.\"}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button\n variant=\"text\"\n onClick={() => {\n setDeleteDialogOpen(false);\n setDeleteDialogTarget(null);\n }}\n disabled={deleting}\n >\n Cancel\n </Button>\n <LoadingButton\n color=\"error\"\n loading={deleting}\n onClick={deleteDialogTarget === \"selection\" ? handleBulkDelete : handleConfirmDeleteFolder}\n >\n <Trash2Icon size={14} className=\"mr-1\"/>\n Delete\n </LoadingButton>\n </DialogActions>\n </Dialog>\n\n {/* New Folder Dialog */}\n <Dialog\n open={newFolderDialogOpen}\n onOpenChange={(open) => {\n if (!open && !creatingFolder) {\n setNewFolderDialogOpen(false);\n setNewFolderName(\"\");\n }\n }}\n >\n <DialogTitle hidden>New Folder</DialogTitle>\n <DialogContent>\n <TextField\n autoFocus\n size=\"small\"\n label=\"Folder name\"\n value={newFolderName}\n onChange={(e) => setNewFolderName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && newFolderName.trim()) {\n e.preventDefault();\n handleCreateFolder();\n }\n }}\n disabled={creatingFolder}\n placeholder=\"Enter folder name\"\n />\n {currentPath && (\n <Typography variant=\"caption\" color=\"secondary\" className=\"mt-2\">\n Will be created in <span className=\"font-mono\">/{currentPath}/</span>\n </Typography>\n )}\n </DialogContent>\n <DialogActions>\n <Button\n variant=\"text\"\n onClick={() => {\n setNewFolderDialogOpen(false);\n setNewFolderName(\"\");\n }}\n disabled={creatingFolder}\n >\n Cancel\n </Button>\n <LoadingButton\n color=\"primary\"\n loading={creatingFolder}\n disabled={!newFolderName.trim()}\n onClick={handleCreateFolder}\n >\n <FolderPlusIcon size={14} className=\"mr-1\"/>\n Create\n </LoadingButton>\n </DialogActions>\n </Dialog>\n </div>\n );\n};\n"],"mappings":"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"}