@sqlrooms/ai 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +466 -0
  2. package/dist/AiSlice.d.ts +489 -307
  3. package/dist/AiSlice.d.ts.map +1 -1
  4. package/dist/AiSlice.js +267 -177
  5. package/dist/AiSlice.js.map +1 -1
  6. package/dist/analysis.d.ts +25 -19
  7. package/dist/analysis.d.ts.map +1 -1
  8. package/dist/analysis.js +86 -145
  9. package/dist/analysis.js.map +1 -1
  10. package/dist/components/AnalysisAnswer.d.ts +14 -0
  11. package/dist/components/AnalysisAnswer.d.ts.map +1 -0
  12. package/dist/components/AnalysisAnswer.js +14 -0
  13. package/dist/components/AnalysisAnswer.js.map +1 -0
  14. package/dist/{AnalysisResult.d.ts → components/AnalysisResult.d.ts} +2 -1
  15. package/dist/components/AnalysisResult.d.ts.map +1 -0
  16. package/dist/components/AnalysisResult.js +46 -0
  17. package/dist/components/AnalysisResult.js.map +1 -0
  18. package/dist/components/AnalysisResultsContainer.d.ts +5 -0
  19. package/dist/components/AnalysisResultsContainer.d.ts.map +1 -0
  20. package/dist/components/AnalysisResultsContainer.js +27 -0
  21. package/dist/components/AnalysisResultsContainer.js.map +1 -0
  22. package/dist/components/ErrorMessage.d.ts +4 -0
  23. package/dist/components/ErrorMessage.d.ts.map +1 -0
  24. package/dist/components/ErrorMessage.js +7 -0
  25. package/dist/components/ErrorMessage.js.map +1 -0
  26. package/dist/components/MessageContainer.d.ts +10 -0
  27. package/dist/components/MessageContainer.d.ts.map +1 -0
  28. package/dist/components/MessageContainer.js +17 -0
  29. package/dist/components/MessageContainer.js.map +1 -0
  30. package/dist/components/ModelSelector.d.ts +13 -0
  31. package/dist/components/ModelSelector.d.ts.map +1 -0
  32. package/dist/components/ModelSelector.js +29 -0
  33. package/dist/components/ModelSelector.js.map +1 -0
  34. package/dist/components/QueryControls.d.ts +8 -0
  35. package/dist/components/QueryControls.d.ts.map +1 -0
  36. package/dist/components/QueryControls.js +45 -0
  37. package/dist/components/QueryControls.js.map +1 -0
  38. package/dist/components/SessionControls.d.ts +17 -0
  39. package/dist/components/SessionControls.d.ts.map +1 -0
  40. package/dist/components/SessionControls.js +20 -0
  41. package/dist/components/SessionControls.js.map +1 -0
  42. package/dist/components/session/DeleteSessionButton.d.ts +19 -0
  43. package/dist/components/session/DeleteSessionButton.d.ts.map +1 -0
  44. package/dist/components/session/DeleteSessionButton.js +54 -0
  45. package/dist/components/session/DeleteSessionButton.js.map +1 -0
  46. package/dist/components/session/DeleteSessionDialog.d.ts +27 -0
  47. package/dist/components/session/DeleteSessionDialog.d.ts.map +1 -0
  48. package/dist/components/session/DeleteSessionDialog.js +19 -0
  49. package/dist/components/session/DeleteSessionDialog.js.map +1 -0
  50. package/dist/components/session/SessionActions.d.ts +18 -0
  51. package/dist/components/session/SessionActions.d.ts.map +1 -0
  52. package/dist/components/session/SessionActions.js +19 -0
  53. package/dist/components/session/SessionActions.js.map +1 -0
  54. package/dist/components/session/SessionDropdown.d.ts +18 -0
  55. package/dist/components/session/SessionDropdown.d.ts.map +1 -0
  56. package/dist/components/session/SessionDropdown.js +21 -0
  57. package/dist/components/session/SessionDropdown.js.map +1 -0
  58. package/dist/components/session/SessionTitle.d.ts +18 -0
  59. package/dist/components/session/SessionTitle.d.ts.map +1 -0
  60. package/dist/components/session/SessionTitle.js +22 -0
  61. package/dist/components/session/SessionTitle.js.map +1 -0
  62. package/dist/components/session/SessionType.d.ts +24 -0
  63. package/dist/components/session/SessionType.d.ts.map +1 -0
  64. package/dist/components/session/SessionType.js +2 -0
  65. package/dist/components/session/SessionType.js.map +1 -0
  66. package/dist/components/session/index.d.ts +7 -0
  67. package/dist/components/session/index.d.ts.map +1 -0
  68. package/dist/components/session/index.js +7 -0
  69. package/dist/components/session/index.js.map +1 -0
  70. package/dist/components/tools/QueryToolResult.d.ts +7 -0
  71. package/dist/components/tools/QueryToolResult.d.ts.map +1 -0
  72. package/dist/components/tools/QueryToolResult.js +9 -0
  73. package/dist/components/tools/QueryToolResult.js.map +1 -0
  74. package/dist/components/tools/ToolChart.d.ts +13 -0
  75. package/dist/components/tools/ToolChart.d.ts.map +1 -0
  76. package/dist/components/tools/ToolChart.js +14 -0
  77. package/dist/components/tools/ToolChart.js.map +1 -0
  78. package/dist/components/tools/ToolQuery.d.ts +7 -0
  79. package/dist/components/tools/ToolQuery.d.ts.map +1 -0
  80. package/dist/components/tools/ToolQuery.js +9 -0
  81. package/dist/components/tools/ToolQuery.js.map +1 -0
  82. package/dist/components/tools/ToolResult.d.ts +9 -0
  83. package/dist/components/tools/ToolResult.d.ts.map +1 -0
  84. package/dist/components/tools/ToolResult.js +32 -0
  85. package/dist/components/tools/ToolResult.js.map +1 -0
  86. package/dist/components/tools/ToolResultErrorBoundary.d.ts +19 -0
  87. package/dist/components/tools/ToolResultErrorBoundary.d.ts.map +1 -0
  88. package/dist/components/tools/ToolResultErrorBoundary.js +23 -0
  89. package/dist/components/tools/ToolResultErrorBoundary.js.map +1 -0
  90. package/dist/hooks/useScrollToBottom.d.ts +82 -0
  91. package/dist/hooks/useScrollToBottom.d.ts.map +1 -0
  92. package/dist/hooks/useScrollToBottom.js +140 -0
  93. package/dist/hooks/useScrollToBottom.js.map +1 -0
  94. package/dist/index.d.ts +20 -5
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +19 -5
  97. package/dist/index.js.map +1 -1
  98. package/dist/schemas.d.ts +592 -201
  99. package/dist/schemas.d.ts.map +1 -1
  100. package/dist/schemas.js +36 -11
  101. package/dist/schemas.js.map +1 -1
  102. package/package.json +11 -9
  103. package/dist/AnalysisResult.d.ts.map +0 -1
  104. package/dist/AnalysisResult.js +0 -49
  105. package/dist/AnalysisResult.js.map +0 -1
  106. package/dist/AnalysisResultsContainer.d.ts +0 -2
  107. package/dist/AnalysisResultsContainer.d.ts.map +0 -1
  108. package/dist/AnalysisResultsContainer.js +0 -15
  109. package/dist/AnalysisResultsContainer.js.map +0 -1
  110. package/dist/QueryControls.d.ts +0 -6
  111. package/dist/QueryControls.d.ts.map +0 -1
  112. package/dist/QueryControls.js +0 -28
  113. package/dist/QueryControls.js.map +0 -1
  114. package/dist/QueryResult.d.ts +0 -9
  115. package/dist/QueryResult.d.ts.map +0 -1
  116. package/dist/QueryResult.js +0 -46
  117. package/dist/QueryResult.js.map +0 -1
  118. package/dist/ToolCall.d.ts +0 -66
  119. package/dist/ToolCall.d.ts.map +0 -1
  120. package/dist/ToolCall.js +0 -59
  121. package/dist/ToolCall.js.map +0 -1
  122. package/dist/ToolResult.d.ts +0 -10
  123. package/dist/ToolResult.d.ts.map +0 -1
  124. package/dist/ToolResult.js +0 -26
  125. package/dist/ToolResult.js.map +0 -1
  126. package/dist/hooks/use-scroll-to-bottom.d.ts +0 -7
  127. package/dist/hooks/use-scroll-to-bottom.d.ts.map +0 -1
  128. package/dist/hooks/use-scroll-to-bottom.js +0 -51
  129. package/dist/hooks/use-scroll-to-bottom.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorMessage.d.ts","sourceRoot":"","sources":["../../src/components/ErrorMessage.tsx"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,2CAQzD"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Markdown from 'react-markdown';
3
+ import { MessageContainer } from './MessageContainer';
4
+ export function ErrorMessage(props) {
5
+ return (_jsx(MessageContainer, { isSuccess: false, type: "error", content: props, children: _jsx(Markdown, { className: "prose dark:prose-invert max-w-none text-sm", children: props.errorMessage }) }));
6
+ }
7
+ //# sourceMappingURL=ErrorMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorMessage.js","sourceRoot":"","sources":["../../src/components/ErrorMessage.tsx"],"names":[],"mappings":";AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAEpD,MAAM,UAAU,YAAY,CAAC,KAA6B;IACxD,OAAO,CACL,KAAC,gBAAgB,IAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAC,OAAO,EAAC,OAAO,EAAE,KAAK,YAC7D,KAAC,QAAQ,IAAC,SAAS,EAAC,4CAA4C,YAC7D,KAAK,CAAC,YAAY,GACV,GACM,CACpB,CAAC;AACJ,CAAC","sourcesContent":["import Markdown from 'react-markdown';\nimport {MessageContainer} from './MessageContainer';\n\nexport function ErrorMessage(props: {errorMessage: string}) {\n return (\n <MessageContainer isSuccess={false} type=\"error\" content={props}>\n <Markdown className=\"prose dark:prose-invert max-w-none text-sm\">\n {props.errorMessage}\n </Markdown>\n </MessageContainer>\n );\n}\n"]}
@@ -0,0 +1,10 @@
1
+ type MessageContainerProps = {
2
+ className?: string;
3
+ isSuccess: boolean;
4
+ type: string;
5
+ content: object;
6
+ children: React.ReactNode;
7
+ };
8
+ export declare const MessageContainer: React.FC<MessageContainerProps>;
9
+ export {};
10
+ //# sourceMappingURL=MessageContainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageContainer.d.ts","sourceRoot":"","sources":["../../src/components/MessageContainer.tsx"],"names":[],"mappings":"AAWA,KAAK,qBAAqB,GAAG;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAmE5D,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { JsonMonacoEditor } from '@sqlrooms/monaco-editor';
3
+ import { Badge, Button, cn, Popover, PopoverContent, PopoverTrigger, } from '@sqlrooms/ui';
4
+ import { CodeIcon, XCircleIcon } from 'lucide-react';
5
+ export const MessageContainer = ({ className, type,
6
+ // borderColor,
7
+ content, children, }) => {
8
+ return (_jsxs("div", { className: cn('group relative px-5 py-2 text-xs', className, type === 'error' && 'border-destructive rounded-md border py-4'), children: [type === 'error' && (_jsxs(Badge, { variant: "secondary", className: cn('absolute left-2 top-[-12px] flex items-center gap-1 border text-xs', 'border-destructive bg-background'), children: [_jsx(XCircleIcon, { className: "h-3 w-3 text-red-500" }), type] })), _jsx("div", { className: "absolute right-2 top-2 opacity-0 transition-opacity duration-200 group-hover:opacity-100", children: _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", children: _jsx(CodeIcon, { className: "h-4 w-4" }) }) }), _jsx(PopoverContent, { className: "max-h-[300px] w-[400px] overflow-auto p-4", side: "right", align: "start", children: _jsx(JsonMonacoEditor, { value: JSON.stringify(content, null, 2), readOnly: true, className: "h-[250px]", options: {
9
+ minimap: { enabled: false },
10
+ scrollBeyondLastLine: false,
11
+ automaticLayout: true,
12
+ folding: true,
13
+ lineNumbers: false,
14
+ wordWrap: 'on',
15
+ } }) })] }) }), _jsx("div", { className: "flex flex-col gap-5", children: children })] }));
16
+ };
17
+ //# sourceMappingURL=MessageContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageContainer.js","sourceRoot":"","sources":["../../src/components/MessageContainer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACL,KAAK,EACL,MAAM,EACN,EAAE,EACF,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AAWnD,MAAM,CAAC,MAAM,gBAAgB,GAAoC,CAAC,EAChE,SAAS,EACT,IAAI;AACJ,eAAe;AACf,OAAO,EACP,QAAQ,GACT,EAAE,EAAE;IACH,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,kCAAkC,EAClC,SAAS,EACT,IAAI,KAAK,OAAO,IAAI,2CAA2C,CAGhE,aAEA,IAAI,KAAK,OAAO,IAAI,CACnB,MAAC,KAAK,IACJ,OAAO,EAAC,WAAW,EACnB,SAAS,EAAE,EAAE,CACX,oEAAoE,EACpE,kCAAkC,CAEnC,aAKD,KAAC,WAAW,IAAC,SAAS,EAAC,sBAAsB,GAAG,EAE/C,IAAI,IACC,CACT,EAED,cAAK,SAAS,EAAC,0FAA0F,YACvG,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,KAAC,MAAM,IAAC,OAAO,EAAC,OAAO,EAAC,IAAI,EAAC,MAAM,EAAC,SAAS,EAAC,SAAS,YACrD,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,GAAG,GACzB,GACM,EACjB,KAAC,cAAc,IACb,SAAS,EAAC,2CAA2C,EACrD,IAAI,EAAC,OAAO,EACZ,KAAK,EAAC,OAAO,YAEb,KAAC,gBAAgB,IACf,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EACvC,QAAQ,EAAE,IAAI,EACd,SAAS,EAAC,WAAW,EACrB,OAAO,EAAE;oCACP,OAAO,EAAE,EAAC,OAAO,EAAE,KAAK,EAAC;oCACzB,oBAAoB,EAAE,KAAK;oCAC3B,eAAe,EAAE,IAAI;oCACrB,OAAO,EAAE,IAAI;oCACb,WAAW,EAAE,KAAK;oCAClB,QAAQ,EAAE,IAAI;iCACf,GACD,GACa,IACT,GACN,EAEN,cAAK,SAAS,EAAC,qBAAqB,YAAE,QAAQ,GAAO,IACjD,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {JsonMonacoEditor} from '@sqlrooms/monaco-editor';\nimport {\n Badge,\n Button,\n cn,\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@sqlrooms/ui';\nimport {CodeIcon, XCircleIcon} from 'lucide-react';\n\ntype MessageContainerProps = {\n className?: string;\n isSuccess: boolean;\n // borderColor: string;\n type: string;\n content: object;\n children: React.ReactNode;\n};\n\nexport const MessageContainer: React.FC<MessageContainerProps> = ({\n className,\n type,\n // borderColor,\n content,\n children,\n}) => {\n return (\n <div\n className={cn(\n 'group relative px-5 py-2 text-xs',\n className,\n type === 'error' && 'border-destructive rounded-md border py-4',\n // borderColor,\n // isSuccess ? borderColor : 'border-red-500',\n )}\n >\n {type === 'error' && (\n <Badge\n variant=\"secondary\"\n className={cn(\n 'absolute left-2 top-[-12px] flex items-center gap-1 border text-xs',\n 'border-destructive bg-background',\n // isSuccess ? borderColor : 'border-red-500',\n )}\n >\n {/* {isSuccess ? ( */}\n {/* <CheckCircle2Icon className=\"h-3 w-3 text-green-500\" /> */}\n {/* ) : ( */}\n <XCircleIcon className=\"h-3 w-3 text-red-500\" />\n {/* )} */}\n {type}\n </Badge>\n )}\n\n <div className=\"absolute right-2 top-2 opacity-0 transition-opacity duration-200 group-hover:opacity-100\">\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\">\n <CodeIcon className=\"h-4 w-4\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent\n className=\"max-h-[300px] w-[400px] overflow-auto p-4\"\n side=\"right\"\n align=\"start\"\n >\n <JsonMonacoEditor\n value={JSON.stringify(content, null, 2)}\n readOnly={true}\n className=\"h-[250px]\"\n options={{\n minimap: {enabled: false},\n scrollBeyondLastLine: false,\n automaticLayout: true,\n folding: true,\n lineNumbers: false,\n wordWrap: 'on',\n }}\n />\n </PopoverContent>\n </Popover>\n </div>\n\n <div className=\"flex flex-col gap-5\">{children}</div>\n </div>\n );\n};\n"]}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ interface Model {
3
+ provider: string;
4
+ label: string;
5
+ value: string;
6
+ }
7
+ interface ModelSelectorProps {
8
+ className?: string;
9
+ models: Model[];
10
+ }
11
+ export declare const ModelSelector: React.FC<ModelSelectorProps>;
12
+ export {};
13
+ //# sourceMappingURL=ModelSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../src/components/ModelSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,UAAU,KAAK;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA6DtD,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, } from '@sqlrooms/ui';
4
+ import { useStoreWithAi } from '../AiSlice';
5
+ import { capitalize } from '@sqlrooms/utils';
6
+ export const ModelSelector = ({ className, models, }) => {
7
+ const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
8
+ const setAiModel = useStoreWithAi((s) => s.ai.setAiModel);
9
+ const handleModelChange = (value) => {
10
+ const selectedModel = models.find((model) => model.value === value);
11
+ if (selectedModel) {
12
+ setAiModel(selectedModel.provider, value);
13
+ }
14
+ };
15
+ if (!currentSession)
16
+ return null;
17
+ const currentModel = currentSession.model;
18
+ const currentModelDetails = models.find((m) => m.value === currentModel);
19
+ // Group models by provider
20
+ const modelsByProvider = models.reduce((acc, model) => {
21
+ if (!acc[model.provider]) {
22
+ acc[model.provider] = [];
23
+ }
24
+ acc[model.provider].push(model);
25
+ return acc;
26
+ }, {});
27
+ return (_jsx("div", { className: className, children: _jsxs(Select, { value: currentModel, onValueChange: handleModelChange, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: "Select AI Model", children: currentModelDetails?.label ?? '' }) }), _jsx(SelectContent, { children: Object.entries(modelsByProvider).map(([provider, providerModels]) => (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [_jsx(SelectLabel, { className: "text-muted-foreground/50 text-center text-sm font-bold", children: capitalize(provider) }), providerModels.map((model) => (_jsx(SelectItem, { value: model.value, children: model.label }, model.value)))] }), _jsx(SelectSeparator, {})] }, provider))) })] }) }));
28
+ };
29
+ //# sourceMappingURL=ModelSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModelSelector.js","sourceRoot":"","sources":["../../src/components/ModelSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAY3C,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAC1D,SAAS,EACT,MAAM,GACP,EAAE,EAAE;IACH,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;IAE1D,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAE,EAAE;QAC1C,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACpE,IAAI,aAAa,EAAE,CAAC;YAClB,UAAU,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAEjC,MAAM,YAAY,GAAG,cAAc,CAAC,KAAK,CAAC;IAC1C,MAAM,mBAAmB,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC;IAEzE,2BAA2B;IAC3B,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;QAC3B,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAA6B,CAC9B,CAAC;IAEF,OAAO,CACL,cAAK,SAAS,EAAE,SAAS,YACvB,MAAC,MAAM,IAAC,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,aAC3D,KAAC,aAAa,IAAC,SAAS,EAAC,QAAQ,YAC/B,KAAC,WAAW,IAAC,WAAW,EAAC,iBAAiB,YACvC,mBAAmB,EAAE,KAAK,IAAI,EAAE,GACrB,GACA,EAChB,KAAC,aAAa,cACX,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CACnC,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAC9B,MAAC,KAAK,CAAC,QAAQ,eACb,MAAC,WAAW,eACV,KAAC,WAAW,IAAC,SAAS,EAAC,wDAAwD,YAC5E,UAAU,CAAC,QAAQ,CAAC,GACT,EACb,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC7B,KAAC,UAAU,IAAmB,KAAK,EAAE,KAAK,CAAC,KAAK,YAC7C,KAAK,CAAC,KAAK,IADG,KAAK,CAAC,KAAK,CAEf,CACd,CAAC,IACU,EACd,KAAC,eAAe,KAAG,KAXA,QAAQ,CAYZ,CAClB,CACF,GACa,IACT,GACL,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n} from '@sqlrooms/ui';\nimport {useStoreWithAi} from '../AiSlice';\nimport {capitalize} from '@sqlrooms/utils';\ninterface Model {\n provider: string;\n label: string;\n value: string;\n}\n\ninterface ModelSelectorProps {\n className?: string;\n models: Model[];\n}\n\nexport const ModelSelector: React.FC<ModelSelectorProps> = ({\n className,\n models,\n}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const setAiModel = useStoreWithAi((s) => s.ai.setAiModel);\n\n const handleModelChange = (value: string) => {\n const selectedModel = models.find((model) => model.value === value);\n if (selectedModel) {\n setAiModel(selectedModel.provider, value);\n }\n };\n\n if (!currentSession) return null;\n\n const currentModel = currentSession.model;\n const currentModelDetails = models.find((m) => m.value === currentModel);\n\n // Group models by provider\n const modelsByProvider = models.reduce(\n (acc, model) => {\n if (!acc[model.provider]) {\n acc[model.provider] = [];\n }\n acc[model.provider]!.push(model);\n return acc;\n },\n {} as Record<string, Model[]>,\n );\n\n return (\n <div className={className}>\n <Select value={currentModel} onValueChange={handleModelChange}>\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder=\"Select AI Model\">\n {currentModelDetails?.label ?? ''}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {Object.entries(modelsByProvider).map(\n ([provider, providerModels]) => (\n <React.Fragment key={provider}>\n <SelectGroup>\n <SelectLabel className=\"text-muted-foreground/50 text-center text-sm font-bold\">\n {capitalize(provider)}\n </SelectLabel>\n {providerModels.map((model) => (\n <SelectItem key={model.value} value={model.value}>\n {model.label}\n </SelectItem>\n ))}\n </SelectGroup>\n <SelectSeparator />\n </React.Fragment>\n ),\n )}\n </SelectContent>\n </Select>\n </div>\n );\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import { PropsWithChildren } from 'react';
2
+ type QueryControlsProps = PropsWithChildren<{
3
+ className?: string;
4
+ placeholder?: string;
5
+ }>;
6
+ export declare const QueryControls: React.FC<QueryControlsProps>;
7
+ export {};
8
+ //# sourceMappingURL=QueryControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/components/QueryControls.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,iBAAiB,EAAiC,MAAM,OAAO,CAAC;AAGxE,KAAK,kBAAkB,GAAG,iBAAiB,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAEH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAyGtD,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, cn, Spinner, Textarea } from '@sqlrooms/ui';
3
+ import { ArrowUpIcon, OctagonXIcon } from 'lucide-react';
4
+ import { useCallback, useRef, useEffect } from 'react';
5
+ import { useStoreWithAi } from '../AiSlice';
6
+ export const QueryControls = ({ className, placeholder = 'Type here what would you like to learn about the data?', children, }) => {
7
+ const textareaRef = useRef(null);
8
+ const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);
9
+ const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);
10
+ const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);
11
+ const analysisPrompt = useStoreWithAi((s) => s.ai.analysisPrompt);
12
+ const isDataAvailable = useStoreWithAi((s) => s.project.isDataAvailable);
13
+ const setAnalysisPrompt = useStoreWithAi((s) => s.ai.setAnalysisPrompt);
14
+ const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
15
+ const model = currentSession?.model;
16
+ useEffect(() => {
17
+ if (!isDataAvailable)
18
+ return;
19
+ // Focus the textarea when the component mounts
20
+ // Using a small timeout ensures the data is loaded and
21
+ // add timeout to prevent aria hidden warning caused by the
22
+ // loading progress dialog being still open
23
+ const timer = setTimeout(() => {
24
+ if (textareaRef.current) {
25
+ textareaRef.current.focus();
26
+ }
27
+ }, 500);
28
+ return () => clearTimeout(timer);
29
+ }, [isDataAvailable]);
30
+ const handleKeyDown = useCallback((e) => {
31
+ if (e.key === 'Enter' &&
32
+ !e.shiftKey &&
33
+ !e.ctrlKey &&
34
+ !e.altKey &&
35
+ !e.metaKey) {
36
+ e.preventDefault();
37
+ if (!isRunningAnalysis && model && analysisPrompt.trim().length) {
38
+ runAnalysis();
39
+ }
40
+ }
41
+ }, [isRunningAnalysis, model, analysisPrompt, runAnalysis]);
42
+ const canStart = Boolean(!isRunningAnalysis && model && analysisPrompt.trim().length);
43
+ return (_jsx("div", { className: cn('flex w-full flex-col items-center justify-center gap-4', className), children: _jsx("div", { className: "relative w-full overflow-hidden p-[1px]", children: _jsxs("div", { className: "flex flex-col", children: [_jsx(Textarea, { ref: textareaRef, disabled: isRunningAnalysis, className: "bg-muted/50 h-[100px] resize-none", value: analysisPrompt, onChange: (e) => setAnalysisPrompt(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, autoFocus: true }), _jsxs("div", { className: "bg-muted/30 flex w-full items-center justify-between gap-2 p-2", children: [_jsx("div", { children: children }), _jsx("div", { className: "flex-1" }), _jsxs("div", { children: [isRunningAnalysis && (_jsxs(Button, { variant: "outline", className: "rounded-full", onClick: cancelAnalysis, children: [_jsx(OctagonXIcon, { className: "h-4 w-4" }), "Stop"] })), _jsx(Button, { className: "h-10 w-10 rounded-full", variant: "default", size: "icon", onClick: runAnalysis, disabled: !canStart, children: isRunningAnalysis ? (_jsx("div", { className: "flex items-center gap-2", children: _jsx(Spinner, { className: "h-4 w-4" }) })) : (_jsx(ArrowUpIcon, {})) })] })] })] }) }) }));
44
+ };
45
+ //# sourceMappingURL=QueryControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryControls.js","sourceRoot":"","sources":["../../src/components/QueryControls.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Button, cn, Spinner, Textarea} from '@sqlrooms/ui';\nimport {ArrowUpIcon, OctagonXIcon} from 'lucide-react';\nimport {PropsWithChildren, useCallback, useRef, useEffect} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\n\ntype QueryControlsProps = PropsWithChildren<{\n className?: string;\n placeholder?: string;\n}>;\n\nexport const QueryControls: React.FC<QueryControlsProps> = ({\n className,\n placeholder = 'Type here what would you like to learn about the data?',\n children,\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);\n const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);\n const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);\n const analysisPrompt = useStoreWithAi((s) => s.ai.analysisPrompt);\n const isDataAvailable = useStoreWithAi((s) => s.project.isDataAvailable);\n const setAnalysisPrompt = useStoreWithAi((s) => s.ai.setAnalysisPrompt);\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const model = currentSession?.model;\n\n useEffect(() => {\n if (!isDataAvailable) return;\n // Focus the textarea when the component mounts\n // Using a small timeout ensures the data is loaded and\n // add timeout to prevent aria hidden warning caused by the\n // loading progress dialog being still open\n const timer = setTimeout(() => {\n if (textareaRef.current) {\n textareaRef.current.focus();\n }\n }, 500);\n\n return () => clearTimeout(timer);\n }, [isDataAvailable]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.metaKey\n ) {\n e.preventDefault();\n if (!isRunningAnalysis && model && analysisPrompt.trim().length) {\n runAnalysis();\n }\n }\n },\n [isRunningAnalysis, model, analysisPrompt, runAnalysis],\n );\n\n const canStart = Boolean(\n !isRunningAnalysis && model && analysisPrompt.trim().length,\n );\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-4',\n className,\n )}\n >\n <div className=\"relative w-full overflow-hidden p-[1px]\">\n <div className=\"flex flex-col\">\n <Textarea\n ref={textareaRef}\n disabled={isRunningAnalysis}\n className=\"bg-muted/50 h-[100px] resize-none\"\n value={analysisPrompt}\n onChange={(e) => setAnalysisPrompt(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n autoFocus\n />\n <div className=\"bg-muted/30 flex w-full items-center justify-between gap-2 p-2\">\n <div>{children}</div>\n <div className=\"flex-1\" />\n <div>\n {isRunningAnalysis && (\n <Button\n variant=\"outline\"\n className=\"rounded-full\"\n onClick={cancelAnalysis}\n >\n <OctagonXIcon className=\"h-4 w-4\" />\n Stop\n </Button>\n )}\n <Button\n className=\"h-10 w-10 rounded-full\"\n variant=\"default\"\n size=\"icon\"\n onClick={runAnalysis}\n disabled={!canStart}\n >\n {isRunningAnalysis ? (\n <div className=\"flex items-center gap-2\">\n <Spinner className=\"h-4 w-4\" />\n </div>\n ) : (\n <ArrowUpIcon />\n )}\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"]}
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ /**
3
+ * Main component for managing AI sessions.
4
+ * Combines session dropdown, title editing, action buttons, and delete confirmation.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * <SessionControls className="p-4 border-b">
9
+ * <Button>Custom Button</Button>
10
+ * </SessionControls>
11
+ * ```
12
+ */
13
+ export declare const SessionControls: React.FC<{
14
+ className?: string;
15
+ children?: React.ReactNode;
16
+ }>;
17
+ //# sourceMappingURL=SessionControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionControls.d.ts","sourceRoot":"","sources":["../../src/components/SessionControls.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CA2BA,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { cn } from '@sqlrooms/ui';
3
+ import { useStoreWithAi } from '../AiSlice';
4
+ import { SessionActions, SessionDropdown, SessionTitle } from './session';
5
+ /**
6
+ * Main component for managing AI sessions.
7
+ * Combines session dropdown, title editing, action buttons, and delete confirmation.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <SessionControls className="p-4 border-b">
12
+ * <Button>Custom Button</Button>
13
+ * </SessionControls>
14
+ * ```
15
+ */
16
+ export const SessionControls = ({ className, children }) => {
17
+ const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
18
+ return (_jsx(_Fragment, { children: _jsxs("div", { className: cn('flex flex-wrap items-center justify-between', className), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(SessionDropdown, {}), _jsx(SessionTitle, {}), currentSession && (_jsx("div", { className: "text-muted-foreground text-xs", children: currentSession.model }))] }), children, _jsx(SessionActions, {})] }) }));
19
+ };
20
+ //# sourceMappingURL=SessionControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionControls.js","sourceRoot":"","sources":["../../src/components/SessionControls.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAEhC,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAC,cAAc,EAAE,eAAe,EAAE,YAAY,EAAC,MAAM,WAAW,CAAC;AAExE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAGvB,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAC,EAAE,EAAE;IAC7B,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACvE,OAAO,CACL,4BAEE,eACE,SAAS,EAAE,EAAE,CAAC,6CAA6C,EAAE,SAAS,CAAC,aAGvE,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,eAAe,KAAG,EACnB,KAAC,YAAY,KAAG,EACf,cAAc,IAAI,CACjB,cAAK,SAAS,EAAC,+BAA+B,YAC3C,cAAc,CAAC,KAAK,GACjB,CACP,IACG,EAGL,QAAQ,EAGT,KAAC,cAAc,KAAG,IACd,GACL,CACJ,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {cn} from '@sqlrooms/ui';\nimport React from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {SessionActions, SessionDropdown, SessionTitle} from './session';\n\n/**\n * Main component for managing AI sessions.\n * Combines session dropdown, title editing, action buttons, and delete confirmation.\n *\n * @example\n * ```tsx\n * <SessionControls className=\"p-4 border-b\">\n * <Button>Custom Button</Button>\n * </SessionControls>\n * ```\n */\nexport const SessionControls: React.FC<{\n className?: string;\n children?: React.ReactNode;\n}> = ({className, children}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n return (\n <>\n {/* Header with session controls */}\n <div\n className={cn('flex flex-wrap items-center justify-between', className)}\n >\n {/* Left side - History Button and Editable Session Title */}\n <div className=\"flex items-center gap-3\">\n <SessionDropdown />\n <SessionTitle />\n {currentSession && (\n <div className=\"text-muted-foreground text-xs\">\n {currentSession.model}\n </div>\n )}\n </div>\n\n {/* Render children if provided */}\n {children}\n\n {/* Right side buttons */}\n <SessionActions />\n </div>\n </>\n );\n};\n"]}
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ /**
3
+ * Props for the DeleteSessionButton component
4
+ */
5
+ export interface DeleteSessionButtonProps {
6
+ /** Optional CSS class names to apply to the button */
7
+ className?: string;
8
+ }
9
+ /**
10
+ * A button component that handles session deletion with confirmation dialog.
11
+ * Only appears when there is more than one session available.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <DeleteSessionButton className="my-custom-class" />
16
+ * ```
17
+ */
18
+ export declare const DeleteSessionButton: React.FC<DeleteSessionButtonProps>;
19
+ //# sourceMappingURL=DeleteSessionButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteSessionButton.d.ts","sourceRoot":"","sources":["../../../src/components/session/DeleteSessionButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAiElE,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, cn } from '@sqlrooms/ui';
3
+ import { Trash2 } from 'lucide-react';
4
+ import { useState } from 'react';
5
+ import { useStoreWithAi } from '../../AiSlice';
6
+ import { DeleteSessionDialog } from './DeleteSessionDialog';
7
+ /**
8
+ * A button component that handles session deletion with confirmation dialog.
9
+ * Only appears when there is more than one session available.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <DeleteSessionButton className="my-custom-class" />
14
+ * ```
15
+ */
16
+ export const DeleteSessionButton = ({ className, }) => {
17
+ const sessions = useStoreWithAi((s) => s.config.ai.sessions);
18
+ const currentSessionId = useStoreWithAi((s) => s.config.ai.currentSessionId);
19
+ const deleteSession = useStoreWithAi((s) => s.ai.deleteSession);
20
+ const [sessionToDeleteId, setSessionToDeleteId] = useState(null);
21
+ const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
22
+ /**
23
+ * Opens the delete confirmation dialog for the current session
24
+ */
25
+ const handleOpenDeleteDialog = () => {
26
+ if (currentSessionId) {
27
+ setSessionToDeleteId(currentSessionId);
28
+ setIsDeleteDialogOpen(true);
29
+ }
30
+ };
31
+ /**
32
+ * Deletes the session after confirmation
33
+ */
34
+ const handleDeleteSession = () => {
35
+ if (sessionToDeleteId) {
36
+ deleteSession(sessionToDeleteId);
37
+ setIsDeleteDialogOpen(false);
38
+ setSessionToDeleteId(null);
39
+ }
40
+ };
41
+ /**
42
+ * Closes the delete confirmation dialog without deleting
43
+ */
44
+ const handleCloseDeleteDialog = () => {
45
+ setIsDeleteDialogOpen(false);
46
+ setSessionToDeleteId(null);
47
+ };
48
+ // Only show the delete button if there's more than one session
49
+ if (sessions.length <= 1 || !currentSessionId) {
50
+ return null;
51
+ }
52
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", size: "sm", className: cn('text-destructive', className), onClick: handleOpenDeleteDialog, children: _jsx(Trash2, { className: "h-4 w-4" }) }), _jsx(DeleteSessionDialog, { isOpen: isDeleteDialogOpen, onClose: handleCloseDeleteDialog, onDelete: handleDeleteSession })] }));
53
+ };
54
+ //# sourceMappingURL=DeleteSessionButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteSessionButton.js","sourceRoot":"","sources":["../../../src/components/session/DeleteSessionButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,EAAE,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AACpC,OAAc,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,cAAc,EAAC,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAU1D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuC,CAAC,EACtE,SAAS,GACV,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAC7E,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAEhE,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CACxD,IAAI,CACL,CAAC;IACF,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpE;;OAEG;IACH,MAAM,sBAAsB,GAAG,GAAG,EAAE;QAClC,IAAI,gBAAgB,EAAE,CAAC;YACrB,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;YACvC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF;;OAEG;IACH,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,iBAAiB,EAAE,CAAC;YACtB,aAAa,CAAC,iBAAiB,CAAC,CAAC;YACjC,qBAAqB,CAAC,KAAK,CAAC,CAAC;YAC7B,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IAEF;;OAEG;IACH,MAAM,uBAAuB,GAAG,GAAG,EAAE;QACnC,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAC7B,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC;IAEF,+DAA+D;IAC/D,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,8BACE,KAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,SAAS,EAAE,EAAE,CAAC,kBAAkB,EAAE,SAAS,CAAC,EAC5C,OAAO,EAAE,sBAAsB,YAE/B,KAAC,MAAM,IAAC,SAAS,EAAC,SAAS,GAAG,GACvB,EAGT,KAAC,mBAAmB,IAClB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,mBAAmB,GAC7B,IACD,CACJ,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {Button, cn} from '@sqlrooms/ui';\nimport {Trash2} from 'lucide-react';\nimport React, {useState} from 'react';\nimport {useStoreWithAi} from '../../AiSlice';\nimport {DeleteSessionDialog} from './DeleteSessionDialog';\n\n/**\n * Props for the DeleteSessionButton component\n */\nexport interface DeleteSessionButtonProps {\n /** Optional CSS class names to apply to the button */\n className?: string;\n}\n\n/**\n * A button component that handles session deletion with confirmation dialog.\n * Only appears when there is more than one session available.\n *\n * @example\n * ```tsx\n * <DeleteSessionButton className=\"my-custom-class\" />\n * ```\n */\nexport const DeleteSessionButton: React.FC<DeleteSessionButtonProps> = ({\n className,\n}) => {\n const sessions = useStoreWithAi((s) => s.config.ai.sessions);\n const currentSessionId = useStoreWithAi((s) => s.config.ai.currentSessionId);\n const deleteSession = useStoreWithAi((s) => s.ai.deleteSession);\n\n const [sessionToDeleteId, setSessionToDeleteId] = useState<string | null>(\n null,\n );\n const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);\n\n /**\n * Opens the delete confirmation dialog for the current session\n */\n const handleOpenDeleteDialog = () => {\n if (currentSessionId) {\n setSessionToDeleteId(currentSessionId);\n setIsDeleteDialogOpen(true);\n }\n };\n\n /**\n * Deletes the session after confirmation\n */\n const handleDeleteSession = () => {\n if (sessionToDeleteId) {\n deleteSession(sessionToDeleteId);\n setIsDeleteDialogOpen(false);\n setSessionToDeleteId(null);\n }\n };\n\n /**\n * Closes the delete confirmation dialog without deleting\n */\n const handleCloseDeleteDialog = () => {\n setIsDeleteDialogOpen(false);\n setSessionToDeleteId(null);\n };\n\n // Only show the delete button if there's more than one session\n if (sessions.length <= 1 || !currentSessionId) {\n return null;\n }\n\n return (\n <>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className={cn('text-destructive', className)}\n onClick={handleOpenDeleteDialog}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n\n {/* Delete Confirmation Dialog */}\n <DeleteSessionDialog\n isOpen={isDeleteDialogOpen}\n onClose={handleCloseDeleteDialog}\n onDelete={handleDeleteSession}\n />\n </>\n );\n};\n"]}
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ /**
3
+ * Props for the DeleteSessionDialog component
4
+ */
5
+ export interface DeleteSessionDialogProps {
6
+ /** Whether the dialog is currently open */
7
+ isOpen: boolean;
8
+ /** Callback function to close the dialog */
9
+ onClose: () => void;
10
+ /** Callback function to confirm deletion */
11
+ onDelete: () => void;
12
+ }
13
+ /**
14
+ * Dialog component for confirming session deletion.
15
+ * Displays a warning message and provides cancel/delete buttons.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <DeleteSessionDialog
20
+ * isOpen={true}
21
+ * onClose={() => console.log("Dialog closed")}
22
+ * onDelete={() => console.log("Session deleted")}
23
+ * />
24
+ * ```
25
+ */
26
+ export declare const DeleteSessionDialog: React.FC<DeleteSessionDialogProps>;
27
+ //# sourceMappingURL=DeleteSessionDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteSessionDialog.d.ts","sourceRoot":"","sources":["../../../src/components/session/DeleteSessionDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAC;IAEhB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA0BlE,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@sqlrooms/ui';
3
+ /**
4
+ * Dialog component for confirming session deletion.
5
+ * Displays a warning message and provides cancel/delete buttons.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <DeleteSessionDialog
10
+ * isOpen={true}
11
+ * onClose={() => console.log("Dialog closed")}
12
+ * onDelete={() => console.log("Session deleted")}
13
+ * />
14
+ * ```
15
+ */
16
+ export const DeleteSessionDialog = ({ isOpen, onClose, onDelete, }) => {
17
+ return (_jsx(Dialog, { open: isOpen, onOpenChange: onClose, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Delete Session" }), _jsx(DialogDescription, { children: "Are you sure you want to delete this session? This action cannot be undone." })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: onClose, children: "Cancel" }), _jsx(Button, { variant: "destructive", onClick: onDelete, children: "Delete" })] })] }) }));
18
+ };
19
+ //# sourceMappingURL=DeleteSessionDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteSessionDialog.js","sourceRoot":"","sources":["../../../src/components/session/DeleteSessionDialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC;AAiBtB;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuC,CAAC,EACtE,MAAM,EACN,OAAO,EACP,QAAQ,GACT,EAAE,EAAE;IACH,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,YACzC,MAAC,aAAa,eACZ,MAAC,YAAY,eACX,KAAC,WAAW,iCAA6B,EACzC,KAAC,iBAAiB,8FAGE,IACP,EACf,MAAC,YAAY,eACX,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,OAAO,uBAEjC,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,aAAa,EAAC,OAAO,EAAE,QAAQ,uBAEtC,IACI,IACD,GACT,CACV,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@sqlrooms/ui';\nimport React from 'react';\n\n/**\n * Props for the DeleteSessionDialog component\n */\nexport interface DeleteSessionDialogProps {\n /** Whether the dialog is currently open */\n isOpen: boolean;\n\n /** Callback function to close the dialog */\n onClose: () => void;\n\n /** Callback function to confirm deletion */\n onDelete: () => void;\n}\n\n/**\n * Dialog component for confirming session deletion.\n * Displays a warning message and provides cancel/delete buttons.\n *\n * @example\n * ```tsx\n * <DeleteSessionDialog\n * isOpen={true}\n * onClose={() => console.log(\"Dialog closed\")}\n * onDelete={() => console.log(\"Session deleted\")}\n * />\n * ```\n */\nexport const DeleteSessionDialog: React.FC<DeleteSessionDialogProps> = ({\n isOpen,\n onClose,\n onDelete,\n}) => {\n return (\n <Dialog open={isOpen} onOpenChange={onClose}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Delete Session</DialogTitle>\n <DialogDescription>\n Are you sure you want to delete this session? This action cannot be\n undone.\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={onDelete}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ /**
3
+ * Props for the SessionActions component
4
+ */
5
+ export interface SessionActionsProps {
6
+ className?: string;
7
+ }
8
+ /**
9
+ * Component that displays action buttons for session management.
10
+ * Shows a delete button (via DeleteSessionButton) and a create new session button.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <SessionActions className="my-custom-class" />
15
+ * ```
16
+ */
17
+ export declare const SessionActions: React.FC<SessionActionsProps>;
18
+ //# sourceMappingURL=SessionActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionActions.d.ts","sourceRoot":"","sources":["../../../src/components/session/SessionActions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAoBxD,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, cn } from '@sqlrooms/ui';
3
+ import { Plus as PlusIcon } from 'lucide-react';
4
+ import { useStoreWithAi } from '../../AiSlice';
5
+ import { DeleteSessionButton } from './DeleteSessionButton';
6
+ /**
7
+ * Component that displays action buttons for session management.
8
+ * Shows a delete button (via DeleteSessionButton) and a create new session button.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <SessionActions className="my-custom-class" />
13
+ * ```
14
+ */
15
+ export const SessionActions = ({ className }) => {
16
+ const createSession = useStoreWithAi((s) => s.ai.createSession);
17
+ return (_jsxs("div", { className: cn('flex items-center gap-2', className), children: [_jsx(DeleteSessionButton, {}), _jsxs(Button, { variant: "outline", size: "sm", className: "gap-1", onClick: () => createSession(), children: [_jsx(PlusIcon, { className: "h-4 w-4" }), "New Session"] })] }));
18
+ };
19
+ //# sourceMappingURL=SessionActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionActions.js","sourceRoot":"","sources":["../../../src/components/session/SessionActions.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,EAAE,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,IAAI,IAAI,QAAQ,EAAC,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAC,cAAc,EAAC,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAS1D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkC,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE;IAC3E,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAEhE,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,yBAAyB,EAAE,SAAS,CAAC,aAEtD,KAAC,mBAAmB,KAAG,EAGvB,MAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,SAAS,EAAC,OAAO,EACjB,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,aAE9B,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,GAAG,mBAEzB,IACL,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {Button, cn} from '@sqlrooms/ui';\nimport {Plus as PlusIcon} from 'lucide-react';\nimport React from 'react';\nimport {useStoreWithAi} from '../../AiSlice';\nimport {DeleteSessionButton} from './DeleteSessionButton';\n\n/**\n * Props for the SessionActions component\n */\nexport interface SessionActionsProps {\n className?: string;\n}\n\n/**\n * Component that displays action buttons for session management.\n * Shows a delete button (via DeleteSessionButton) and a create new session button.\n *\n * @example\n * ```tsx\n * <SessionActions className=\"my-custom-class\" />\n * ```\n */\nexport const SessionActions: React.FC<SessionActionsProps> = ({className}) => {\n const createSession = useStoreWithAi((s) => s.ai.createSession);\n\n return (\n <div className={cn('flex items-center gap-2', className)}>\n {/* Delete Current Session Button */}\n <DeleteSessionButton />\n\n {/* Create New Session Button */}\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-1\"\n onClick={() => createSession()}\n >\n <PlusIcon className=\"h-4 w-4\" />\n New Session\n </Button>\n </div>\n );\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ /**
3
+ * Props for the SessionDropdown component
4
+ */
5
+ export interface SessionDropdownProps {
6
+ className?: string;
7
+ }
8
+ /**
9
+ * Dropdown component for managing AI sessions.
10
+ * Allows users to switch between existing sessions or create a new one.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <SessionDropdown className="my-custom-class" />
15
+ * ```
16
+ */
17
+ export declare const SessionDropdown: React.FC<SessionDropdownProps>;
18
+ //# sourceMappingURL=SessionDropdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionDropdown.d.ts","sourceRoot":"","sources":["../../../src/components/session/SessionDropdown.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwC1D,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, cn, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@sqlrooms/ui';
3
+ import { Check, ChevronDown, History, Plus as PlusIcon } from 'lucide-react';
4
+ import { useStoreWithAi } from '../../AiSlice';
5
+ /**
6
+ * Dropdown component for managing AI sessions.
7
+ * Allows users to switch between existing sessions or create a new one.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <SessionDropdown className="my-custom-class" />
12
+ * ```
13
+ */
14
+ export const SessionDropdown = ({ className, }) => {
15
+ const sessions = useStoreWithAi((s) => s.config.ai.sessions);
16
+ const currentSessionId = useStoreWithAi((s) => s.config.ai.currentSessionId);
17
+ const switchSession = useStoreWithAi((s) => s.ai.switchSession);
18
+ const createSession = useStoreWithAi((s) => s.ai.createSession);
19
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { className: cn('gap-1', className), variant: "outline", size: "sm", children: [_jsx(History, { className: "h-4 w-4" }), _jsx(ChevronDown, { className: "ml-1 h-4 w-4" })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "w-70", children: [_jsxs(DropdownMenuItem, { onClick: () => createSession(), className: "flex items-center py-2", children: [_jsx(PlusIcon, { className: "mr-2 h-4 w-4" }), "New Session"] }), _jsx("div", { className: "bg-border my-1 h-px" }), sessions.map((session) => (_jsxs(DropdownMenuItem, { className: "flex justify-between py-2", onClick: () => switchSession(session.id), children: [_jsx("span", { className: "truncate", children: session.name }), session.id === currentSessionId && (_jsx(Check, { className: "ml-2 h-4 w-4" }))] }, session.id)))] })] }));
20
+ };
21
+ //# sourceMappingURL=SessionDropdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionDropdown.js","sourceRoot":"","sources":["../../../src/components/session/SessionDropdown.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,MAAM,EACN,EAAE,EACF,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAC,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAC,cAAc,EAAC,MAAM,eAAe,CAAC;AAS7C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAmC,CAAC,EAC9D,SAAS,GACV,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAC7E,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAEhE,OAAO,CACL,MAAC,YAAY,eACX,KAAC,mBAAmB,IAAC,OAAO,kBAC1B,MAAC,MAAM,IAAC,SAAS,EAAE,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,aACpE,KAAC,OAAO,IAAC,SAAS,EAAC,SAAS,GAAG,EAC/B,KAAC,WAAW,IAAC,SAAS,EAAC,cAAc,GAAG,IACjC,GACW,EACtB,MAAC,mBAAmB,IAAC,KAAK,EAAC,OAAO,EAAC,SAAS,EAAC,MAAM,aACjD,MAAC,gBAAgB,IACf,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAC9B,SAAS,EAAC,wBAAwB,aAElC,KAAC,QAAQ,IAAC,SAAS,EAAC,cAAc,GAAG,mBAEpB,EACnB,cAAK,SAAS,EAAC,qBAAqB,GAAG,EACtC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CACzB,MAAC,gBAAgB,IAEf,SAAS,EAAC,2BAA2B,EACrC,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,aAExC,eAAM,SAAS,EAAC,UAAU,YAAE,OAAO,CAAC,IAAI,GAAQ,EAC/C,OAAO,CAAC,EAAE,KAAK,gBAAgB,IAAI,CAClC,KAAC,KAAK,IAAC,SAAS,EAAC,cAAc,GAAG,CACnC,KAPI,OAAO,CAAC,EAAE,CAQE,CACpB,CAAC,IACkB,IACT,CAChB,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n Button,\n cn,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@sqlrooms/ui';\nimport {Check, ChevronDown, History, Plus as PlusIcon} from 'lucide-react';\nimport React from 'react';\nimport {useStoreWithAi} from '../../AiSlice';\n\n/**\n * Props for the SessionDropdown component\n */\nexport interface SessionDropdownProps {\n className?: string;\n}\n\n/**\n * Dropdown component for managing AI sessions.\n * Allows users to switch between existing sessions or create a new one.\n *\n * @example\n * ```tsx\n * <SessionDropdown className=\"my-custom-class\" />\n * ```\n */\nexport const SessionDropdown: React.FC<SessionDropdownProps> = ({\n className,\n}) => {\n const sessions = useStoreWithAi((s) => s.config.ai.sessions);\n const currentSessionId = useStoreWithAi((s) => s.config.ai.currentSessionId);\n const switchSession = useStoreWithAi((s) => s.ai.switchSession);\n const createSession = useStoreWithAi((s) => s.ai.createSession);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button className={cn('gap-1', className)} variant=\"outline\" size=\"sm\">\n <History className=\"h-4 w-4\" />\n <ChevronDown className=\"ml-1 h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-70\">\n <DropdownMenuItem\n onClick={() => createSession()}\n className=\"flex items-center py-2\"\n >\n <PlusIcon className=\"mr-2 h-4 w-4\" />\n New Session\n </DropdownMenuItem>\n <div className=\"bg-border my-1 h-px\" />\n {sessions.map((session) => (\n <DropdownMenuItem\n key={session.id}\n className=\"flex justify-between py-2\"\n onClick={() => switchSession(session.id)}\n >\n <span className=\"truncate\">{session.name}</span>\n {session.id === currentSessionId && (\n <Check className=\"ml-2 h-4 w-4\" />\n )}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ /**
3
+ * Props for the SessionTitle component
4
+ */
5
+ export interface SessionTitleProps {
6
+ className?: string;
7
+ }
8
+ /**
9
+ * Component that displays the current session name as an editable text field.
10
+ * Shows the model name if available and a placeholder if no session is selected.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <SessionTitle className="my-custom-class" />
15
+ * ```
16
+ */
17
+ export declare const SessionTitle: React.FC<SessionTitleProps>;
18
+ //# sourceMappingURL=SessionTitle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionTitle.d.ts","sourceRoot":"","sources":["../../../src/components/session/SessionTitle.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyBpD,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn, EditableText } from '@sqlrooms/ui';
3
+ import { useStoreWithAi } from '../../AiSlice';
4
+ /**
5
+ * Component that displays the current session name as an editable text field.
6
+ * Shows the model name if available and a placeholder if no session is selected.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * <SessionTitle className="my-custom-class" />
11
+ * ```
12
+ */
13
+ export const SessionTitle = ({ className }) => {
14
+ const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
15
+ const renameSession = useStoreWithAi((s) => s.ai.renameSession);
16
+ return (_jsx("div", { className: cn('flex items-center gap-2', className), children: currentSession ? (_jsx(EditableText, { value: currentSession.name, onChange: (newName) => {
17
+ if (currentSession && newName.trim()) {
18
+ renameSession(currentSession.id, newName);
19
+ }
20
+ }, placeholder: "Session name", className: "text-sm font-medium", maxWidth: 300 })) : (_jsx("span", { className: "text-muted-foreground text-sm font-medium", children: "No session selected" })) }));
21
+ };
22
+ //# sourceMappingURL=SessionTitle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionTitle.js","sourceRoot":"","sources":["../../../src/components/session/SessionTitle.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,EAAE,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAC,cAAc,EAAC,MAAM,eAAe,CAAC;AAS7C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE;IACvE,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAEhE,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,yBAAyB,EAAE,SAAS,CAAC,YACrD,cAAc,CAAC,CAAC,CAAC,CAChB,KAAC,YAAY,IACX,KAAK,EAAE,cAAc,CAAC,IAAI,EAC1B,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE;gBACpB,IAAI,cAAc,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;oBACrC,aAAa,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,EACD,WAAW,EAAC,cAAc,EAC1B,SAAS,EAAC,qBAAqB,EAC/B,QAAQ,EAAE,GAAG,GACb,CACH,CAAC,CAAC,CAAC,CACF,eAAM,SAAS,EAAC,2CAA2C,oCAEpD,CACR,GACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {cn, EditableText} from '@sqlrooms/ui';\nimport React from 'react';\nimport {useStoreWithAi} from '../../AiSlice';\n\n/**\n * Props for the SessionTitle component\n */\nexport interface SessionTitleProps {\n className?: string;\n}\n\n/**\n * Component that displays the current session name as an editable text field.\n * Shows the model name if available and a placeholder if no session is selected.\n *\n * @example\n * ```tsx\n * <SessionTitle className=\"my-custom-class\" />\n * ```\n */\nexport const SessionTitle: React.FC<SessionTitleProps> = ({className}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const renameSession = useStoreWithAi((s) => s.ai.renameSession);\n\n return (\n <div className={cn('flex items-center gap-2', className)}>\n {currentSession ? (\n <EditableText\n value={currentSession.name}\n onChange={(newName) => {\n if (currentSession && newName.trim()) {\n renameSession(currentSession.id, newName);\n }\n }}\n placeholder=\"Session name\"\n className=\"text-sm font-medium\"\n maxWidth={300}\n />\n ) : (\n <span className=\"text-muted-foreground text-sm font-medium\">\n No session selected\n </span>\n )}\n </div>\n );\n};\n"]}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Represents a session in the AI system.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * const session: SessionType = {
7
+ * id: "session_123",
8
+ * name: "My Analysis Session",
9
+ * modelProvider: "openai",
10
+ * model: "gpt-4o-mini"
11
+ * };
12
+ * ```
13
+ */
14
+ export type SessionType = {
15
+ /** Unique identifier for the session */
16
+ id: string;
17
+ /** Display name of the session */
18
+ name: string;
19
+ /** Provider of the AI model (e.g., "openai") */
20
+ modelProvider?: string;
21
+ /** Name of the AI model being used (e.g., "gpt-4o-mini") */
22
+ model?: string;
23
+ };
24
+ //# sourceMappingURL=SessionType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionType.d.ts","sourceRoot":"","sources":["../../../src/components/session/SessionType.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IAEX,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SessionType.js.map