@flanksource/clicky-ui 0.3.56 → 0.3.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ErrorWrapper.cjs +15 -4
- package/dist/components/ErrorWrapper.cjs.map +1 -1
- package/dist/components/ErrorWrapper.d.ts +7 -0
- package/dist/components/ErrorWrapper.d.ts.map +1 -1
- package/dist/components/ErrorWrapper.js +15 -4
- package/dist/components/ErrorWrapper.js.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptLayerStrip.cjs +6 -3
- package/dist/data/ai/PromptCatalog/PromptLayerStrip.cjs.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptLayerStrip.js +6 -3
- package/dist/data/ai/PromptCatalog/PromptLayerStrip.js.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPage.cjs +2 -1
- package/dist/data/ai/PromptCatalog/PromptPage.cjs.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPage.d.ts.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPage.js +2 -1
- package/dist/data/ai/PromptCatalog/PromptPage.js.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPageHeader.cjs +9 -6
- package/dist/data/ai/PromptCatalog/PromptPageHeader.cjs.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPageHeader.d.ts.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPageHeader.js +9 -6
- package/dist/data/ai/PromptCatalog/PromptPageHeader.js.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPageSaveBar.cjs +3 -3
- package/dist/data/ai/PromptCatalog/PromptPageSaveBar.cjs.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPageSaveBar.d.ts +2 -1
- package/dist/data/ai/PromptCatalog/PromptPageSaveBar.d.ts.map +1 -1
- package/dist/data/ai/PromptCatalog/PromptPageSaveBar.js +3 -3
- package/dist/data/ai/PromptCatalog/PromptPageSaveBar.js.map +1 -1
- package/dist/data/ai/PromptCatalog/prompt-page-model.cjs +4 -3
- package/dist/data/ai/PromptCatalog/prompt-page-model.cjs.map +1 -1
- package/dist/data/ai/PromptCatalog/prompt-page-model.d.ts +1 -1
- package/dist/data/ai/PromptCatalog/prompt-page-model.d.ts.map +1 -1
- package/dist/data/ai/PromptCatalog/prompt-page-model.js +4 -3
- package/dist/data/ai/PromptCatalog/prompt-page-model.js.map +1 -1
- package/dist/data/ai/PromptCatalog/types.d.ts +1 -0
- package/dist/data/ai/PromptCatalog/types.d.ts.map +1 -1
- package/dist/data/traces/index.d.ts +7 -0
- package/dist/data/traces/index.d.ts.map +1 -1
- package/dist/data/traces/otel/OperationList.cjs +64 -0
- package/dist/data/traces/otel/OperationList.cjs.map +1 -0
- package/dist/data/traces/otel/OperationList.d.ts +10 -0
- package/dist/data/traces/otel/OperationList.d.ts.map +1 -0
- package/dist/data/traces/otel/OperationList.js +64 -0
- package/dist/data/traces/otel/OperationList.js.map +1 -0
- package/dist/data/traces/otel/OtelTraceDetail.cjs +781 -0
- package/dist/data/traces/otel/OtelTraceDetail.cjs.map +1 -0
- package/dist/data/traces/otel/OtelTraceDetail.d.ts +7 -0
- package/dist/data/traces/otel/OtelTraceDetail.d.ts.map +1 -0
- package/dist/data/traces/otel/OtelTraceDetail.js +781 -0
- package/dist/data/traces/otel/OtelTraceDetail.js.map +1 -0
- package/dist/data/traces/otel/OtelTraceSearch.cjs +145 -0
- package/dist/data/traces/otel/OtelTraceSearch.cjs.map +1 -0
- package/dist/data/traces/otel/OtelTraceSearch.d.ts +16 -0
- package/dist/data/traces/otel/OtelTraceSearch.d.ts.map +1 -0
- package/dist/data/traces/otel/OtelTraceSearch.js +145 -0
- package/dist/data/traces/otel/OtelTraceSearch.js.map +1 -0
- package/dist/data/traces/otel/OtelTraceTable.cjs +47 -0
- package/dist/data/traces/otel/OtelTraceTable.cjs.map +1 -0
- package/dist/data/traces/otel/OtelTraceTable.d.ts +12 -0
- package/dist/data/traces/otel/OtelTraceTable.d.ts.map +1 -0
- package/dist/data/traces/otel/OtelTraceTable.js +47 -0
- package/dist/data/traces/otel/OtelTraceTable.js.map +1 -0
- package/dist/data/traces/otel/QueryBar.cjs +158 -0
- package/dist/data/traces/otel/QueryBar.cjs.map +1 -0
- package/dist/data/traces/otel/QueryBar.d.ts +12 -0
- package/dist/data/traces/otel/QueryBar.d.ts.map +1 -0
- package/dist/data/traces/otel/QueryBar.js +158 -0
- package/dist/data/traces/otel/QueryBar.js.map +1 -0
- package/dist/data/traces/otel/SpanCards.cjs +264 -0
- package/dist/data/traces/otel/SpanCards.cjs.map +1 -0
- package/dist/data/traces/otel/SpanCards.d.ts +17 -0
- package/dist/data/traces/otel/SpanCards.d.ts.map +1 -0
- package/dist/data/traces/otel/SpanCards.js +261 -0
- package/dist/data/traces/otel/SpanCards.js.map +1 -0
- package/dist/data/traces/otel/SpanCategory.cjs +18 -0
- package/dist/data/traces/otel/SpanCategory.cjs.map +1 -0
- package/dist/data/traces/otel/SpanCategory.d.ts +7 -0
- package/dist/data/traces/otel/SpanCategory.d.ts.map +1 -0
- package/dist/data/traces/otel/SpanCategory.js +18 -0
- package/dist/data/traces/otel/SpanCategory.js.map +1 -0
- package/dist/data/traces/otel/TraceResults.cjs +195 -0
- package/dist/data/traces/otel/TraceResults.cjs.map +1 -0
- package/dist/data/traces/otel/TraceResults.d.ts +19 -0
- package/dist/data/traces/otel/TraceResults.d.ts.map +1 -0
- package/dist/data/traces/otel/TraceResults.js +193 -0
- package/dist/data/traces/otel/TraceResults.js.map +1 -0
- package/dist/data/traces/otel/api.cjs +36 -0
- package/dist/data/traces/otel/api.cjs.map +1 -0
- package/dist/data/traces/otel/api.d.ts +87 -0
- package/dist/data/traces/otel/api.d.ts.map +1 -0
- package/dist/data/traces/otel/api.js +33 -0
- package/dist/data/traces/otel/api.js.map +1 -0
- package/dist/data/traces/otel/fixtures.d.ts +4 -0
- package/dist/data/traces/otel/fixtures.d.ts.map +1 -0
- package/dist/data/traces/otel/metrics.cjs +7 -0
- package/dist/data/traces/otel/metrics.cjs.map +1 -0
- package/dist/data/traces/otel/metrics.d.ts +2 -0
- package/dist/data/traces/otel/metrics.d.ts.map +1 -0
- package/dist/data/traces/otel/metrics.js +7 -0
- package/dist/data/traces/otel/metrics.js.map +1 -0
- package/dist/data/traces/otel/model.cjs +167 -0
- package/dist/data/traces/otel/model.cjs.map +1 -0
- package/dist/data/traces/otel/model.d.ts +81 -0
- package/dist/data/traces/otel/model.d.ts.map +1 -0
- package/dist/data/traces/otel/model.js +154 -0
- package/dist/data/traces/otel/model.js.map +1 -0
- package/dist/data/traces/otel/query.cjs +90 -0
- package/dist/data/traces/otel/query.cjs.map +1 -0
- package/dist/data/traces/otel/query.d.ts +20 -0
- package/dist/data/traces/otel/query.d.ts.map +1 -0
- package/dist/data/traces/otel/query.js +86 -0
- package/dist/data/traces/otel/query.js.map +1 -0
- package/dist/data/traces/otel/result-model.cjs +25 -0
- package/dist/data/traces/otel/result-model.cjs.map +1 -0
- package/dist/data/traces/otel/result-model.d.ts +5 -0
- package/dist/data/traces/otel/result-model.d.ts.map +1 -0
- package/dist/data/traces/otel/result-model.js +24 -0
- package/dist/data/traces/otel/result-model.js.map +1 -0
- package/dist/data/traces/otel/source.cjs +11 -0
- package/dist/data/traces/otel/source.cjs.map +1 -0
- package/dist/data/traces/otel/source.d.ts +5 -0
- package/dist/data/traces/otel/source.d.ts.map +1 -0
- package/dist/data/traces/otel/source.js +10 -0
- package/dist/data/traces/otel/source.js.map +1 -0
- package/dist/data/traces/otel/span-traces.cjs +39 -0
- package/dist/data/traces/otel/span-traces.cjs.map +1 -0
- package/dist/data/traces/otel/span-traces.d.ts +3 -0
- package/dist/data/traces/otel/span-traces.d.ts.map +1 -0
- package/dist/data/traces/otel/span-traces.js +39 -0
- package/dist/data/traces/otel/span-traces.js.map +1 -0
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +11 -0
- package/dist/data.js +6 -1
- package/dist/index.cjs +11 -0
- package/dist/index.js +6 -1
- package/dist/profiles/editor/profileEditorSections.cjs +4 -0
- package/dist/profiles/editor/profileEditorSections.cjs.map +1 -1
- package/dist/profiles/editor/profileEditorSections.d.ts.map +1 -1
- package/dist/profiles/editor/profileEditorSections.js +4 -0
- package/dist/profiles/editor/profileEditorSections.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -22,10 +22,21 @@ var ErrorWrapper = class extends react.Component {
|
|
|
22
22
|
this.props.onError?.(error, errorInfo);
|
|
23
23
|
}
|
|
24
24
|
render() {
|
|
25
|
-
if (this.state.error)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
if (this.state.error) {
|
|
26
|
+
if (this.props.renderFallback) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: this.props.renderFallback({
|
|
27
|
+
error: this.state.error,
|
|
28
|
+
componentStack: this.state.componentStack,
|
|
29
|
+
report: errorReport(this.state.error, this.state.componentStack),
|
|
30
|
+
reset: () => this.setState({
|
|
31
|
+
error: null,
|
|
32
|
+
componentStack: null
|
|
33
|
+
})
|
|
34
|
+
}) });
|
|
35
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorFallback, {
|
|
36
|
+
error: this.state.error,
|
|
37
|
+
componentStack: this.state.componentStack
|
|
38
|
+
});
|
|
39
|
+
}
|
|
29
40
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: this.props.children });
|
|
30
41
|
}
|
|
31
42
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorWrapper.cjs","names":["Component","_Fragment","useState","useMemo","Icon","UiWarningTriangle","Button","UiCheck","UiCopy","cn","ErrorDetails","normalizeErrorDiagnostics","reportPageLine"],"sources":["../../src/components/ErrorWrapper.tsx"],"sourcesContent":["import {\n Component,\n useMemo,\n useState,\n type ErrorInfo,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { ErrorDetails } from \"../data/diagnostics/ErrorDetails\";\nimport {\n normalizeErrorDiagnostics,\n reportPageLine,\n type ErrorDiagnostics,\n} from \"../data/diagnostics/error-diagnostics\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiCopy, UiWarningTriangle } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\n\nexport type ErrorWrapperProps = {\n children: ReactNode;\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\n};\n\ntype ErrorWrapperState = {\n error: Error | null;\n componentStack: string | null;\n};\n\nexport class ErrorWrapper extends Component<\n ErrorWrapperProps,\n ErrorWrapperState\n> {\n override state: ErrorWrapperState = {\n error: null,\n componentStack: null,\n };\n\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n\n override componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.setState({ componentStack: errorInfo.componentStack ?? null });\n this.props.onError?.(error, errorInfo);\n }\n\n override render(): ReactElement {\n if (this.state.error) {\n return (\n <ErrorFallback\n error={this.state.error}\n componentStack={this.state.componentStack}\n />\n );\n }\n return <>{this.props.children}</>;\n }\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nfunction copyStatusMessage(copyState: CopyState): string {\n if (copyState === \"copied\") return \"Error details copied to clipboard.\";\n if (copyState === \"failed\") {\n return \"Clipboard access failed. Expand the error details to copy individual values.\";\n }\n return \"\";\n}\n\nfunction ErrorFallback({\n error,\n componentStack,\n}: {\n error: Error;\n componentStack: string | null;\n}) {\n const [copyState, setCopyState] = useState<CopyState>(\"idle\");\n const diagnostics = useMemo(\n () => errorDiagnostics(error, componentStack),\n [componentStack, error],\n );\n\n const copyDetails = async () => {\n if (!navigator.clipboard?.writeText) {\n setCopyState(\"failed\");\n return;\n }\n try {\n await navigator.clipboard.writeText(errorReport(error, componentStack));\n setCopyState(\"copied\");\n } catch {\n setCopyState(\"failed\");\n }\n };\n\n return (\n <main\n data-slot=\"error-wrapper\"\n role=\"alert\"\n aria-labelledby=\"error-wrapper-title\"\n className=\"flex min-h-dvh w-full items-center justify-center bg-background p-density-6 text-foreground\"\n >\n <div className=\"w-full max-w-3xl\">\n <div className=\"mb-density-4 flex items-start gap-density-3\">\n <span className=\"grid size-12 shrink-0 place-items-center rounded-full bg-destructive/10 text-destructive\">\n <Icon icon={UiWarningTriangle} className=\"size-6\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-destructive\">\n Unexpected application error\n </p>\n <h1\n id=\"error-wrapper-title\"\n className=\"mt-density-1 text-2xl font-semibold tracking-tight\"\n >\n Something went wrong\n </h1>\n <p className=\"mt-density-2 break-words text-sm text-muted-foreground\">\n {diagnostics.message}\n </p>\n </div>\n </div>\n\n <div className=\"mb-density-3 flex items-center gap-density-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => void copyDetails()}\n >\n <Icon icon={copyState === \"copied\" ? UiCheck : UiCopy} />\n {/* Distinct from ErrorDetails' own \"Copy error details\" control\n below: this copies the page-level report (URL, user agent,\n React component stack), and two identically named buttons in\n one view are ambiguous to assistive tech. */}\n {copyState === \"copied\" ? \"Copied\" : \"Copy error report\"}\n </Button>\n <span\n aria-live=\"polite\"\n className={cn(\n \"text-xs\",\n copyState === \"failed\"\n ? \"text-destructive\"\n : \"text-muted-foreground\",\n )}\n >\n {copyStatusMessage(copyState)}\n </span>\n </div>\n\n <ErrorDetails diagnostics={diagnostics} />\n </div>\n </main>\n );\n}\n\nfunction errorDiagnostics(\n error: Error,\n componentStack: string | null,\n): ErrorDiagnostics {\n const diagnostics = normalizeErrorDiagnostics(\n error,\n \"An unexpected error was thrown without a message.\",\n );\n if (!diagnostics) {\n throw new Error(\"ErrorWrapper could not normalize the captured error\");\n }\n\n const cause =\n error.cause === undefined\n ? []\n : [[\"cause\", String(error.cause)] as [string, string]];\n const reactStack = componentStack?.trim();\n return {\n ...diagnostics,\n context: [...diagnostics.context, ...cause],\n ...(reactStack\n ? {\n stacktrace: [\n diagnostics.stacktrace,\n \"React component stack:\",\n reactStack,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n }\n : {}),\n };\n}\n\nfunction errorReport(error: Error, componentStack: string | null) {\n const lines = [\n `Error: ${error.message || \"An unexpected error was thrown without a message.\"}`,\n ];\n if (error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (error.cause !== undefined) lines.push(`Cause: ${String(error.cause)}`);\n const page = reportPageLine();\n if (page) lines.push(page);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) {\n lines.push(`User agent: ${navigator.userAgent}`);\n }\n lines.push(`Time: ${new Date().toISOString()}`);\n if (error.stack) lines.push(\"\", \"Stack trace:\", error.stack);\n if (componentStack?.trim()) {\n lines.push(\"\", \"React component stack:\", componentStack.trim());\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ErrorWrapper.cjs","names":["Component","_Fragment","useState","useMemo","Icon","UiWarningTriangle","Button","UiCheck","UiCopy","cn","ErrorDetails","normalizeErrorDiagnostics","reportPageLine"],"sources":["../../src/components/ErrorWrapper.tsx"],"sourcesContent":["import {\n Component,\n useMemo,\n useState,\n type ErrorInfo,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { ErrorDetails } from \"../data/diagnostics/ErrorDetails\";\nimport {\n normalizeErrorDiagnostics,\n reportPageLine,\n type ErrorDiagnostics,\n} from \"../data/diagnostics/error-diagnostics\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiCopy, UiWarningTriangle } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\n\nexport type ErrorWrapperProps = {\n children: ReactNode;\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\n /** Render host-specific recovery actions without replacing ancestors of this boundary. */\n renderFallback?: (failure: {\n error: Error;\n componentStack: string | null;\n report: string;\n reset: () => void;\n }) => ReactNode;\n};\n\ntype ErrorWrapperState = {\n error: Error | null;\n componentStack: string | null;\n};\n\nexport class ErrorWrapper extends Component<\n ErrorWrapperProps,\n ErrorWrapperState\n> {\n override state: ErrorWrapperState = {\n error: null,\n componentStack: null,\n };\n\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n\n override componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.setState({ componentStack: errorInfo.componentStack ?? null });\n this.props.onError?.(error, errorInfo);\n }\n\n override render(): ReactElement {\n if (this.state.error) {\n if (this.props.renderFallback)\n return (\n <>\n {this.props.renderFallback({\n error: this.state.error,\n componentStack: this.state.componentStack,\n report: errorReport(this.state.error, this.state.componentStack),\n reset: () => this.setState({ error: null, componentStack: null }),\n })}\n </>\n );\n return (\n <ErrorFallback\n error={this.state.error}\n componentStack={this.state.componentStack}\n />\n );\n }\n return <>{this.props.children}</>;\n }\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nfunction copyStatusMessage(copyState: CopyState): string {\n if (copyState === \"copied\") return \"Error details copied to clipboard.\";\n if (copyState === \"failed\") {\n return \"Clipboard access failed. Expand the error details to copy individual values.\";\n }\n return \"\";\n}\n\nfunction ErrorFallback({\n error,\n componentStack,\n}: {\n error: Error;\n componentStack: string | null;\n}) {\n const [copyState, setCopyState] = useState<CopyState>(\"idle\");\n const diagnostics = useMemo(\n () => errorDiagnostics(error, componentStack),\n [componentStack, error],\n );\n\n const copyDetails = async () => {\n if (!navigator.clipboard?.writeText) {\n setCopyState(\"failed\");\n return;\n }\n try {\n await navigator.clipboard.writeText(errorReport(error, componentStack));\n setCopyState(\"copied\");\n } catch {\n setCopyState(\"failed\");\n }\n };\n\n return (\n <main\n data-slot=\"error-wrapper\"\n role=\"alert\"\n aria-labelledby=\"error-wrapper-title\"\n className=\"flex min-h-dvh w-full items-center justify-center bg-background p-density-6 text-foreground\"\n >\n <div className=\"w-full max-w-3xl\">\n <div className=\"mb-density-4 flex items-start gap-density-3\">\n <span className=\"grid size-12 shrink-0 place-items-center rounded-full bg-destructive/10 text-destructive\">\n <Icon icon={UiWarningTriangle} className=\"size-6\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-destructive\">\n Unexpected application error\n </p>\n <h1\n id=\"error-wrapper-title\"\n className=\"mt-density-1 text-2xl font-semibold tracking-tight\"\n >\n Something went wrong\n </h1>\n <p className=\"mt-density-2 break-words text-sm text-muted-foreground\">\n {diagnostics.message}\n </p>\n </div>\n </div>\n\n <div className=\"mb-density-3 flex items-center gap-density-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => void copyDetails()}\n >\n <Icon icon={copyState === \"copied\" ? UiCheck : UiCopy} />\n {/* Distinct from ErrorDetails' own \"Copy error details\" control\n below: this copies the page-level report (URL, user agent,\n React component stack), and two identically named buttons in\n one view are ambiguous to assistive tech. */}\n {copyState === \"copied\" ? \"Copied\" : \"Copy error report\"}\n </Button>\n <span\n aria-live=\"polite\"\n className={cn(\n \"text-xs\",\n copyState === \"failed\"\n ? \"text-destructive\"\n : \"text-muted-foreground\",\n )}\n >\n {copyStatusMessage(copyState)}\n </span>\n </div>\n\n <ErrorDetails diagnostics={diagnostics} />\n </div>\n </main>\n );\n}\n\nfunction errorDiagnostics(\n error: Error,\n componentStack: string | null,\n): ErrorDiagnostics {\n const diagnostics = normalizeErrorDiagnostics(\n error,\n \"An unexpected error was thrown without a message.\",\n );\n if (!diagnostics) {\n throw new Error(\"ErrorWrapper could not normalize the captured error\");\n }\n\n const cause =\n error.cause === undefined\n ? []\n : [[\"cause\", String(error.cause)] as [string, string]];\n const reactStack = componentStack?.trim();\n return {\n ...diagnostics,\n context: [...diagnostics.context, ...cause],\n ...(reactStack\n ? {\n stacktrace: [\n diagnostics.stacktrace,\n \"React component stack:\",\n reactStack,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n }\n : {}),\n };\n}\n\nfunction errorReport(error: Error, componentStack: string | null) {\n const lines = [\n `Error: ${error.message || \"An unexpected error was thrown without a message.\"}`,\n ];\n if (error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (error.cause !== undefined) lines.push(`Cause: ${String(error.cause)}`);\n const page = reportPageLine();\n if (page) lines.push(page);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) {\n lines.push(`User agent: ${navigator.userAgent}`);\n }\n lines.push(`Time: ${new Date().toISOString()}`);\n if (error.stack) lines.push(\"\", \"Stack trace:\", error.stack);\n if (componentStack?.trim()) {\n lines.push(\"\", \"React component stack:\", componentStack.trim());\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
|
|
@@ -2,6 +2,13 @@ import { Component, ErrorInfo, ReactElement, ReactNode } from 'react';
|
|
|
2
2
|
export type ErrorWrapperProps = {
|
|
3
3
|
children: ReactNode;
|
|
4
4
|
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
5
|
+
/** Render host-specific recovery actions without replacing ancestors of this boundary. */
|
|
6
|
+
renderFallback?: (failure: {
|
|
7
|
+
error: Error;
|
|
8
|
+
componentStack: string | null;
|
|
9
|
+
report: string;
|
|
10
|
+
reset: () => void;
|
|
11
|
+
}) => ReactNode;
|
|
5
12
|
};
|
|
6
13
|
type ErrorWrapperState = {
|
|
7
14
|
error: Error | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorWrapper.d.ts","sourceRoot":"","sources":["../../src/components/ErrorWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAGT,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ErrorWrapper.d.ts","sourceRoot":"","sources":["../../src/components/ErrorWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAGT,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACvD,0FAA0F;IAC1F,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE;QACzB,KAAK,EAAE,KAAK,CAAC;QACb,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,IAAI,CAAC;KACnB,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,qBAAa,YAAa,SAAQ,SAAS,CACzC,iBAAiB,EACjB,iBAAiB,CAClB;IACU,KAAK,EAAE,iBAAiB,CAG/B;IAEF,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK;;;IAInC,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;IAKpD,MAAM,IAAI,YAAY;CAsBhC"}
|
|
@@ -22,10 +22,21 @@ var ErrorWrapper = class extends Component {
|
|
|
22
22
|
this.props.onError?.(error, errorInfo);
|
|
23
23
|
}
|
|
24
24
|
render() {
|
|
25
|
-
if (this.state.error)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
if (this.state.error) {
|
|
26
|
+
if (this.props.renderFallback) return /* @__PURE__ */ jsx(Fragment$1, { children: this.props.renderFallback({
|
|
27
|
+
error: this.state.error,
|
|
28
|
+
componentStack: this.state.componentStack,
|
|
29
|
+
report: errorReport(this.state.error, this.state.componentStack),
|
|
30
|
+
reset: () => this.setState({
|
|
31
|
+
error: null,
|
|
32
|
+
componentStack: null
|
|
33
|
+
})
|
|
34
|
+
}) });
|
|
35
|
+
return /* @__PURE__ */ jsx(ErrorFallback, {
|
|
36
|
+
error: this.state.error,
|
|
37
|
+
componentStack: this.state.componentStack
|
|
38
|
+
});
|
|
39
|
+
}
|
|
29
40
|
return /* @__PURE__ */ jsx(Fragment$1, { children: this.props.children });
|
|
30
41
|
}
|
|
31
42
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorWrapper.js","names":["_Fragment"],"sources":["../../src/components/ErrorWrapper.tsx"],"sourcesContent":["import {\n Component,\n useMemo,\n useState,\n type ErrorInfo,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { ErrorDetails } from \"../data/diagnostics/ErrorDetails\";\nimport {\n normalizeErrorDiagnostics,\n reportPageLine,\n type ErrorDiagnostics,\n} from \"../data/diagnostics/error-diagnostics\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiCopy, UiWarningTriangle } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\n\nexport type ErrorWrapperProps = {\n children: ReactNode;\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\n};\n\ntype ErrorWrapperState = {\n error: Error | null;\n componentStack: string | null;\n};\n\nexport class ErrorWrapper extends Component<\n ErrorWrapperProps,\n ErrorWrapperState\n> {\n override state: ErrorWrapperState = {\n error: null,\n componentStack: null,\n };\n\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n\n override componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.setState({ componentStack: errorInfo.componentStack ?? null });\n this.props.onError?.(error, errorInfo);\n }\n\n override render(): ReactElement {\n if (this.state.error) {\n return (\n <ErrorFallback\n error={this.state.error}\n componentStack={this.state.componentStack}\n />\n );\n }\n return <>{this.props.children}</>;\n }\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nfunction copyStatusMessage(copyState: CopyState): string {\n if (copyState === \"copied\") return \"Error details copied to clipboard.\";\n if (copyState === \"failed\") {\n return \"Clipboard access failed. Expand the error details to copy individual values.\";\n }\n return \"\";\n}\n\nfunction ErrorFallback({\n error,\n componentStack,\n}: {\n error: Error;\n componentStack: string | null;\n}) {\n const [copyState, setCopyState] = useState<CopyState>(\"idle\");\n const diagnostics = useMemo(\n () => errorDiagnostics(error, componentStack),\n [componentStack, error],\n );\n\n const copyDetails = async () => {\n if (!navigator.clipboard?.writeText) {\n setCopyState(\"failed\");\n return;\n }\n try {\n await navigator.clipboard.writeText(errorReport(error, componentStack));\n setCopyState(\"copied\");\n } catch {\n setCopyState(\"failed\");\n }\n };\n\n return (\n <main\n data-slot=\"error-wrapper\"\n role=\"alert\"\n aria-labelledby=\"error-wrapper-title\"\n className=\"flex min-h-dvh w-full items-center justify-center bg-background p-density-6 text-foreground\"\n >\n <div className=\"w-full max-w-3xl\">\n <div className=\"mb-density-4 flex items-start gap-density-3\">\n <span className=\"grid size-12 shrink-0 place-items-center rounded-full bg-destructive/10 text-destructive\">\n <Icon icon={UiWarningTriangle} className=\"size-6\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-destructive\">\n Unexpected application error\n </p>\n <h1\n id=\"error-wrapper-title\"\n className=\"mt-density-1 text-2xl font-semibold tracking-tight\"\n >\n Something went wrong\n </h1>\n <p className=\"mt-density-2 break-words text-sm text-muted-foreground\">\n {diagnostics.message}\n </p>\n </div>\n </div>\n\n <div className=\"mb-density-3 flex items-center gap-density-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => void copyDetails()}\n >\n <Icon icon={copyState === \"copied\" ? UiCheck : UiCopy} />\n {/* Distinct from ErrorDetails' own \"Copy error details\" control\n below: this copies the page-level report (URL, user agent,\n React component stack), and two identically named buttons in\n one view are ambiguous to assistive tech. */}\n {copyState === \"copied\" ? \"Copied\" : \"Copy error report\"}\n </Button>\n <span\n aria-live=\"polite\"\n className={cn(\n \"text-xs\",\n copyState === \"failed\"\n ? \"text-destructive\"\n : \"text-muted-foreground\",\n )}\n >\n {copyStatusMessage(copyState)}\n </span>\n </div>\n\n <ErrorDetails diagnostics={diagnostics} />\n </div>\n </main>\n );\n}\n\nfunction errorDiagnostics(\n error: Error,\n componentStack: string | null,\n): ErrorDiagnostics {\n const diagnostics = normalizeErrorDiagnostics(\n error,\n \"An unexpected error was thrown without a message.\",\n );\n if (!diagnostics) {\n throw new Error(\"ErrorWrapper could not normalize the captured error\");\n }\n\n const cause =\n error.cause === undefined\n ? []\n : [[\"cause\", String(error.cause)] as [string, string]];\n const reactStack = componentStack?.trim();\n return {\n ...diagnostics,\n context: [...diagnostics.context, ...cause],\n ...(reactStack\n ? {\n stacktrace: [\n diagnostics.stacktrace,\n \"React component stack:\",\n reactStack,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n }\n : {}),\n };\n}\n\nfunction errorReport(error: Error, componentStack: string | null) {\n const lines = [\n `Error: ${error.message || \"An unexpected error was thrown without a message.\"}`,\n ];\n if (error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (error.cause !== undefined) lines.push(`Cause: ${String(error.cause)}`);\n const page = reportPageLine();\n if (page) lines.push(page);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) {\n lines.push(`User agent: ${navigator.userAgent}`);\n }\n lines.push(`Time: ${new Date().toISOString()}`);\n if (error.stack) lines.push(\"\", \"Stack trace:\", error.stack);\n if (componentStack?.trim()) {\n lines.push(\"\", \"React component stack:\", componentStack.trim());\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"ErrorWrapper.js","names":["_Fragment"],"sources":["../../src/components/ErrorWrapper.tsx"],"sourcesContent":["import {\n Component,\n useMemo,\n useState,\n type ErrorInfo,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { ErrorDetails } from \"../data/diagnostics/ErrorDetails\";\nimport {\n normalizeErrorDiagnostics,\n reportPageLine,\n type ErrorDiagnostics,\n} from \"../data/diagnostics/error-diagnostics\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiCopy, UiWarningTriangle } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\n\nexport type ErrorWrapperProps = {\n children: ReactNode;\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\n /** Render host-specific recovery actions without replacing ancestors of this boundary. */\n renderFallback?: (failure: {\n error: Error;\n componentStack: string | null;\n report: string;\n reset: () => void;\n }) => ReactNode;\n};\n\ntype ErrorWrapperState = {\n error: Error | null;\n componentStack: string | null;\n};\n\nexport class ErrorWrapper extends Component<\n ErrorWrapperProps,\n ErrorWrapperState\n> {\n override state: ErrorWrapperState = {\n error: null,\n componentStack: null,\n };\n\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n\n override componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.setState({ componentStack: errorInfo.componentStack ?? null });\n this.props.onError?.(error, errorInfo);\n }\n\n override render(): ReactElement {\n if (this.state.error) {\n if (this.props.renderFallback)\n return (\n <>\n {this.props.renderFallback({\n error: this.state.error,\n componentStack: this.state.componentStack,\n report: errorReport(this.state.error, this.state.componentStack),\n reset: () => this.setState({ error: null, componentStack: null }),\n })}\n </>\n );\n return (\n <ErrorFallback\n error={this.state.error}\n componentStack={this.state.componentStack}\n />\n );\n }\n return <>{this.props.children}</>;\n }\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nfunction copyStatusMessage(copyState: CopyState): string {\n if (copyState === \"copied\") return \"Error details copied to clipboard.\";\n if (copyState === \"failed\") {\n return \"Clipboard access failed. Expand the error details to copy individual values.\";\n }\n return \"\";\n}\n\nfunction ErrorFallback({\n error,\n componentStack,\n}: {\n error: Error;\n componentStack: string | null;\n}) {\n const [copyState, setCopyState] = useState<CopyState>(\"idle\");\n const diagnostics = useMemo(\n () => errorDiagnostics(error, componentStack),\n [componentStack, error],\n );\n\n const copyDetails = async () => {\n if (!navigator.clipboard?.writeText) {\n setCopyState(\"failed\");\n return;\n }\n try {\n await navigator.clipboard.writeText(errorReport(error, componentStack));\n setCopyState(\"copied\");\n } catch {\n setCopyState(\"failed\");\n }\n };\n\n return (\n <main\n data-slot=\"error-wrapper\"\n role=\"alert\"\n aria-labelledby=\"error-wrapper-title\"\n className=\"flex min-h-dvh w-full items-center justify-center bg-background p-density-6 text-foreground\"\n >\n <div className=\"w-full max-w-3xl\">\n <div className=\"mb-density-4 flex items-start gap-density-3\">\n <span className=\"grid size-12 shrink-0 place-items-center rounded-full bg-destructive/10 text-destructive\">\n <Icon icon={UiWarningTriangle} className=\"size-6\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-destructive\">\n Unexpected application error\n </p>\n <h1\n id=\"error-wrapper-title\"\n className=\"mt-density-1 text-2xl font-semibold tracking-tight\"\n >\n Something went wrong\n </h1>\n <p className=\"mt-density-2 break-words text-sm text-muted-foreground\">\n {diagnostics.message}\n </p>\n </div>\n </div>\n\n <div className=\"mb-density-3 flex items-center gap-density-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => void copyDetails()}\n >\n <Icon icon={copyState === \"copied\" ? UiCheck : UiCopy} />\n {/* Distinct from ErrorDetails' own \"Copy error details\" control\n below: this copies the page-level report (URL, user agent,\n React component stack), and two identically named buttons in\n one view are ambiguous to assistive tech. */}\n {copyState === \"copied\" ? \"Copied\" : \"Copy error report\"}\n </Button>\n <span\n aria-live=\"polite\"\n className={cn(\n \"text-xs\",\n copyState === \"failed\"\n ? \"text-destructive\"\n : \"text-muted-foreground\",\n )}\n >\n {copyStatusMessage(copyState)}\n </span>\n </div>\n\n <ErrorDetails diagnostics={diagnostics} />\n </div>\n </main>\n );\n}\n\nfunction errorDiagnostics(\n error: Error,\n componentStack: string | null,\n): ErrorDiagnostics {\n const diagnostics = normalizeErrorDiagnostics(\n error,\n \"An unexpected error was thrown without a message.\",\n );\n if (!diagnostics) {\n throw new Error(\"ErrorWrapper could not normalize the captured error\");\n }\n\n const cause =\n error.cause === undefined\n ? []\n : [[\"cause\", String(error.cause)] as [string, string]];\n const reactStack = componentStack?.trim();\n return {\n ...diagnostics,\n context: [...diagnostics.context, ...cause],\n ...(reactStack\n ? {\n stacktrace: [\n diagnostics.stacktrace,\n \"React component stack:\",\n reactStack,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n }\n : {}),\n };\n}\n\nfunction errorReport(error: Error, componentStack: string | null) {\n const lines = [\n `Error: ${error.message || \"An unexpected error was thrown without a message.\"}`,\n ];\n if (error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (error.cause !== undefined) lines.push(`Cause: ${String(error.cause)}`);\n const page = reportPageLine();\n if (page) lines.push(page);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) {\n lines.push(`User agent: ${navigator.userAgent}`);\n }\n lines.push(`Time: ${new Date().toISOString()}`);\n if (error.stack) lines.push(\"\", \"Stack trace:\", error.stack);\n if (componentStack?.trim()) {\n lines.push(\"\", \"React component stack:\", componentStack.trim());\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
|
|
@@ -23,15 +23,18 @@ function PromptLayerStrip({ entry, selectedOrigin, onSelect }) {
|
|
|
23
23
|
"aria-pressed": active,
|
|
24
24
|
title: layer.path,
|
|
25
25
|
onClick: () => onSelect(layer),
|
|
26
|
-
className: require_utils.cn("flex min-w-44 flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition", active ? "border-primary bg-primary/5" : "border-border hover:bg-muted"),
|
|
26
|
+
className: require_utils.cn("flex min-w-44 max-w-full flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition", active ? "border-primary bg-primary/5" : "border-border hover:bg-muted"),
|
|
27
27
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
28
|
-
className: "flex items-center gap-1.5 font-medium",
|
|
28
|
+
className: "flex min-w-0 items-center gap-1.5 font-medium",
|
|
29
29
|
children: [
|
|
30
30
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
31
31
|
className: "text-muted-foreground",
|
|
32
32
|
children: [index + 1, "."]
|
|
33
33
|
}),
|
|
34
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
34
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35
|
+
className: "truncate",
|
|
36
|
+
children: require_prompt_catalog_model.layerLabel(layer.origin)
|
|
37
|
+
}),
|
|
35
38
|
!layer.editable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_UiLock.UiLock, {
|
|
36
39
|
className: "text-muted-foreground",
|
|
37
40
|
"aria-label": "read-only"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptLayerStrip.cjs","names":["effectiveLayer","cn","layerLabel","UiLock","PromptSourceBadge","Badge","UiCheck"],"sources":["../../../../src/data/ai/PromptCatalog/PromptLayerStrip.tsx"],"sourcesContent":["import { UiCheck, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Badge } from \"../../Badge\";\nimport { effectiveLayer, layerLabel } from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptLayerStripProps = {\n entry: PromptCatalogEntry;\n selectedOrigin?: string | undefined;\n onSelect: (layer: PromptCatalogLayer) => void;\n};\n\n// PromptLayerStrip shows the config chain lowest → highest precedence, marks\n// the layer whose override runs, and lets the user pick which layer to view or\n// edit. Read-only layers stay selectable so their content can be inspected.\nexport function PromptLayerStrip({\n entry,\n selectedOrigin,\n onSelect,\n}: PromptLayerStripProps) {\n const effective = effectiveLayer(entry);\n if (entry.layers.length === 0) {\n return (\n <p className=\"px-density-4 py-density-2 text-xs text-muted-foreground\">\n No configuration layers for this prompt.\n </p>\n );\n }\n return (\n <div\n role=\"group\"\n aria-label=\"Configuration layers\"\n className=\"flex flex-wrap items-stretch gap-2 px-density-4 py-density-2\"\n >\n {entry.layers.map((layer, index) => {\n const active = layer.origin === selectedOrigin;\n return (\n <button\n key={layer.origin}\n type=\"button\"\n aria-pressed={active}\n title={layer.path}\n onClick={() => onSelect(layer)}\n className={cn(\n \"flex min-w-44 flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition\",\n active\n ? \"border-primary bg-primary/5\"\n : \"border-border hover:bg-muted\",\n )}\n >\n <span className=\"flex items-center gap-1.5 font-medium\">\n <span className=\"text-muted-foreground\">{index + 1}.</span>\n <span>{layerLabel(layer.origin)}</span>\n {!layer.editable ? (\n <UiLock\n className=\"text-muted-foreground\"\n aria-label=\"read-only\"\n />\n ) : null}\n </span>\n <span className=\"flex flex-wrap items-center gap-1.5\">\n {layer.source === \"none\" ? (\n <span className=\"text-muted-foreground\">unset</span>\n ) : (\n <PromptSourceBadge source={layer.source} />\n )}\n {layer.fields && layer.fields.length > 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {layer.fields.join(\", \")}\n </span>\n ) : null}\n {effective?.origin === layer.origin ? (\n <Badge\n variant=\"soft\"\n tone=\"success\"\n size=\"xs\"\n icon={UiCheck}\n clickToCopy={false}\n >\n effective\n </Badge>\n ) : null}\n </span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,iBAAiB,EAC/B,OACA,gBACA,YACwB;CACxB,MAAM,YAAYA,6BAAAA,eAAe,KAAK;CACtC,IAAI,MAAM,OAAO,WAAW,GAC1B,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;EAAG,WAAU;EAA0D,UAAA;CAEpE,CAAA;CAGP,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EAET,UAAA,MAAM,OAAO,KAAK,OAAO,UAAU;GAClC,MAAM,SAAS,MAAM,WAAW;GAChC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IAEE,MAAK;IACL,gBAAc;IACd,OAAO,MAAM;IACb,eAAe,SAAS,KAAK;IAC7B,WAAWC,cAAAA,GACT,
|
|
1
|
+
{"version":3,"file":"PromptLayerStrip.cjs","names":["effectiveLayer","cn","layerLabel","UiLock","PromptSourceBadge","Badge","UiCheck"],"sources":["../../../../src/data/ai/PromptCatalog/PromptLayerStrip.tsx"],"sourcesContent":["import { UiCheck, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Badge } from \"../../Badge\";\nimport { effectiveLayer, layerLabel } from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptLayerStripProps = {\n entry: PromptCatalogEntry;\n selectedOrigin?: string | undefined;\n onSelect: (layer: PromptCatalogLayer) => void;\n};\n\n// PromptLayerStrip shows the config chain lowest → highest precedence, marks\n// the layer whose override runs, and lets the user pick which layer to view or\n// edit. Read-only layers stay selectable so their content can be inspected.\nexport function PromptLayerStrip({\n entry,\n selectedOrigin,\n onSelect,\n}: PromptLayerStripProps) {\n const effective = effectiveLayer(entry);\n if (entry.layers.length === 0) {\n return (\n <p className=\"px-density-4 py-density-2 text-xs text-muted-foreground\">\n No configuration layers for this prompt.\n </p>\n );\n }\n return (\n <div\n role=\"group\"\n aria-label=\"Configuration layers\"\n className=\"flex flex-wrap items-stretch gap-2 px-density-4 py-density-2\"\n >\n {entry.layers.map((layer, index) => {\n const active = layer.origin === selectedOrigin;\n return (\n <button\n key={layer.origin}\n type=\"button\"\n aria-pressed={active}\n title={layer.path}\n onClick={() => onSelect(layer)}\n className={cn(\n \"flex min-w-44 max-w-full flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition\",\n active\n ? \"border-primary bg-primary/5\"\n : \"border-border hover:bg-muted\",\n )}\n >\n <span className=\"flex min-w-0 items-center gap-1.5 font-medium\">\n <span className=\"text-muted-foreground\">{index + 1}.</span>\n <span className=\"truncate\">{layerLabel(layer.origin)}</span>\n {!layer.editable ? (\n <UiLock\n className=\"text-muted-foreground\"\n aria-label=\"read-only\"\n />\n ) : null}\n </span>\n <span className=\"flex flex-wrap items-center gap-1.5\">\n {layer.source === \"none\" ? (\n <span className=\"text-muted-foreground\">unset</span>\n ) : (\n <PromptSourceBadge source={layer.source} />\n )}\n {layer.fields && layer.fields.length > 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {layer.fields.join(\", \")}\n </span>\n ) : null}\n {effective?.origin === layer.origin ? (\n <Badge\n variant=\"soft\"\n tone=\"success\"\n size=\"xs\"\n icon={UiCheck}\n clickToCopy={false}\n >\n effective\n </Badge>\n ) : null}\n </span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,iBAAiB,EAC/B,OACA,gBACA,YACwB;CACxB,MAAM,YAAYA,6BAAAA,eAAe,KAAK;CACtC,IAAI,MAAM,OAAO,WAAW,GAC1B,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;EAAG,WAAU;EAA0D,UAAA;CAEpE,CAAA;CAGP,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EAET,UAAA,MAAM,OAAO,KAAK,OAAO,UAAU;GAClC,MAAM,SAAS,MAAM,WAAW;GAChC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IAEE,MAAK;IACL,gBAAc;IACd,OAAO,MAAM;IACb,eAAe,SAAS,KAAK;IAC7B,WAAWC,cAAAA,GACT,oGACA,SACI,gCACA,8BACN;IAXF,UAAA,CAaE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;OAAM,WAAU;OAAhB,UAAA,CAAyC,QAAQ,GAAE,GAAO;;MAC1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAU;OAAY,UAAAC,6BAAAA,WAAW,MAAM,MAAM;MAAQ,CAAA;MAC1D,CAAC,MAAM,WACN,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,QAAD;OACE,WAAU;OACV,cAAW;MACZ,CAAA,IACC;KACA;IACN,CAAA,GAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACG,MAAM,WAAW,SAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAU;OAAwB,UAAA;MAAW,CAAA,IAEnD,iBAAA,GAAA,kBAAA,IAAA,CAACC,0BAAAA,mBAAD,EAAmB,QAAQ,MAAM,OAAS,CAAA;MAE3C,MAAM,UAAU,MAAM,OAAO,SAAS,IACrC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAU;OACb,UAAA,MAAM,OAAO,KAAK,IAAI;MACnB,CAAA,IACJ;MACH,WAAW,WAAW,MAAM,SAC3B,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,OAAD;OACE,SAAQ;OACR,MAAK;OACL,MAAK;OACL,MAAMC,gBAAAA;OACN,aAAa;OACd,UAAA;MAEM,CAAA,IACL;KACA;IACA,CAAA,CAAA;GA7CD,GAAA,MAAM,MA6CL;EAEZ,CAAC;CACE,CAAA;AAET"}
|
|
@@ -23,15 +23,18 @@ function PromptLayerStrip({ entry, selectedOrigin, onSelect }) {
|
|
|
23
23
|
"aria-pressed": active,
|
|
24
24
|
title: layer.path,
|
|
25
25
|
onClick: () => onSelect(layer),
|
|
26
|
-
className: cn("flex min-w-44 flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition", active ? "border-primary bg-primary/5" : "border-border hover:bg-muted"),
|
|
26
|
+
className: cn("flex min-w-44 max-w-full flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition", active ? "border-primary bg-primary/5" : "border-border hover:bg-muted"),
|
|
27
27
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
28
|
-
className: "flex items-center gap-1.5 font-medium",
|
|
28
|
+
className: "flex min-w-0 items-center gap-1.5 font-medium",
|
|
29
29
|
children: [
|
|
30
30
|
/* @__PURE__ */ jsxs("span", {
|
|
31
31
|
className: "text-muted-foreground",
|
|
32
32
|
children: [index + 1, "."]
|
|
33
33
|
}),
|
|
34
|
-
/* @__PURE__ */ jsx("span", {
|
|
34
|
+
/* @__PURE__ */ jsx("span", {
|
|
35
|
+
className: "truncate",
|
|
36
|
+
children: layerLabel(layer.origin)
|
|
37
|
+
}),
|
|
35
38
|
!layer.editable ? /* @__PURE__ */ jsx(UiLock, {
|
|
36
39
|
className: "text-muted-foreground",
|
|
37
40
|
"aria-label": "read-only"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptLayerStrip.js","names":[],"sources":["../../../../src/data/ai/PromptCatalog/PromptLayerStrip.tsx"],"sourcesContent":["import { UiCheck, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Badge } from \"../../Badge\";\nimport { effectiveLayer, layerLabel } from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptLayerStripProps = {\n entry: PromptCatalogEntry;\n selectedOrigin?: string | undefined;\n onSelect: (layer: PromptCatalogLayer) => void;\n};\n\n// PromptLayerStrip shows the config chain lowest → highest precedence, marks\n// the layer whose override runs, and lets the user pick which layer to view or\n// edit. Read-only layers stay selectable so their content can be inspected.\nexport function PromptLayerStrip({\n entry,\n selectedOrigin,\n onSelect,\n}: PromptLayerStripProps) {\n const effective = effectiveLayer(entry);\n if (entry.layers.length === 0) {\n return (\n <p className=\"px-density-4 py-density-2 text-xs text-muted-foreground\">\n No configuration layers for this prompt.\n </p>\n );\n }\n return (\n <div\n role=\"group\"\n aria-label=\"Configuration layers\"\n className=\"flex flex-wrap items-stretch gap-2 px-density-4 py-density-2\"\n >\n {entry.layers.map((layer, index) => {\n const active = layer.origin === selectedOrigin;\n return (\n <button\n key={layer.origin}\n type=\"button\"\n aria-pressed={active}\n title={layer.path}\n onClick={() => onSelect(layer)}\n className={cn(\n \"flex min-w-44 flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition\",\n active\n ? \"border-primary bg-primary/5\"\n : \"border-border hover:bg-muted\",\n )}\n >\n <span className=\"flex items-center gap-1.5 font-medium\">\n <span className=\"text-muted-foreground\">{index + 1}.</span>\n <span>{layerLabel(layer.origin)}</span>\n {!layer.editable ? (\n <UiLock\n className=\"text-muted-foreground\"\n aria-label=\"read-only\"\n />\n ) : null}\n </span>\n <span className=\"flex flex-wrap items-center gap-1.5\">\n {layer.source === \"none\" ? (\n <span className=\"text-muted-foreground\">unset</span>\n ) : (\n <PromptSourceBadge source={layer.source} />\n )}\n {layer.fields && layer.fields.length > 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {layer.fields.join(\", \")}\n </span>\n ) : null}\n {effective?.origin === layer.origin ? (\n <Badge\n variant=\"soft\"\n tone=\"success\"\n size=\"xs\"\n icon={UiCheck}\n clickToCopy={false}\n >\n effective\n </Badge>\n ) : null}\n </span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,iBAAiB,EAC/B,OACA,gBACA,YACwB;CACxB,MAAM,YAAY,eAAe,KAAK;CACtC,IAAI,MAAM,OAAO,WAAW,GAC1B,OACE,oBAAC,KAAD;EAAG,WAAU;EAA0D,UAAA;CAEpE,CAAA;CAGP,OACE,oBAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EAET,UAAA,MAAM,OAAO,KAAK,OAAO,UAAU;GAClC,MAAM,SAAS,MAAM,WAAW;GAChC,OACE,qBAAC,UAAD;IAEE,MAAK;IACL,gBAAc;IACd,OAAO,MAAM;IACb,eAAe,SAAS,KAAK;IAC7B,WAAW,GACT,
|
|
1
|
+
{"version":3,"file":"PromptLayerStrip.js","names":[],"sources":["../../../../src/data/ai/PromptCatalog/PromptLayerStrip.tsx"],"sourcesContent":["import { UiCheck, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Badge } from \"../../Badge\";\nimport { effectiveLayer, layerLabel } from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptLayerStripProps = {\n entry: PromptCatalogEntry;\n selectedOrigin?: string | undefined;\n onSelect: (layer: PromptCatalogLayer) => void;\n};\n\n// PromptLayerStrip shows the config chain lowest → highest precedence, marks\n// the layer whose override runs, and lets the user pick which layer to view or\n// edit. Read-only layers stay selectable so their content can be inspected.\nexport function PromptLayerStrip({\n entry,\n selectedOrigin,\n onSelect,\n}: PromptLayerStripProps) {\n const effective = effectiveLayer(entry);\n if (entry.layers.length === 0) {\n return (\n <p className=\"px-density-4 py-density-2 text-xs text-muted-foreground\">\n No configuration layers for this prompt.\n </p>\n );\n }\n return (\n <div\n role=\"group\"\n aria-label=\"Configuration layers\"\n className=\"flex flex-wrap items-stretch gap-2 px-density-4 py-density-2\"\n >\n {entry.layers.map((layer, index) => {\n const active = layer.origin === selectedOrigin;\n return (\n <button\n key={layer.origin}\n type=\"button\"\n aria-pressed={active}\n title={layer.path}\n onClick={() => onSelect(layer)}\n className={cn(\n \"flex min-w-44 max-w-full flex-col gap-1 rounded-md border px-3 py-2 text-left text-xs transition\",\n active\n ? \"border-primary bg-primary/5\"\n : \"border-border hover:bg-muted\",\n )}\n >\n <span className=\"flex min-w-0 items-center gap-1.5 font-medium\">\n <span className=\"text-muted-foreground\">{index + 1}.</span>\n <span className=\"truncate\">{layerLabel(layer.origin)}</span>\n {!layer.editable ? (\n <UiLock\n className=\"text-muted-foreground\"\n aria-label=\"read-only\"\n />\n ) : null}\n </span>\n <span className=\"flex flex-wrap items-center gap-1.5\">\n {layer.source === \"none\" ? (\n <span className=\"text-muted-foreground\">unset</span>\n ) : (\n <PromptSourceBadge source={layer.source} />\n )}\n {layer.fields && layer.fields.length > 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {layer.fields.join(\", \")}\n </span>\n ) : null}\n {effective?.origin === layer.origin ? (\n <Badge\n variant=\"soft\"\n tone=\"success\"\n size=\"xs\"\n icon={UiCheck}\n clickToCopy={false}\n >\n effective\n </Badge>\n ) : null}\n </span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,iBAAiB,EAC/B,OACA,gBACA,YACwB;CACxB,MAAM,YAAY,eAAe,KAAK;CACtC,IAAI,MAAM,OAAO,WAAW,GAC1B,OACE,oBAAC,KAAD;EAAG,WAAU;EAA0D,UAAA;CAEpE,CAAA;CAGP,OACE,oBAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,WAAU;EAET,UAAA,MAAM,OAAO,KAAK,OAAO,UAAU;GAClC,MAAM,SAAS,MAAM,WAAW;GAChC,OACE,qBAAC,UAAD;IAEE,MAAK;IACL,gBAAc;IACd,OAAO,MAAM;IACb,eAAe,SAAS,KAAK;IAC7B,WAAW,GACT,oGACA,SACI,gCACA,8BACN;IAXF,UAAA,CAaE,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACE,qBAAC,QAAD;OAAM,WAAU;OAAhB,UAAA,CAAyC,QAAQ,GAAE,GAAO;;MAC1D,oBAAC,QAAD;OAAM,WAAU;OAAY,UAAA,WAAW,MAAM,MAAM;MAAQ,CAAA;MAC1D,CAAC,MAAM,WACN,oBAAC,QAAD;OACE,WAAU;OACV,cAAW;MACZ,CAAA,IACC;KACA;IACN,CAAA,GAAA,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACG,MAAM,WAAW,SAChB,oBAAC,QAAD;OAAM,WAAU;OAAwB,UAAA;MAAW,CAAA,IAEnD,oBAAC,mBAAD,EAAmB,QAAQ,MAAM,OAAS,CAAA;MAE3C,MAAM,UAAU,MAAM,OAAO,SAAS,IACrC,oBAAC,QAAD;OAAM,WAAU;OACb,UAAA,MAAM,OAAO,KAAK,IAAI;MACnB,CAAA,IACJ;MACH,WAAW,WAAW,MAAM,SAC3B,oBAAC,OAAD;OACE,SAAQ;OACR,MAAK;OACL,MAAK;OACL,MAAM;OACN,aAAa;OACd,UAAA;MAEM,CAAA,IACL;KACA;IACA,CAAA,CAAA;GA7CD,GAAA,MAAM,MA6CL;EAEZ,CAAC;CACE,CAAA;AAET"}
|
|
@@ -56,7 +56,7 @@ function PromptPage({ entry, adapter, models, families, onBack, onSaved, extraTa
|
|
|
56
56
|
detail
|
|
57
57
|
});
|
|
58
58
|
setDraft(require_prompt_page_model.draftFor(detail));
|
|
59
|
-
setSaveSource(require_prompt_page_model.initialSaveSource(detail));
|
|
59
|
+
setSaveSource(require_prompt_page_model.initialSaveSource(detail, layer));
|
|
60
60
|
setPath(require_prompt_page_model.defaultFilePath(entry, layer, detail));
|
|
61
61
|
setSaveError("");
|
|
62
62
|
setConflict(false);
|
|
@@ -239,6 +239,7 @@ function PromptPage({ entry, adapter, models, families, onBack, onSaved, extraTa
|
|
|
239
239
|
children: renderPanel()
|
|
240
240
|
}),
|
|
241
241
|
state.status === "ready" && !readOnly ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PromptPageSaveBar.PromptPageSaveBar, {
|
|
242
|
+
sources: selectedLayer.saveSources,
|
|
242
243
|
source: saveSource,
|
|
243
244
|
onSourceChange: setSaveSource,
|
|
244
245
|
path,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptPage.cjs","names":["PROMPT_PAGE_TAB","UiFileCode","UiEye","UiDiff","useState","defaultEditLayer","useMemo","isDraftDirty","isPromptPageDirty","useCallback","draftFor","initialSaveSource","defaultFilePath","useRef","errorMessage","isConflictError","buildSavePayload","pageTabs","draftRaw","Button","PromptPageEditor","PromptPagePreview","CodeDiff","_Fragment","cn","PromptPageHeader","PromptLayerStrip","UiLock","layerLabel","Tabs","PromptPageSaveBar","Modal"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiDiff, UiEye, UiFileCode, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Tabs, type TabItem } from \"../../../layout/Tabs\";\nimport { Modal } from \"../../../overlay/Modal\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { CodeDiff } from \"../../CodeDiff\";\nimport type { SpecRuntimeFamily } from \"../../runtime/runtime-mode\";\nimport type { PromptSpecDetail } from \"../PromptPicker/types\";\nimport { defaultEditLayer, layerLabel } from \"./prompt-catalog-model\";\nimport {\n PROMPT_PAGE_TAB,\n buildSavePayload,\n defaultFilePath,\n draftFor,\n draftRaw,\n errorMessage,\n initialSaveSource,\n isConflictError,\n isDraftDirty,\n isPromptPageDirty,\n pageTabs,\n type PromptDraft,\n type PromptSaveSource,\n} from \"./prompt-page-model\";\nimport { PromptLayerStrip } from \"./PromptLayerStrip\";\nimport { PromptPageEditor } from \"./PromptPageEditor\";\nimport { PromptPageHeader } from \"./PromptPageHeader\";\nimport { PromptPagePreview } from \"./PromptPagePreview\";\nimport { PromptPageSaveBar } from \"./PromptPageSaveBar\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageAdapter,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptPageProps = {\n entry: PromptCatalogEntry;\n adapter: PromptPageAdapter;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n onBack?: (() => void) | undefined;\n onSaved?:\n | ((detail: PromptSpecDetail, layer: PromptCatalogLayer) => void)\n | undefined;\n extraTabs?: PromptPageTab[] | undefined;\n initialLayerOrigin?: string | undefined;\n className?: string | undefined;\n};\n\ntype LayerState =\n | { status: \"idle\" }\n | { status: \"loading\" }\n | { status: \"error\"; message: string }\n | { status: \"ready\"; detail: PromptSpecDetail };\n\ntype PendingTransition =\n | { type: \"back\" }\n | { type: \"reload\" }\n | { type: \"layer\"; origin: string };\n\nconst TAB_ICONS: Record<string, TabItem[\"icon\"]> = {\n [PROMPT_PAGE_TAB.prompt]: UiFileCode,\n [PROMPT_PAGE_TAB.preview]: UiEye,\n [PROMPT_PAGE_TAB.diff]: UiDiff,\n};\n\nconst EMPTY_DRAFT: PromptDraft = { mode: \"raw\", raw: \"\", value: undefined };\n\n// PromptPage is the dedicated view of one prompt: what runs and from which\n// layer, the layer chain, and an editor for the layer the user picks — raw or\n// structured — with preview, diff against the built-in, and a save that\n// refuses to clobber a layer that moved on since it was loaded.\nexport function PromptPage({\n entry,\n adapter,\n models,\n families,\n onBack,\n onSaved,\n extraTabs,\n initialLayerOrigin,\n className,\n}: PromptPageProps) {\n const [selectedOrigin, setSelectedOrigin] = useState<string | undefined>(\n () =>\n initialLayerOrigin ??\n defaultEditLayer(entry)?.origin ??\n entry.layers[0]?.origin,\n );\n const selectedLayer = useMemo(\n () => entry.layers.find((layer) => layer.origin === selectedOrigin),\n [entry, selectedOrigin],\n );\n const [state, setState] = useState<LayerState>({ status: \"idle\" });\n const [draft, setDraft] = useState<PromptDraft>(EMPTY_DRAFT);\n const [saveSource, setSaveSource] = useState<PromptSaveSource>(\"inline\");\n const [path, setPath] = useState(\"\");\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState(\"\");\n const [conflict, setConflict] = useState(false);\n const [pendingTransition, setPendingTransition] =\n useState<PendingTransition | null>(null);\n const [tab, setTab] = useState<string>(PROMPT_PAGE_TAB.prompt);\n const [reloadToken, setReloadToken] = useState(0);\n\n const readOnly = !selectedLayer?.editable;\n const draftDirty =\n state.status === \"ready\" && isDraftDirty(draft, state.detail);\n const dirty =\n state.status === \"ready\" && selectedLayer\n ? isPromptPageDirty({\n draft,\n detail: state.detail,\n source: saveSource,\n path,\n entry,\n layer: selectedLayer,\n })\n : false;\n\n const applyDetail = useCallback(\n (detail: PromptSpecDetail, layer: PromptCatalogLayer) => {\n setState({ status: \"ready\", detail });\n setDraft(draftFor(detail));\n setSaveSource(initialSaveSource(detail));\n setPath(defaultFilePath(entry, layer, detail));\n setSaveError(\"\");\n setConflict(false);\n },\n [entry],\n );\n\n // The load is keyed on the layer's identity, not the entry object: a host\n // that refetches its catalog while the user is editing must not reset the\n // draft. The latest adapter/entry are read through a ref for the same reason.\n const latest = useRef({ adapter, entry, applyDetail });\n latest.current = { adapter, entry, applyDetail };\n const layerKey = selectedLayer\n ? `${selectedLayer.origin}\\u0000${selectedLayer.scope ?? \"\"}`\n : \"\";\n useEffect(() => {\n const layer = latest.current.entry.layers.find(\n (candidate) =>\n `${candidate.origin}\\u0000${candidate.scope ?? \"\"}` === layerKey,\n );\n if (!layer) {\n setState({ status: \"idle\" });\n return;\n }\n let cancelled = false;\n setState({ status: \"loading\" });\n latest.current.adapter.loadDetail(latest.current.entry, layer).then(\n (detail) => {\n if (!cancelled) latest.current.applyDetail(detail, layer);\n },\n (cause: unknown) => {\n if (!cancelled)\n setState({\n status: \"error\",\n message: errorMessage(cause, \"failed to load prompt\"),\n });\n },\n );\n return () => {\n cancelled = true;\n };\n }, [layerKey, reloadToken]);\n\n useEffect(() => {\n if (!dirty) return;\n const guard = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n window.addEventListener(\"beforeunload\", guard);\n return () => window.removeEventListener(\"beforeunload\", guard);\n }, [dirty]);\n\n const reload = () => setReloadToken((token) => token + 1);\n\n function runTransition(transition: PendingTransition) {\n setPendingTransition(null);\n if (transition.type === \"back\") {\n onBack?.();\n return;\n }\n if (transition.type === \"reload\") {\n reload();\n return;\n }\n setSelectedOrigin(transition.origin);\n }\n\n function requestTransition(transition: PendingTransition) {\n if (dirty) {\n setPendingTransition(transition);\n return;\n }\n runTransition(transition);\n }\n\n async function persist(\n build: (\n detail: PromptSpecDetail,\n ) => Parameters<PromptPageAdapter[\"saveDetail\"]>[2],\n failure: string,\n ) {\n if (state.status !== \"ready\" || !selectedLayer) return;\n setSaving(true);\n setSaveError(\"\");\n setConflict(false);\n try {\n const next = await adapter.saveDetail(\n entry,\n selectedLayer,\n build(state.detail),\n );\n applyDetail(next, selectedLayer);\n onSaved?.(next, selectedLayer);\n } catch (cause) {\n const message = errorMessage(cause, failure);\n setSaveError(message);\n setConflict(isConflictError(message));\n } finally {\n setSaving(false);\n }\n }\n\n const save = () =>\n persist(\n (detail) => buildSavePayload(draft, detail, saveSource, path),\n \"save failed\",\n );\n const remove = () =>\n persist(\n (detail) => ({ source: \"default\", baseRaw: detail.raw }),\n \"remove failed\",\n );\n\n const render = adapter.render;\n const tabs = pageTabs({\n canPreview: render !== undefined,\n canDiff: entry.defaultRaw !== undefined,\n extraTabs,\n }).map((item) => {\n const icon = TAB_ICONS[item.id];\n return icon ? { ...item, icon } : item;\n });\n const activeTab = tabs.some((item) => item.id === tab)\n ? tab\n : PROMPT_PAGE_TAB.prompt;\n const currentRaw =\n state.status === \"ready\"\n ? draftDirty\n ? draftRaw(draft)\n : state.detail.raw\n : \"\";\n\n function selectLayer(layer: PromptCatalogLayer) {\n if (layer.origin === selectedOrigin) return;\n requestTransition({ type: \"layer\", origin: layer.origin });\n }\n\n function renderPanel() {\n if (state.status === \"loading\" || state.status === \"idle\") {\n return <p className=\"text-sm text-muted-foreground\">Loading prompt…</p>;\n }\n if (state.status === \"error\") {\n return (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 text-sm text-destructive\"\n >\n <span>{state.message}</span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={reload}>\n Retry\n </Button>\n </div>\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.prompt) {\n return (\n <PromptPageEditor\n detail={state.detail}\n draft={draft}\n onChange={setDraft}\n readOnly={readOnly}\n models={models}\n families={families}\n {...(entry.effective.mode\n ? { effectiveMode: entry.effective.mode }\n : {})}\n {...(entry.effective.model\n ? { effectiveModel: entry.effective.model }\n : {})}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.preview && render) {\n return (\n <PromptPagePreview\n entry={entry}\n render={(input) => render(entry, input)}\n draftRaw={draftDirty ? currentRaw : undefined}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.diff && entry.defaultRaw !== undefined) {\n return (\n <CodeDiff\n original={entry.defaultRaw}\n modified={currentRaw}\n language=\"markdown\"\n />\n );\n }\n return extraTabs?.find((item) => item.id === activeTab)?.content ?? null;\n }\n\n return (\n <>\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n <PromptPageHeader\n entry={entry}\n selectedLayer={selectedLayer}\n {...(onBack\n ? { onBack: () => requestTransition({ type: \"back\" }) }\n : {})}\n />\n <PromptLayerStrip\n entry={entry}\n selectedOrigin={selectedOrigin}\n onSelect={selectLayer}\n />\n {readOnly && selectedLayer ? (\n <div\n role=\"note\"\n className=\"mx-density-4 mb-2 flex items-center gap-2 rounded-md border border-border bg-muted px-3 py-2 text-xs\"\n >\n <UiLock className=\"shrink-0 text-muted-foreground\" />\n <span>\n {layerLabel(selectedLayer.origin)} is read-only from here —{\" \"}\n <span className=\"font-mono\">{selectedLayer.path}</span>. Edit it\n directly or pick an editable layer.\n </span>\n </div>\n ) : null}\n <Tabs\n tabs={tabs}\n value={activeTab}\n onChange={setTab}\n className=\"px-density-4\"\n />\n <div className=\"min-h-0 flex-1 overflow-y-auto px-density-4 py-density-3\">\n {renderPanel()}\n </div>\n {state.status === \"ready\" && !readOnly ? (\n <PromptPageSaveBar\n source={saveSource}\n onSourceChange={setSaveSource}\n path={path}\n onPathChange={setPath}\n dirty={dirty}\n saving={saving}\n canRemove={state.detail.source !== \"default\"}\n error={saveError}\n conflict={conflict}\n onSave={save}\n onRemove={remove}\n onReload={() => requestTransition({ type: \"reload\" })}\n />\n ) : null}\n </div>\n {pendingTransition ? (\n <Modal\n open\n onClose={() => setPendingTransition(null)}\n title=\"Discard unsaved prompt changes?\"\n size=\"sm\"\n expandable={false}\n footer={\n <div className=\"flex w-full justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => setPendingTransition(null)}\n >\n Keep editing\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n onClick={() => runTransition(pendingTransition)}\n >\n Discard changes\n </Button>\n </div>\n }\n >\n <p className=\"text-sm text-muted-foreground\">\n Your prompt content, save location, or file path changes will be\n lost.\n </p>\n </Modal>\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PromptPage.cjs","names":["PROMPT_PAGE_TAB","UiFileCode","UiEye","UiDiff","useState","defaultEditLayer","useMemo","isDraftDirty","isPromptPageDirty","useCallback","draftFor","initialSaveSource","defaultFilePath","useRef","errorMessage","isConflictError","buildSavePayload","pageTabs","draftRaw","Button","PromptPageEditor","PromptPagePreview","CodeDiff","_Fragment","cn","PromptPageHeader","PromptLayerStrip","UiLock","layerLabel","Tabs","PromptPageSaveBar","Modal"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiDiff, UiEye, UiFileCode, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Tabs, type TabItem } from \"../../../layout/Tabs\";\nimport { Modal } from \"../../../overlay/Modal\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { CodeDiff } from \"../../CodeDiff\";\nimport type { SpecRuntimeFamily } from \"../../runtime/runtime-mode\";\nimport type { PromptSpecDetail } from \"../PromptPicker/types\";\nimport { defaultEditLayer, layerLabel } from \"./prompt-catalog-model\";\nimport {\n PROMPT_PAGE_TAB,\n buildSavePayload,\n defaultFilePath,\n draftFor,\n draftRaw,\n errorMessage,\n initialSaveSource,\n isConflictError,\n isDraftDirty,\n isPromptPageDirty,\n pageTabs,\n type PromptDraft,\n type PromptSaveSource,\n} from \"./prompt-page-model\";\nimport { PromptLayerStrip } from \"./PromptLayerStrip\";\nimport { PromptPageEditor } from \"./PromptPageEditor\";\nimport { PromptPageHeader } from \"./PromptPageHeader\";\nimport { PromptPagePreview } from \"./PromptPagePreview\";\nimport { PromptPageSaveBar } from \"./PromptPageSaveBar\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageAdapter,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptPageProps = {\n entry: PromptCatalogEntry;\n adapter: PromptPageAdapter;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n onBack?: (() => void) | undefined;\n onSaved?:\n | ((detail: PromptSpecDetail, layer: PromptCatalogLayer) => void)\n | undefined;\n extraTabs?: PromptPageTab[] | undefined;\n initialLayerOrigin?: string | undefined;\n className?: string | undefined;\n};\n\ntype LayerState =\n | { status: \"idle\" }\n | { status: \"loading\" }\n | { status: \"error\"; message: string }\n | { status: \"ready\"; detail: PromptSpecDetail };\n\ntype PendingTransition =\n | { type: \"back\" }\n | { type: \"reload\" }\n | { type: \"layer\"; origin: string };\n\nconst TAB_ICONS: Record<string, TabItem[\"icon\"]> = {\n [PROMPT_PAGE_TAB.prompt]: UiFileCode,\n [PROMPT_PAGE_TAB.preview]: UiEye,\n [PROMPT_PAGE_TAB.diff]: UiDiff,\n};\n\nconst EMPTY_DRAFT: PromptDraft = { mode: \"raw\", raw: \"\", value: undefined };\n\n// PromptPage is the dedicated view of one prompt: what runs and from which\n// layer, the layer chain, and an editor for the layer the user picks — raw or\n// structured — with preview, diff against the built-in, and a save that\n// refuses to clobber a layer that moved on since it was loaded.\nexport function PromptPage({\n entry,\n adapter,\n models,\n families,\n onBack,\n onSaved,\n extraTabs,\n initialLayerOrigin,\n className,\n}: PromptPageProps) {\n const [selectedOrigin, setSelectedOrigin] = useState<string | undefined>(\n () =>\n initialLayerOrigin ??\n defaultEditLayer(entry)?.origin ??\n entry.layers[0]?.origin,\n );\n const selectedLayer = useMemo(\n () => entry.layers.find((layer) => layer.origin === selectedOrigin),\n [entry, selectedOrigin],\n );\n const [state, setState] = useState<LayerState>({ status: \"idle\" });\n const [draft, setDraft] = useState<PromptDraft>(EMPTY_DRAFT);\n const [saveSource, setSaveSource] = useState<PromptSaveSource>(\"inline\");\n const [path, setPath] = useState(\"\");\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState(\"\");\n const [conflict, setConflict] = useState(false);\n const [pendingTransition, setPendingTransition] =\n useState<PendingTransition | null>(null);\n const [tab, setTab] = useState<string>(PROMPT_PAGE_TAB.prompt);\n const [reloadToken, setReloadToken] = useState(0);\n\n const readOnly = !selectedLayer?.editable;\n const draftDirty =\n state.status === \"ready\" && isDraftDirty(draft, state.detail);\n const dirty =\n state.status === \"ready\" && selectedLayer\n ? isPromptPageDirty({\n draft,\n detail: state.detail,\n source: saveSource,\n path,\n entry,\n layer: selectedLayer,\n })\n : false;\n\n const applyDetail = useCallback(\n (detail: PromptSpecDetail, layer: PromptCatalogLayer) => {\n setState({ status: \"ready\", detail });\n setDraft(draftFor(detail));\n setSaveSource(initialSaveSource(detail, layer));\n setPath(defaultFilePath(entry, layer, detail));\n setSaveError(\"\");\n setConflict(false);\n },\n [entry],\n );\n\n // The load is keyed on the layer's identity, not the entry object: a host\n // that refetches its catalog while the user is editing must not reset the\n // draft. The latest adapter/entry are read through a ref for the same reason.\n const latest = useRef({ adapter, entry, applyDetail });\n latest.current = { adapter, entry, applyDetail };\n const layerKey = selectedLayer\n ? `${selectedLayer.origin}\\u0000${selectedLayer.scope ?? \"\"}`\n : \"\";\n useEffect(() => {\n const layer = latest.current.entry.layers.find(\n (candidate) =>\n `${candidate.origin}\\u0000${candidate.scope ?? \"\"}` === layerKey,\n );\n if (!layer) {\n setState({ status: \"idle\" });\n return;\n }\n let cancelled = false;\n setState({ status: \"loading\" });\n latest.current.adapter.loadDetail(latest.current.entry, layer).then(\n (detail) => {\n if (!cancelled) latest.current.applyDetail(detail, layer);\n },\n (cause: unknown) => {\n if (!cancelled)\n setState({\n status: \"error\",\n message: errorMessage(cause, \"failed to load prompt\"),\n });\n },\n );\n return () => {\n cancelled = true;\n };\n }, [layerKey, reloadToken]);\n\n useEffect(() => {\n if (!dirty) return;\n const guard = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n window.addEventListener(\"beforeunload\", guard);\n return () => window.removeEventListener(\"beforeunload\", guard);\n }, [dirty]);\n\n const reload = () => setReloadToken((token) => token + 1);\n\n function runTransition(transition: PendingTransition) {\n setPendingTransition(null);\n if (transition.type === \"back\") {\n onBack?.();\n return;\n }\n if (transition.type === \"reload\") {\n reload();\n return;\n }\n setSelectedOrigin(transition.origin);\n }\n\n function requestTransition(transition: PendingTransition) {\n if (dirty) {\n setPendingTransition(transition);\n return;\n }\n runTransition(transition);\n }\n\n async function persist(\n build: (\n detail: PromptSpecDetail,\n ) => Parameters<PromptPageAdapter[\"saveDetail\"]>[2],\n failure: string,\n ) {\n if (state.status !== \"ready\" || !selectedLayer) return;\n setSaving(true);\n setSaveError(\"\");\n setConflict(false);\n try {\n const next = await adapter.saveDetail(\n entry,\n selectedLayer,\n build(state.detail),\n );\n applyDetail(next, selectedLayer);\n onSaved?.(next, selectedLayer);\n } catch (cause) {\n const message = errorMessage(cause, failure);\n setSaveError(message);\n setConflict(isConflictError(message));\n } finally {\n setSaving(false);\n }\n }\n\n const save = () =>\n persist(\n (detail) => buildSavePayload(draft, detail, saveSource, path),\n \"save failed\",\n );\n const remove = () =>\n persist(\n (detail) => ({ source: \"default\", baseRaw: detail.raw }),\n \"remove failed\",\n );\n\n const render = adapter.render;\n const tabs = pageTabs({\n canPreview: render !== undefined,\n canDiff: entry.defaultRaw !== undefined,\n extraTabs,\n }).map((item) => {\n const icon = TAB_ICONS[item.id];\n return icon ? { ...item, icon } : item;\n });\n const activeTab = tabs.some((item) => item.id === tab)\n ? tab\n : PROMPT_PAGE_TAB.prompt;\n const currentRaw =\n state.status === \"ready\"\n ? draftDirty\n ? draftRaw(draft)\n : state.detail.raw\n : \"\";\n\n function selectLayer(layer: PromptCatalogLayer) {\n if (layer.origin === selectedOrigin) return;\n requestTransition({ type: \"layer\", origin: layer.origin });\n }\n\n function renderPanel() {\n if (state.status === \"loading\" || state.status === \"idle\") {\n return <p className=\"text-sm text-muted-foreground\">Loading prompt…</p>;\n }\n if (state.status === \"error\") {\n return (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 text-sm text-destructive\"\n >\n <span>{state.message}</span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={reload}>\n Retry\n </Button>\n </div>\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.prompt) {\n return (\n <PromptPageEditor\n detail={state.detail}\n draft={draft}\n onChange={setDraft}\n readOnly={readOnly}\n models={models}\n families={families}\n {...(entry.effective.mode\n ? { effectiveMode: entry.effective.mode }\n : {})}\n {...(entry.effective.model\n ? { effectiveModel: entry.effective.model }\n : {})}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.preview && render) {\n return (\n <PromptPagePreview\n entry={entry}\n render={(input) => render(entry, input)}\n draftRaw={draftDirty ? currentRaw : undefined}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.diff && entry.defaultRaw !== undefined) {\n return (\n <CodeDiff\n original={entry.defaultRaw}\n modified={currentRaw}\n language=\"markdown\"\n />\n );\n }\n return extraTabs?.find((item) => item.id === activeTab)?.content ?? null;\n }\n\n return (\n <>\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n <PromptPageHeader\n entry={entry}\n selectedLayer={selectedLayer}\n {...(onBack\n ? { onBack: () => requestTransition({ type: \"back\" }) }\n : {})}\n />\n <PromptLayerStrip\n entry={entry}\n selectedOrigin={selectedOrigin}\n onSelect={selectLayer}\n />\n {readOnly && selectedLayer ? (\n <div\n role=\"note\"\n className=\"mx-density-4 mb-2 flex items-center gap-2 rounded-md border border-border bg-muted px-3 py-2 text-xs\"\n >\n <UiLock className=\"shrink-0 text-muted-foreground\" />\n <span>\n {layerLabel(selectedLayer.origin)} is read-only from here —{\" \"}\n <span className=\"font-mono\">{selectedLayer.path}</span>. Edit it\n directly or pick an editable layer.\n </span>\n </div>\n ) : null}\n <Tabs\n tabs={tabs}\n value={activeTab}\n onChange={setTab}\n className=\"px-density-4\"\n />\n <div className=\"min-h-0 flex-1 overflow-y-auto px-density-4 py-density-3\">\n {renderPanel()}\n </div>\n {state.status === \"ready\" && !readOnly ? (\n <PromptPageSaveBar\n sources={selectedLayer.saveSources}\n source={saveSource}\n onSourceChange={setSaveSource}\n path={path}\n onPathChange={setPath}\n dirty={dirty}\n saving={saving}\n canRemove={state.detail.source !== \"default\"}\n error={saveError}\n conflict={conflict}\n onSave={save}\n onRemove={remove}\n onReload={() => requestTransition({ type: \"reload\" })}\n />\n ) : null}\n </div>\n {pendingTransition ? (\n <Modal\n open\n onClose={() => setPendingTransition(null)}\n title=\"Discard unsaved prompt changes?\"\n size=\"sm\"\n expandable={false}\n footer={\n <div className=\"flex w-full justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => setPendingTransition(null)}\n >\n Keep editing\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n onClick={() => runTransition(pendingTransition)}\n >\n Discard changes\n </Button>\n </div>\n }\n >\n <p className=\"text-sm text-muted-foreground\">\n Your prompt content, save location, or file path changes will be\n lost.\n </p>\n </Modal>\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptPage.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/PromptPage.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAsB9D,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EACJ,CAAC,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAC/D,SAAS,CAAC;IACd,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAyBF,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,EACN,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,SAAS,GACV,EAAE,eAAe,+
|
|
1
|
+
{"version":3,"file":"PromptPage.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/PromptPage.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAsB9D,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EACJ,CAAC,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAC/D,SAAS,CAAC;IACd,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAyBF,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,EACN,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,SAAS,GACV,EAAE,eAAe,+BAqUjB"}
|
|
@@ -56,7 +56,7 @@ function PromptPage({ entry, adapter, models, families, onBack, onSaved, extraTa
|
|
|
56
56
|
detail
|
|
57
57
|
});
|
|
58
58
|
setDraft(draftFor(detail));
|
|
59
|
-
setSaveSource(initialSaveSource(detail));
|
|
59
|
+
setSaveSource(initialSaveSource(detail, layer));
|
|
60
60
|
setPath(defaultFilePath(entry, layer, detail));
|
|
61
61
|
setSaveError("");
|
|
62
62
|
setConflict(false);
|
|
@@ -239,6 +239,7 @@ function PromptPage({ entry, adapter, models, families, onBack, onSaved, extraTa
|
|
|
239
239
|
children: renderPanel()
|
|
240
240
|
}),
|
|
241
241
|
state.status === "ready" && !readOnly ? /* @__PURE__ */ jsx(PromptPageSaveBar, {
|
|
242
|
+
sources: selectedLayer.saveSources,
|
|
242
243
|
source: saveSource,
|
|
243
244
|
onSourceChange: setSaveSource,
|
|
244
245
|
path,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptPage.js","names":["_Fragment"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiDiff, UiEye, UiFileCode, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Tabs, type TabItem } from \"../../../layout/Tabs\";\nimport { Modal } from \"../../../overlay/Modal\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { CodeDiff } from \"../../CodeDiff\";\nimport type { SpecRuntimeFamily } from \"../../runtime/runtime-mode\";\nimport type { PromptSpecDetail } from \"../PromptPicker/types\";\nimport { defaultEditLayer, layerLabel } from \"./prompt-catalog-model\";\nimport {\n PROMPT_PAGE_TAB,\n buildSavePayload,\n defaultFilePath,\n draftFor,\n draftRaw,\n errorMessage,\n initialSaveSource,\n isConflictError,\n isDraftDirty,\n isPromptPageDirty,\n pageTabs,\n type PromptDraft,\n type PromptSaveSource,\n} from \"./prompt-page-model\";\nimport { PromptLayerStrip } from \"./PromptLayerStrip\";\nimport { PromptPageEditor } from \"./PromptPageEditor\";\nimport { PromptPageHeader } from \"./PromptPageHeader\";\nimport { PromptPagePreview } from \"./PromptPagePreview\";\nimport { PromptPageSaveBar } from \"./PromptPageSaveBar\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageAdapter,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptPageProps = {\n entry: PromptCatalogEntry;\n adapter: PromptPageAdapter;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n onBack?: (() => void) | undefined;\n onSaved?:\n | ((detail: PromptSpecDetail, layer: PromptCatalogLayer) => void)\n | undefined;\n extraTabs?: PromptPageTab[] | undefined;\n initialLayerOrigin?: string | undefined;\n className?: string | undefined;\n};\n\ntype LayerState =\n | { status: \"idle\" }\n | { status: \"loading\" }\n | { status: \"error\"; message: string }\n | { status: \"ready\"; detail: PromptSpecDetail };\n\ntype PendingTransition =\n | { type: \"back\" }\n | { type: \"reload\" }\n | { type: \"layer\"; origin: string };\n\nconst TAB_ICONS: Record<string, TabItem[\"icon\"]> = {\n [PROMPT_PAGE_TAB.prompt]: UiFileCode,\n [PROMPT_PAGE_TAB.preview]: UiEye,\n [PROMPT_PAGE_TAB.diff]: UiDiff,\n};\n\nconst EMPTY_DRAFT: PromptDraft = { mode: \"raw\", raw: \"\", value: undefined };\n\n// PromptPage is the dedicated view of one prompt: what runs and from which\n// layer, the layer chain, and an editor for the layer the user picks — raw or\n// structured — with preview, diff against the built-in, and a save that\n// refuses to clobber a layer that moved on since it was loaded.\nexport function PromptPage({\n entry,\n adapter,\n models,\n families,\n onBack,\n onSaved,\n extraTabs,\n initialLayerOrigin,\n className,\n}: PromptPageProps) {\n const [selectedOrigin, setSelectedOrigin] = useState<string | undefined>(\n () =>\n initialLayerOrigin ??\n defaultEditLayer(entry)?.origin ??\n entry.layers[0]?.origin,\n );\n const selectedLayer = useMemo(\n () => entry.layers.find((layer) => layer.origin === selectedOrigin),\n [entry, selectedOrigin],\n );\n const [state, setState] = useState<LayerState>({ status: \"idle\" });\n const [draft, setDraft] = useState<PromptDraft>(EMPTY_DRAFT);\n const [saveSource, setSaveSource] = useState<PromptSaveSource>(\"inline\");\n const [path, setPath] = useState(\"\");\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState(\"\");\n const [conflict, setConflict] = useState(false);\n const [pendingTransition, setPendingTransition] =\n useState<PendingTransition | null>(null);\n const [tab, setTab] = useState<string>(PROMPT_PAGE_TAB.prompt);\n const [reloadToken, setReloadToken] = useState(0);\n\n const readOnly = !selectedLayer?.editable;\n const draftDirty =\n state.status === \"ready\" && isDraftDirty(draft, state.detail);\n const dirty =\n state.status === \"ready\" && selectedLayer\n ? isPromptPageDirty({\n draft,\n detail: state.detail,\n source: saveSource,\n path,\n entry,\n layer: selectedLayer,\n })\n : false;\n\n const applyDetail = useCallback(\n (detail: PromptSpecDetail, layer: PromptCatalogLayer) => {\n setState({ status: \"ready\", detail });\n setDraft(draftFor(detail));\n setSaveSource(initialSaveSource(detail));\n setPath(defaultFilePath(entry, layer, detail));\n setSaveError(\"\");\n setConflict(false);\n },\n [entry],\n );\n\n // The load is keyed on the layer's identity, not the entry object: a host\n // that refetches its catalog while the user is editing must not reset the\n // draft. The latest adapter/entry are read through a ref for the same reason.\n const latest = useRef({ adapter, entry, applyDetail });\n latest.current = { adapter, entry, applyDetail };\n const layerKey = selectedLayer\n ? `${selectedLayer.origin}\\u0000${selectedLayer.scope ?? \"\"}`\n : \"\";\n useEffect(() => {\n const layer = latest.current.entry.layers.find(\n (candidate) =>\n `${candidate.origin}\\u0000${candidate.scope ?? \"\"}` === layerKey,\n );\n if (!layer) {\n setState({ status: \"idle\" });\n return;\n }\n let cancelled = false;\n setState({ status: \"loading\" });\n latest.current.adapter.loadDetail(latest.current.entry, layer).then(\n (detail) => {\n if (!cancelled) latest.current.applyDetail(detail, layer);\n },\n (cause: unknown) => {\n if (!cancelled)\n setState({\n status: \"error\",\n message: errorMessage(cause, \"failed to load prompt\"),\n });\n },\n );\n return () => {\n cancelled = true;\n };\n }, [layerKey, reloadToken]);\n\n useEffect(() => {\n if (!dirty) return;\n const guard = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n window.addEventListener(\"beforeunload\", guard);\n return () => window.removeEventListener(\"beforeunload\", guard);\n }, [dirty]);\n\n const reload = () => setReloadToken((token) => token + 1);\n\n function runTransition(transition: PendingTransition) {\n setPendingTransition(null);\n if (transition.type === \"back\") {\n onBack?.();\n return;\n }\n if (transition.type === \"reload\") {\n reload();\n return;\n }\n setSelectedOrigin(transition.origin);\n }\n\n function requestTransition(transition: PendingTransition) {\n if (dirty) {\n setPendingTransition(transition);\n return;\n }\n runTransition(transition);\n }\n\n async function persist(\n build: (\n detail: PromptSpecDetail,\n ) => Parameters<PromptPageAdapter[\"saveDetail\"]>[2],\n failure: string,\n ) {\n if (state.status !== \"ready\" || !selectedLayer) return;\n setSaving(true);\n setSaveError(\"\");\n setConflict(false);\n try {\n const next = await adapter.saveDetail(\n entry,\n selectedLayer,\n build(state.detail),\n );\n applyDetail(next, selectedLayer);\n onSaved?.(next, selectedLayer);\n } catch (cause) {\n const message = errorMessage(cause, failure);\n setSaveError(message);\n setConflict(isConflictError(message));\n } finally {\n setSaving(false);\n }\n }\n\n const save = () =>\n persist(\n (detail) => buildSavePayload(draft, detail, saveSource, path),\n \"save failed\",\n );\n const remove = () =>\n persist(\n (detail) => ({ source: \"default\", baseRaw: detail.raw }),\n \"remove failed\",\n );\n\n const render = adapter.render;\n const tabs = pageTabs({\n canPreview: render !== undefined,\n canDiff: entry.defaultRaw !== undefined,\n extraTabs,\n }).map((item) => {\n const icon = TAB_ICONS[item.id];\n return icon ? { ...item, icon } : item;\n });\n const activeTab = tabs.some((item) => item.id === tab)\n ? tab\n : PROMPT_PAGE_TAB.prompt;\n const currentRaw =\n state.status === \"ready\"\n ? draftDirty\n ? draftRaw(draft)\n : state.detail.raw\n : \"\";\n\n function selectLayer(layer: PromptCatalogLayer) {\n if (layer.origin === selectedOrigin) return;\n requestTransition({ type: \"layer\", origin: layer.origin });\n }\n\n function renderPanel() {\n if (state.status === \"loading\" || state.status === \"idle\") {\n return <p className=\"text-sm text-muted-foreground\">Loading prompt…</p>;\n }\n if (state.status === \"error\") {\n return (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 text-sm text-destructive\"\n >\n <span>{state.message}</span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={reload}>\n Retry\n </Button>\n </div>\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.prompt) {\n return (\n <PromptPageEditor\n detail={state.detail}\n draft={draft}\n onChange={setDraft}\n readOnly={readOnly}\n models={models}\n families={families}\n {...(entry.effective.mode\n ? { effectiveMode: entry.effective.mode }\n : {})}\n {...(entry.effective.model\n ? { effectiveModel: entry.effective.model }\n : {})}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.preview && render) {\n return (\n <PromptPagePreview\n entry={entry}\n render={(input) => render(entry, input)}\n draftRaw={draftDirty ? currentRaw : undefined}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.diff && entry.defaultRaw !== undefined) {\n return (\n <CodeDiff\n original={entry.defaultRaw}\n modified={currentRaw}\n language=\"markdown\"\n />\n );\n }\n return extraTabs?.find((item) => item.id === activeTab)?.content ?? null;\n }\n\n return (\n <>\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n <PromptPageHeader\n entry={entry}\n selectedLayer={selectedLayer}\n {...(onBack\n ? { onBack: () => requestTransition({ type: \"back\" }) }\n : {})}\n />\n <PromptLayerStrip\n entry={entry}\n selectedOrigin={selectedOrigin}\n onSelect={selectLayer}\n />\n {readOnly && selectedLayer ? (\n <div\n role=\"note\"\n className=\"mx-density-4 mb-2 flex items-center gap-2 rounded-md border border-border bg-muted px-3 py-2 text-xs\"\n >\n <UiLock className=\"shrink-0 text-muted-foreground\" />\n <span>\n {layerLabel(selectedLayer.origin)} is read-only from here —{\" \"}\n <span className=\"font-mono\">{selectedLayer.path}</span>. Edit it\n directly or pick an editable layer.\n </span>\n </div>\n ) : null}\n <Tabs\n tabs={tabs}\n value={activeTab}\n onChange={setTab}\n className=\"px-density-4\"\n />\n <div className=\"min-h-0 flex-1 overflow-y-auto px-density-4 py-density-3\">\n {renderPanel()}\n </div>\n {state.status === \"ready\" && !readOnly ? (\n <PromptPageSaveBar\n source={saveSource}\n onSourceChange={setSaveSource}\n path={path}\n onPathChange={setPath}\n dirty={dirty}\n saving={saving}\n canRemove={state.detail.source !== \"default\"}\n error={saveError}\n conflict={conflict}\n onSave={save}\n onRemove={remove}\n onReload={() => requestTransition({ type: \"reload\" })}\n />\n ) : null}\n </div>\n {pendingTransition ? (\n <Modal\n open\n onClose={() => setPendingTransition(null)}\n title=\"Discard unsaved prompt changes?\"\n size=\"sm\"\n expandable={false}\n footer={\n <div className=\"flex w-full justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => setPendingTransition(null)}\n >\n Keep editing\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n onClick={() => runTransition(pendingTransition)}\n >\n Discard changes\n </Button>\n </div>\n }\n >\n <p className=\"text-sm text-muted-foreground\">\n Your prompt content, save location, or file path changes will be\n lost.\n </p>\n </Modal>\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PromptPage.js","names":["_Fragment"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiDiff, UiEye, UiFileCode, UiLock } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Tabs, type TabItem } from \"../../../layout/Tabs\";\nimport { Modal } from \"../../../overlay/Modal\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { CodeDiff } from \"../../CodeDiff\";\nimport type { SpecRuntimeFamily } from \"../../runtime/runtime-mode\";\nimport type { PromptSpecDetail } from \"../PromptPicker/types\";\nimport { defaultEditLayer, layerLabel } from \"./prompt-catalog-model\";\nimport {\n PROMPT_PAGE_TAB,\n buildSavePayload,\n defaultFilePath,\n draftFor,\n draftRaw,\n errorMessage,\n initialSaveSource,\n isConflictError,\n isDraftDirty,\n isPromptPageDirty,\n pageTabs,\n type PromptDraft,\n type PromptSaveSource,\n} from \"./prompt-page-model\";\nimport { PromptLayerStrip } from \"./PromptLayerStrip\";\nimport { PromptPageEditor } from \"./PromptPageEditor\";\nimport { PromptPageHeader } from \"./PromptPageHeader\";\nimport { PromptPagePreview } from \"./PromptPagePreview\";\nimport { PromptPageSaveBar } from \"./PromptPageSaveBar\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageAdapter,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptPageProps = {\n entry: PromptCatalogEntry;\n adapter: PromptPageAdapter;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n onBack?: (() => void) | undefined;\n onSaved?:\n | ((detail: PromptSpecDetail, layer: PromptCatalogLayer) => void)\n | undefined;\n extraTabs?: PromptPageTab[] | undefined;\n initialLayerOrigin?: string | undefined;\n className?: string | undefined;\n};\n\ntype LayerState =\n | { status: \"idle\" }\n | { status: \"loading\" }\n | { status: \"error\"; message: string }\n | { status: \"ready\"; detail: PromptSpecDetail };\n\ntype PendingTransition =\n | { type: \"back\" }\n | { type: \"reload\" }\n | { type: \"layer\"; origin: string };\n\nconst TAB_ICONS: Record<string, TabItem[\"icon\"]> = {\n [PROMPT_PAGE_TAB.prompt]: UiFileCode,\n [PROMPT_PAGE_TAB.preview]: UiEye,\n [PROMPT_PAGE_TAB.diff]: UiDiff,\n};\n\nconst EMPTY_DRAFT: PromptDraft = { mode: \"raw\", raw: \"\", value: undefined };\n\n// PromptPage is the dedicated view of one prompt: what runs and from which\n// layer, the layer chain, and an editor for the layer the user picks — raw or\n// structured — with preview, diff against the built-in, and a save that\n// refuses to clobber a layer that moved on since it was loaded.\nexport function PromptPage({\n entry,\n adapter,\n models,\n families,\n onBack,\n onSaved,\n extraTabs,\n initialLayerOrigin,\n className,\n}: PromptPageProps) {\n const [selectedOrigin, setSelectedOrigin] = useState<string | undefined>(\n () =>\n initialLayerOrigin ??\n defaultEditLayer(entry)?.origin ??\n entry.layers[0]?.origin,\n );\n const selectedLayer = useMemo(\n () => entry.layers.find((layer) => layer.origin === selectedOrigin),\n [entry, selectedOrigin],\n );\n const [state, setState] = useState<LayerState>({ status: \"idle\" });\n const [draft, setDraft] = useState<PromptDraft>(EMPTY_DRAFT);\n const [saveSource, setSaveSource] = useState<PromptSaveSource>(\"inline\");\n const [path, setPath] = useState(\"\");\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState(\"\");\n const [conflict, setConflict] = useState(false);\n const [pendingTransition, setPendingTransition] =\n useState<PendingTransition | null>(null);\n const [tab, setTab] = useState<string>(PROMPT_PAGE_TAB.prompt);\n const [reloadToken, setReloadToken] = useState(0);\n\n const readOnly = !selectedLayer?.editable;\n const draftDirty =\n state.status === \"ready\" && isDraftDirty(draft, state.detail);\n const dirty =\n state.status === \"ready\" && selectedLayer\n ? isPromptPageDirty({\n draft,\n detail: state.detail,\n source: saveSource,\n path,\n entry,\n layer: selectedLayer,\n })\n : false;\n\n const applyDetail = useCallback(\n (detail: PromptSpecDetail, layer: PromptCatalogLayer) => {\n setState({ status: \"ready\", detail });\n setDraft(draftFor(detail));\n setSaveSource(initialSaveSource(detail, layer));\n setPath(defaultFilePath(entry, layer, detail));\n setSaveError(\"\");\n setConflict(false);\n },\n [entry],\n );\n\n // The load is keyed on the layer's identity, not the entry object: a host\n // that refetches its catalog while the user is editing must not reset the\n // draft. The latest adapter/entry are read through a ref for the same reason.\n const latest = useRef({ adapter, entry, applyDetail });\n latest.current = { adapter, entry, applyDetail };\n const layerKey = selectedLayer\n ? `${selectedLayer.origin}\\u0000${selectedLayer.scope ?? \"\"}`\n : \"\";\n useEffect(() => {\n const layer = latest.current.entry.layers.find(\n (candidate) =>\n `${candidate.origin}\\u0000${candidate.scope ?? \"\"}` === layerKey,\n );\n if (!layer) {\n setState({ status: \"idle\" });\n return;\n }\n let cancelled = false;\n setState({ status: \"loading\" });\n latest.current.adapter.loadDetail(latest.current.entry, layer).then(\n (detail) => {\n if (!cancelled) latest.current.applyDetail(detail, layer);\n },\n (cause: unknown) => {\n if (!cancelled)\n setState({\n status: \"error\",\n message: errorMessage(cause, \"failed to load prompt\"),\n });\n },\n );\n return () => {\n cancelled = true;\n };\n }, [layerKey, reloadToken]);\n\n useEffect(() => {\n if (!dirty) return;\n const guard = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n window.addEventListener(\"beforeunload\", guard);\n return () => window.removeEventListener(\"beforeunload\", guard);\n }, [dirty]);\n\n const reload = () => setReloadToken((token) => token + 1);\n\n function runTransition(transition: PendingTransition) {\n setPendingTransition(null);\n if (transition.type === \"back\") {\n onBack?.();\n return;\n }\n if (transition.type === \"reload\") {\n reload();\n return;\n }\n setSelectedOrigin(transition.origin);\n }\n\n function requestTransition(transition: PendingTransition) {\n if (dirty) {\n setPendingTransition(transition);\n return;\n }\n runTransition(transition);\n }\n\n async function persist(\n build: (\n detail: PromptSpecDetail,\n ) => Parameters<PromptPageAdapter[\"saveDetail\"]>[2],\n failure: string,\n ) {\n if (state.status !== \"ready\" || !selectedLayer) return;\n setSaving(true);\n setSaveError(\"\");\n setConflict(false);\n try {\n const next = await adapter.saveDetail(\n entry,\n selectedLayer,\n build(state.detail),\n );\n applyDetail(next, selectedLayer);\n onSaved?.(next, selectedLayer);\n } catch (cause) {\n const message = errorMessage(cause, failure);\n setSaveError(message);\n setConflict(isConflictError(message));\n } finally {\n setSaving(false);\n }\n }\n\n const save = () =>\n persist(\n (detail) => buildSavePayload(draft, detail, saveSource, path),\n \"save failed\",\n );\n const remove = () =>\n persist(\n (detail) => ({ source: \"default\", baseRaw: detail.raw }),\n \"remove failed\",\n );\n\n const render = adapter.render;\n const tabs = pageTabs({\n canPreview: render !== undefined,\n canDiff: entry.defaultRaw !== undefined,\n extraTabs,\n }).map((item) => {\n const icon = TAB_ICONS[item.id];\n return icon ? { ...item, icon } : item;\n });\n const activeTab = tabs.some((item) => item.id === tab)\n ? tab\n : PROMPT_PAGE_TAB.prompt;\n const currentRaw =\n state.status === \"ready\"\n ? draftDirty\n ? draftRaw(draft)\n : state.detail.raw\n : \"\";\n\n function selectLayer(layer: PromptCatalogLayer) {\n if (layer.origin === selectedOrigin) return;\n requestTransition({ type: \"layer\", origin: layer.origin });\n }\n\n function renderPanel() {\n if (state.status === \"loading\" || state.status === \"idle\") {\n return <p className=\"text-sm text-muted-foreground\">Loading prompt…</p>;\n }\n if (state.status === \"error\") {\n return (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 text-sm text-destructive\"\n >\n <span>{state.message}</span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={reload}>\n Retry\n </Button>\n </div>\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.prompt) {\n return (\n <PromptPageEditor\n detail={state.detail}\n draft={draft}\n onChange={setDraft}\n readOnly={readOnly}\n models={models}\n families={families}\n {...(entry.effective.mode\n ? { effectiveMode: entry.effective.mode }\n : {})}\n {...(entry.effective.model\n ? { effectiveModel: entry.effective.model }\n : {})}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.preview && render) {\n return (\n <PromptPagePreview\n entry={entry}\n render={(input) => render(entry, input)}\n draftRaw={draftDirty ? currentRaw : undefined}\n />\n );\n }\n if (activeTab === PROMPT_PAGE_TAB.diff && entry.defaultRaw !== undefined) {\n return (\n <CodeDiff\n original={entry.defaultRaw}\n modified={currentRaw}\n language=\"markdown\"\n />\n );\n }\n return extraTabs?.find((item) => item.id === activeTab)?.content ?? null;\n }\n\n return (\n <>\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n <PromptPageHeader\n entry={entry}\n selectedLayer={selectedLayer}\n {...(onBack\n ? { onBack: () => requestTransition({ type: \"back\" }) }\n : {})}\n />\n <PromptLayerStrip\n entry={entry}\n selectedOrigin={selectedOrigin}\n onSelect={selectLayer}\n />\n {readOnly && selectedLayer ? (\n <div\n role=\"note\"\n className=\"mx-density-4 mb-2 flex items-center gap-2 rounded-md border border-border bg-muted px-3 py-2 text-xs\"\n >\n <UiLock className=\"shrink-0 text-muted-foreground\" />\n <span>\n {layerLabel(selectedLayer.origin)} is read-only from here —{\" \"}\n <span className=\"font-mono\">{selectedLayer.path}</span>. Edit it\n directly or pick an editable layer.\n </span>\n </div>\n ) : null}\n <Tabs\n tabs={tabs}\n value={activeTab}\n onChange={setTab}\n className=\"px-density-4\"\n />\n <div className=\"min-h-0 flex-1 overflow-y-auto px-density-4 py-density-3\">\n {renderPanel()}\n </div>\n {state.status === \"ready\" && !readOnly ? (\n <PromptPageSaveBar\n sources={selectedLayer.saveSources}\n source={saveSource}\n onSourceChange={setSaveSource}\n path={path}\n onPathChange={setPath}\n dirty={dirty}\n saving={saving}\n canRemove={state.detail.source !== \"default\"}\n error={saveError}\n conflict={conflict}\n onSave={save}\n onRemove={remove}\n onReload={() => requestTransition({ type: \"reload\" })}\n />\n ) : null}\n </div>\n {pendingTransition ? (\n <Modal\n open\n onClose={() => setPendingTransition(null)}\n title=\"Discard unsaved prompt changes?\"\n size=\"sm\"\n expandable={false}\n footer={\n <div className=\"flex w-full justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => setPendingTransition(null)}\n >\n Keep editing\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n onClick={() => runTransition(pendingTransition)}\n >\n Discard changes\n </Button>\n </div>\n }\n >\n <p className=\"text-sm text-muted-foreground\">\n Your prompt content, save location, or file path changes will be\n lost.\n </p>\n </Modal>\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ function PromptPageHeader({ entry, selectedLayer, onBack, actions }) {
|
|
|
30
30
|
className: "flex flex-wrap items-center gap-2",
|
|
31
31
|
children: [
|
|
32
32
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
33
|
-
className: "text-lg font-semibold leading-tight",
|
|
33
|
+
className: "break-words text-lg font-semibold leading-tight",
|
|
34
34
|
children: entry.title
|
|
35
35
|
}),
|
|
36
36
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PromptSourceBadge.PromptSourceBadge, {
|
|
@@ -77,7 +77,7 @@ function PromptPageHeader({ entry, selectedLayer, onBack, actions }) {
|
|
|
77
77
|
children: "Runs as"
|
|
78
78
|
}),
|
|
79
79
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", {
|
|
80
|
-
className: entry.effective.error ? "text-destructive" : "font-mono",
|
|
80
|
+
className: entry.effective.error ? "min-w-0 break-all text-destructive" : "min-w-0 break-all font-mono",
|
|
81
81
|
children: [require_prompt_catalog_model.runtimeSummary(entry.effective), entry.effective.model ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
82
82
|
className: "ml-1 font-sans text-muted-foreground",
|
|
83
83
|
children: [
|
|
@@ -91,10 +91,13 @@ function PromptPageHeader({ entry, selectedLayer, onBack, actions }) {
|
|
|
91
91
|
className: "text-muted-foreground",
|
|
92
92
|
children: "Runs from"
|
|
93
93
|
}),
|
|
94
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
95
|
-
className: "
|
|
96
|
-
children: effective.
|
|
97
|
-
|
|
94
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
95
|
+
className: "min-w-0 break-all",
|
|
96
|
+
children: effective ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [require_prompt_catalog_model.layerLabel(effective.origin), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
97
|
+
className: "ml-1 font-mono text-muted-foreground",
|
|
98
|
+
children: effective.filePath ?? effective.path
|
|
99
|
+
})] }) : "built-in default"
|
|
100
|
+
})
|
|
98
101
|
]
|
|
99
102
|
})
|
|
100
103
|
]
|