@prostgles/prostgles 2.3.6-dev.1786548258

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 (1650) hide show
  1. package/.dockerignore +14 -0
  2. package/.eslintrc.common.js +71 -0
  3. package/.gitattributes +2 -0
  4. package/.github/ISSUE_TEMPLATE/BUG.yml +52 -0
  5. package/.github/ISSUE_TEMPLATE/CUSTOM.yml +13 -0
  6. package/.github/ISSUE_TEMPLATE/FEATURE.yml +27 -0
  7. package/.github/ISSUE_TEMPLATE/bug_report.md +9 -0
  8. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  9. package/.github/ISSUE_TEMPLATE/custom.md +3 -0
  10. package/.github/ISSUE_TEMPLATE/feature_request.md +5 -0
  11. package/.github/workflows/docker_test.yml +46 -0
  12. package/.github/workflows/electron_build_linux.yml +40 -0
  13. package/.github/workflows/electron_build_macos.yml +36 -0
  14. package/.github/workflows/electron_build_windows.yml +34 -0
  15. package/.github/workflows/electron_linux_test.yml +24 -0
  16. package/.github/workflows/electron_macos_test.yml +25 -0
  17. package/.github/workflows/linux_test.yml +127 -0
  18. package/.github/workflows/macos_test.yml +63 -0
  19. package/.github/workflows/on_release.yml +185 -0
  20. package/.github/workflows/package_version_increased.yml +66 -0
  21. package/.github/workflows/publish_release.yml +67 -0
  22. package/.github/workflows/windows_test.yml +48 -0
  23. package/.prettierignore +5 -0
  24. package/.prettierrc +3 -0
  25. package/.vscode/settings.json +46 -0
  26. package/CODE_OF_CONDUCT +47 -0
  27. package/CONTRIBUTING +59 -0
  28. package/DB.Dockerfile +11 -0
  29. package/Dockerfile +31 -0
  30. package/LICENSE +661 -0
  31. package/PRIVACY +28 -0
  32. package/README.md +132 -0
  33. package/SECURITY.md +8 -0
  34. package/changelog/v1.0.0.md +5 -0
  35. package/changelog/v2.0.0.md +25 -0
  36. package/changelog/v2.2.0.md +13 -0
  37. package/changelog/v2.2.1.md +4 -0
  38. package/changelog/v2.2.2.md +3 -0
  39. package/changelog/v2.2.3.md +2 -0
  40. package/changelog/v2.2.4.md +3 -0
  41. package/changelog/v2.3.0.md +5 -0
  42. package/changelog/v2.3.1.md +1 -0
  43. package/changelog/v2.3.2.md +1 -0
  44. package/changelog/v2.3.3.md +2 -0
  45. package/changelog/v2.3.4.md +2 -0
  46. package/changelog/v2.3.5.md +2 -0
  47. package/changelog/v2.3.6.md +2 -0
  48. package/client/build.sh +1 -0
  49. package/client/eslint.config.mjs +114 -0
  50. package/client/package-lock.json +16513 -0
  51. package/client/package.json +108 -0
  52. package/client/public/manifest.json +12 -0
  53. package/client/public/robots.txt +3 -0
  54. package/client/setup-icons.js +59 -0
  55. package/client/src/App.css +31 -0
  56. package/client/src/App.tsx +364 -0
  57. package/client/src/Testing.ts +724 -0
  58. package/client/src/app/CommandPalette/CommandPalette.css +11 -0
  59. package/client/src/app/CommandPalette/CommandPalette.tsx +119 -0
  60. package/client/src/app/CommandPalette/Documentation.css +3 -0
  61. package/client/src/app/CommandPalette/Documentation.tsx +77 -0
  62. package/client/src/app/CommandPalette/DynamicComponent.tsx +87 -0
  63. package/client/src/app/CommandPalette/getDocumentation.ts +175 -0
  64. package/client/src/app/CommandPalette/getUIDocShortestPath.ts +62 -0
  65. package/client/src/app/CommandPalette/useCommandPaletteState.tsx +188 -0
  66. package/client/src/app/CommandPalette/useGoToUI.tsx +147 -0
  67. package/client/src/app/CommandPalette/useHighlightDocItem.ts +89 -0
  68. package/client/src/app/CommandPalette/utils.ts +111 -0
  69. package/client/src/app/UIDocs/UIInstallationUIDoc.ts +43 -0
  70. package/client/src/app/UIDocs/accountUIDoc.ts +128 -0
  71. package/client/src/app/UIDocs/commandPaletteUIDoc.ts +40 -0
  72. package/client/src/app/UIDocs/connection/AIAssistantUIDoc.ts +309 -0
  73. package/client/src/app/UIDocs/connection/agenticWorkflowsUIDoc.ts +37 -0
  74. package/client/src/app/UIDocs/connection/config/accessControlUIDoc.ts +44 -0
  75. package/client/src/app/UIDocs/connection/config/apiUIDoc.ts +95 -0
  76. package/client/src/app/UIDocs/connection/config/authentication.UIDoc.ts +96 -0
  77. package/client/src/app/UIDocs/connection/config/backupAndRestoreUIDoc.ts +238 -0
  78. package/client/src/app/UIDocs/connection/config/fileStorageUIDoc.ts +27 -0
  79. package/client/src/app/UIDocs/connection/connectionConfigUIDoc.ts +79 -0
  80. package/client/src/app/UIDocs/connection/dashboard/dashboardContentUIDoc.ts +27 -0
  81. package/client/src/app/UIDocs/connection/dashboard/dashboardMenuUIDoc.ts +189 -0
  82. package/client/src/app/UIDocs/connection/dashboard/mapUIDoc.ts +172 -0
  83. package/client/src/app/UIDocs/connection/dashboard/schemaGraphUIDoc.ts +66 -0
  84. package/client/src/app/UIDocs/connection/dashboard/serverSideFunctionUIDoc.ts +27 -0
  85. package/client/src/app/UIDocs/connection/dashboard/sqlEditorUIDoc.ts +284 -0
  86. package/client/src/app/UIDocs/connection/dashboard/table/addColumnMenuUIDoc.ts +250 -0
  87. package/client/src/app/UIDocs/connection/dashboard/table/columnMenuUIDoc.ts +123 -0
  88. package/client/src/app/UIDocs/connection/dashboard/table/paginationUIDoc.ts +56 -0
  89. package/client/src/app/UIDocs/connection/dashboard/table/smartFilterBarUIDoc.ts +126 -0
  90. package/client/src/app/UIDocs/connection/dashboard/table/smartFormUIDoc.ts +168 -0
  91. package/client/src/app/UIDocs/connection/dashboard/table/tableMenuUIDoc.ts +228 -0
  92. package/client/src/app/UIDocs/connection/dashboard/table/tableUIDoc.ts +90 -0
  93. package/client/src/app/UIDocs/connection/dashboard/timechartUIDoc.ts +169 -0
  94. package/client/src/app/UIDocs/connection/dashboardUIDoc.ts +176 -0
  95. package/client/src/app/UIDocs/connection/getCommonViewHeaderUIDoc.ts +146 -0
  96. package/client/src/app/UIDocs/connectionsUIDoc.ts +261 -0
  97. package/client/src/app/UIDocs/desktopInstallation.ts +32 -0
  98. package/client/src/app/UIDocs/editConnectionUIDoc.ts +131 -0
  99. package/client/src/app/UIDocs/navbarUIDoc.ts +145 -0
  100. package/client/src/app/UIDocs/overviewUIDoc.ts +31 -0
  101. package/client/src/app/UIDocs/serverSettingsUIDoc.ts +64 -0
  102. package/client/src/app/UIDocs.ts +274 -0
  103. package/client/src/app/XRealIpSpoofableAlert.tsx +39 -0
  104. package/client/src/app/domToSVG/SVGif/addSVGifCaption.ts +112 -0
  105. package/client/src/app/domToSVG/SVGif/addSVGifPointer.ts +59 -0
  106. package/client/src/app/domToSVG/SVGif/addSVGifTimelineControls.ts +94 -0
  107. package/client/src/app/domToSVG/SVGif/animations/getSVGifCursorAnimationHandler.ts +162 -0
  108. package/client/src/app/domToSVG/SVGif/animations/getSVGifCustomAnimation.ts +53 -0
  109. package/client/src/app/domToSVG/SVGif/animations/getSVGifPropertiesAnimation.ts +50 -0
  110. package/client/src/app/domToSVG/SVGif/animations/getSVGifTypeAnimation.ts +105 -0
  111. package/client/src/app/domToSVG/SVGif/animations/getSVGifZoomToAnimation.ts +114 -0
  112. package/client/src/app/domToSVG/SVGif/compressSVGif.ts +86 -0
  113. package/client/src/app/domToSVG/SVGif/getSVGif.ts +111 -0
  114. package/client/src/app/domToSVG/SVGif/getSVGifAnimations.ts +318 -0
  115. package/client/src/app/domToSVG/SVGif/getSVGifKeyframes.ts +42 -0
  116. package/client/src/app/domToSVG/SVGif/getSVGifParsedScenes.ts +52 -0
  117. package/client/src/app/domToSVG/SVGif/getSVGifRevealKeyframes.ts +73 -0
  118. package/client/src/app/domToSVG/SVGif/getSVGifTargetBBox.ts +36 -0
  119. package/client/src/app/domToSVG/addFragmentViewBoxes.ts +43 -0
  120. package/client/src/app/domToSVG/containers/addOverflowClipPath.ts +117 -0
  121. package/client/src/app/domToSVG/containers/bgAndBorderToSVG.ts +204 -0
  122. package/client/src/app/domToSVG/containers/deduplicateSVGPaths.ts +128 -0
  123. package/client/src/app/domToSVG/containers/elementToSVG.ts +231 -0
  124. package/client/src/app/domToSVG/containers/rectangleToSVG.ts +196 -0
  125. package/client/src/app/domToSVG/containers/shadowToSVG.ts +52 -0
  126. package/client/src/app/domToSVG/domToSVG.ts +263 -0
  127. package/client/src/app/domToSVG/domToSvg2.ts +129 -0
  128. package/client/src/app/domToSVG/domToThemeAwareSVG.ts +361 -0
  129. package/client/src/app/domToSVG/getCorrespondingDarkNode.ts +87 -0
  130. package/client/src/app/domToSVG/graphics/fontIconToSVG.ts +141 -0
  131. package/client/src/app/domToSVG/graphics/getForeignObject.ts +43 -0
  132. package/client/src/app/domToSVG/graphics/imgToSVG.ts +140 -0
  133. package/client/src/app/domToSVG/setThemeForSVGScreenshot.ts +82 -0
  134. package/client/src/app/domToSVG/text/getTextForSVG.ts +243 -0
  135. package/client/src/app/domToSVG/text/textToSVG.ts +264 -0
  136. package/client/src/app/domToSVG/utils/addNewChildren.ts +55 -0
  137. package/client/src/app/domToSVG/utils/canvasToDataURL.ts +6 -0
  138. package/client/src/app/domToSVG/utils/copyAnimationStylesToSvg.ts +127 -0
  139. package/client/src/app/domToSVG/utils/getWhatToRenderOnSVG.ts +218 -0
  140. package/client/src/app/domToSVG/utils/isElementVisible.ts +144 -0
  141. package/client/src/app/domToSVG/utils/toFixed.ts +3 -0
  142. package/client/src/appUtils.ts +135 -0
  143. package/client/src/components/AlertProvider.tsx +99 -0
  144. package/client/src/components/Animations.css +207 -0
  145. package/client/src/components/Animations.tsx +130 -0
  146. package/client/src/components/Btn.css +235 -0
  147. package/client/src/components/Btn.tsx +603 -0
  148. package/client/src/components/ButtonBar.tsx +29 -0
  149. package/client/src/components/ButtonGroup.tsx +135 -0
  150. package/client/src/components/Chat/Chat.css +116 -0
  151. package/client/src/components/Chat/Chat.tsx +200 -0
  152. package/client/src/components/Chat/ChatFileAttachments/ChatFileAttachments.tsx +126 -0
  153. package/client/src/components/Chat/ChatMessage.tsx +38 -0
  154. package/client/src/components/Chat/ChatSendControls.tsx +117 -0
  155. package/client/src/components/Chat/ChatSpeech/ChatSpeech.tsx +201 -0
  156. package/client/src/components/Chat/ChatSpeech/ChatSpeechSetup.tsx +75 -0
  157. package/client/src/components/Chat/ChatSpeech/hooks/SpeechRecorder.ts +295 -0
  158. package/client/src/components/Chat/ChatSpeech/hooks/renderSpeechAudioLevelsIcon.ts +67 -0
  159. package/client/src/components/Chat/ChatSpeech/hooks/useSpeechRecorder.ts +59 -0
  160. package/client/src/components/Chat/ChatSpeech/hooks/useSpeechToTextWeb.ts +125 -0
  161. package/client/src/components/Chat/ChatSpeech/useChatSpeechSetup.ts +106 -0
  162. package/client/src/components/Chat/Marked.tsx +258 -0
  163. package/client/src/components/Chat/MonacoCodeInMarkdown/MarkdownMonacoCodeHeader.tsx +179 -0
  164. package/client/src/components/Chat/MonacoCodeInMarkdown/MonacoCodeInMarkdown.tsx +162 -0
  165. package/client/src/components/Chat/MonacoCodeInMarkdown/useOnRunSQL.ts +70 -0
  166. package/client/src/components/Chat/useChatFileUpload.ts +167 -0
  167. package/client/src/components/Chat/useChatOnPaste.ts +102 -0
  168. package/client/src/components/Chat/useChatState.ts +118 -0
  169. package/client/src/components/Checkbox.css +24 -0
  170. package/client/src/components/Checkbox.tsx +152 -0
  171. package/client/src/components/Chip.css +78 -0
  172. package/client/src/components/Chip.tsx +150 -0
  173. package/client/src/components/ClickCatch.tsx +49 -0
  174. package/client/src/components/ClickCatchOverlay.css +7 -0
  175. package/client/src/components/ClickCatchOverlay.tsx +30 -0
  176. package/client/src/components/CodeFileBrowser/CodeFileBrowser.tsx +85 -0
  177. package/client/src/components/CodeFileBrowser/ProjectCodeEditor.tsx +89 -0
  178. package/client/src/components/CodeFileBrowser/WebAppFileBrowser.tsx +96 -0
  179. package/client/src/components/CompactTabs/CompactTabs.tsx +101 -0
  180. package/client/src/components/ConfirmationDialog.tsx +90 -0
  181. package/client/src/components/CopyToClipboardBtn.tsx +24 -0
  182. package/client/src/components/DragOverUpload/DragOverUpload.css +36 -0
  183. package/client/src/components/DragOverUpload/DragOverUpload.tsx +46 -0
  184. package/client/src/components/DraggableLI.tsx +182 -0
  185. package/client/src/components/ElectronSearchBar.tsx +335 -0
  186. package/client/src/components/ErrorComponent.tsx +240 -0
  187. package/client/src/components/ExpandSection.tsx +55 -0
  188. package/client/src/components/Expander.tsx +16 -0
  189. package/client/src/components/FileInput/DropZone.tsx +23 -0
  190. package/client/src/components/FileInput/FileInput.tsx +363 -0
  191. package/client/src/components/FileInput/FileInputMedia.tsx +144 -0
  192. package/client/src/components/FileInput/useFileDropZone.ts +51 -0
  193. package/client/src/components/FileTree/FILE_EXTENSION_TO_ICON_INFO.ts +687 -0
  194. package/client/src/components/FileTree/FileIcon.tsx +31 -0
  195. package/client/src/components/FileTree/FileTree.tsx +147 -0
  196. package/client/src/components/FileTree/FileTreeCurrentDirectory.tsx +135 -0
  197. package/client/src/components/FileTree/FileTreeNode.css +12 -0
  198. package/client/src/components/FileTree/FileTreeNode.tsx +264 -0
  199. package/client/src/components/FileTree/FileTreeNodeCheckbox.tsx +48 -0
  200. package/client/src/components/FileTree/FileTreeSearchBar.tsx +121 -0
  201. package/client/src/components/FileTree/FileTreeSelectedItems.tsx +73 -0
  202. package/client/src/components/FileTree/FolderIcon.tsx +18 -0
  203. package/client/src/components/FileTree/fileSystemTreeUtils.ts +15 -0
  204. package/client/src/components/FileTree/useFileTree.ts +255 -0
  205. package/client/src/components/FileTree/useFileTreeChecked.ts +158 -0
  206. package/client/src/components/FlashMessage.tsx +64 -0
  207. package/client/src/components/Flex.tsx +76 -0
  208. package/client/src/components/FormField/FormField.css +91 -0
  209. package/client/src/components/FormField/FormField.tsx +748 -0
  210. package/client/src/components/FormField/FormFieldCodeEditor.tsx +97 -0
  211. package/client/src/components/FormField/FormFieldDebounced.tsx +60 -0
  212. package/client/src/components/FormField/FormFieldSkeleton.tsx +206 -0
  213. package/client/src/components/FormField/onFormFieldKeyDown.ts +124 -0
  214. package/client/src/components/FullscreenWrapper/FullscreenWrapper.tsx +154 -0
  215. package/client/src/components/FullscreenWrapper/useFullscreen.ts +46 -0
  216. package/client/src/components/HeaderSection.tsx +36 -0
  217. package/client/src/components/Hotkey.css +12 -0
  218. package/client/src/components/Hotkey.tsx +26 -0
  219. package/client/src/components/IFrame/IFrame.tsx +54 -0
  220. package/client/src/components/Icon/Icon.tsx +138 -0
  221. package/client/src/components/IconPalette/IconPalette.tsx +194 -0
  222. package/client/src/components/InfoRow.tsx +64 -0
  223. package/client/src/components/Input.tsx +63 -0
  224. package/client/src/components/JSONBSchema/JSONBSchema.tsx +182 -0
  225. package/client/src/components/JSONBSchema/JSONBSchemaAllowedOptions.tsx +112 -0
  226. package/client/src/components/JSONBSchema/JSONBSchemaArray.tsx +172 -0
  227. package/client/src/components/JSONBSchema/JSONBSchemaLookup.tsx +249 -0
  228. package/client/src/components/JSONBSchema/JSONBSchemaObject.tsx +130 -0
  229. package/client/src/components/JSONBSchema/JSONBSchemaOneOfType.tsx +155 -0
  230. package/client/src/components/JSONBSchema/JSONBSchemaPrimitive.tsx +209 -0
  231. package/client/src/components/JSONBSchema/JSONBSchemaRecord.tsx +78 -0
  232. package/client/src/components/JSONBSchema/isCompleteJSONB.ts +54 -0
  233. package/client/src/components/Label.css +10 -0
  234. package/client/src/components/Label.tsx +152 -0
  235. package/client/src/components/LabeledRow.tsx +51 -0
  236. package/client/src/components/List.css +51 -0
  237. package/client/src/components/List.tsx +170 -0
  238. package/client/src/components/Loader/Loading.css +141 -0
  239. package/client/src/components/Loader/Loading.tsx +254 -0
  240. package/client/src/components/Loader/SpinnerV2.tsx +121 -0
  241. package/client/src/components/Loader/SpinnerV3.tsx +58 -0
  242. package/client/src/components/Loader/SpinnerV4.tsx +31 -0
  243. package/client/src/components/MarkdownWithPlugins/MarkdownWithPlugins.tsx +99 -0
  244. package/client/src/components/MarkdownWithPlugins/Marked.css +72 -0
  245. package/client/src/components/MarkdownWithPlugins/preserveDisallowedHtmlAsText.ts +76 -0
  246. package/client/src/components/MediaViewer/MediaViewer.tsx +252 -0
  247. package/client/src/components/MediaViewer/MediaViewerContent.tsx +223 -0
  248. package/client/src/components/MediaViewer/managedTableUtils.ts +99 -0
  249. package/client/src/components/MenuList.css +3 -0
  250. package/client/src/components/MenuList.tsx +237 -0
  251. package/client/src/components/MenuListItem.tsx +126 -0
  252. package/client/src/components/MonacoEditor/MonacoEditor.tsx +273 -0
  253. package/client/src/components/MonacoEditor/monacoHackyFixes.ts +56 -0
  254. package/client/src/components/MonacoEditor/useMonacoEditorAddActions.ts +56 -0
  255. package/client/src/components/MonacoEditor/useWhyDidYouUpdate.ts +80 -0
  256. package/client/src/components/MonacoLogs/MonacoLogs.tsx +98 -0
  257. package/client/src/components/MonacoLogs/MonacoLogsWithFullscreen.tsx +124 -0
  258. package/client/src/components/MonacoLogs/setAnsiLogContent.ts +163 -0
  259. package/client/src/components/NavBar/NavBar.css +110 -0
  260. package/client/src/components/NavBar/NavBar.tsx +152 -0
  261. package/client/src/components/NavBar/NavBarWrapper.tsx +55 -0
  262. package/client/src/components/NavBar/useNavBarItems.ts +40 -0
  263. package/client/src/components/Pan.tsx +63 -0
  264. package/client/src/components/PdfViewer/PdfViewer.css +58 -0
  265. package/client/src/components/PdfViewer/PdfViewer.tsx +126 -0
  266. package/client/src/components/PdfViewer/PdfViewerDoclingTextOverlay.tsx +44 -0
  267. package/client/src/components/PdfViewer/PdfViewerHeaderControls.tsx +82 -0
  268. package/client/src/components/PdfViewer/PdfViewerHighlights/PdfViewerHighlights.tsx +146 -0
  269. package/client/src/components/PdfViewer/PdfViewerHighlights/usePdfViewerHighlights.ts +212 -0
  270. package/client/src/components/PdfViewer/PdfViewerSearch/PdfViewerSearch.css +21 -0
  271. package/client/src/components/PdfViewer/PdfViewerSearch/PdfViewerSearch.tsx +323 -0
  272. package/client/src/components/PdfViewer/PdfViewerWithFileTableContext.tsx +209 -0
  273. package/client/src/components/PdfViewer/usePdfViewer.ts +215 -0
  274. package/client/src/components/Popup/Footer.tsx +41 -0
  275. package/client/src/components/Popup/FooterButtons.tsx +60 -0
  276. package/client/src/components/Popup/Popup.css +14 -0
  277. package/client/src/components/Popup/Popup.tsx +469 -0
  278. package/client/src/components/Popup/PopupHeader.tsx +113 -0
  279. package/client/src/components/Popup/getPopupPosition.ts +137 -0
  280. package/client/src/components/Popup/getPopupStyle.ts +57 -0
  281. package/client/src/components/Popup/popupCheckPosition.ts +280 -0
  282. package/client/src/components/PopupMenu.tsx +106 -0
  283. package/client/src/components/PopupMenuList.tsx +36 -0
  284. package/client/src/components/PostgresInstallationInstructions.tsx +112 -0
  285. package/client/src/components/ProgressBar.css +29 -0
  286. package/client/src/components/ProgressBar.tsx +131 -0
  287. package/client/src/components/QRCodeImage.tsx +57 -0
  288. package/client/src/components/Scheduler.css +7 -0
  289. package/client/src/components/Scheduler.tsx +149 -0
  290. package/client/src/components/ScrollFade/ScrollFade.css +4 -0
  291. package/client/src/components/ScrollFade/ScrollFade.tsx +177 -0
  292. package/client/src/components/ScrollFade/useAutoScrollToBottom.ts +31 -0
  293. package/client/src/components/ScrollFade/useResizeObserver.ts +96 -0
  294. package/client/src/components/SearchList/SearchInput.tsx +143 -0
  295. package/client/src/components/SearchList/SearchList.css +37 -0
  296. package/client/src/components/SearchList/SearchList.tsx +184 -0
  297. package/client/src/components/SearchList/SearchListContent.tsx +285 -0
  298. package/client/src/components/SearchList/SearchListItems.tsx +244 -0
  299. package/client/src/components/SearchList/SearchListRowContent.tsx +46 -0
  300. package/client/src/components/SearchList/getSearchListMatchAndHighlight.tsx +162 -0
  301. package/client/src/components/SearchList/hooks/useSearchListItems.tsx +113 -0
  302. package/client/src/components/SearchList/hooks/useSearchListItemsSorting.tsx +169 -0
  303. package/client/src/components/SearchList/hooks/useSearchListOnClick.ts +69 -0
  304. package/client/src/components/SearchList/hooks/useSearchListOnKeyUpDown.ts +128 -0
  305. package/client/src/components/SearchList/hooks/useSearchListSearch.ts +211 -0
  306. package/client/src/components/SearchList/searchMatchUtils/getItemSearchRank.ts +74 -0
  307. package/client/src/components/SearchList/searchMatchUtils/getSearchRanking.ts +18 -0
  308. package/client/src/components/Section.tsx +159 -0
  309. package/client/src/components/SegmentedToggle.tsx +57 -0
  310. package/client/src/components/Select/Select.css +18 -0
  311. package/client/src/components/Select/Select.tsx +629 -0
  312. package/client/src/components/Select/SelectTriggerButton.tsx +204 -0
  313. package/client/src/components/ShorterText.tsx +56 -0
  314. package/client/src/components/SidePanel.tsx +49 -0
  315. package/client/src/components/Slider.css +65 -0
  316. package/client/src/components/Slider.tsx +66 -0
  317. package/client/src/components/StatusChip.tsx +34 -0
  318. package/client/src/components/Stepper.tsx +92 -0
  319. package/client/src/components/Stopwatch.tsx +121 -0
  320. package/client/src/components/SvgIcon.tsx +181 -0
  321. package/client/src/components/SwitchToggle.css +136 -0
  322. package/client/src/components/SwitchToggle.tsx +141 -0
  323. package/client/src/components/Table/Pagination.tsx +178 -0
  324. package/client/src/components/Table/Table.css +97 -0
  325. package/client/src/components/Table/Table.tsx +216 -0
  326. package/client/src/components/Table/TableBody.tsx +146 -0
  327. package/client/src/components/Table/TableHeader.tsx +491 -0
  328. package/client/src/components/Table/TableRow.tsx +164 -0
  329. package/client/src/components/Table/useVirtualisedRows.ts +160 -0
  330. package/client/src/components/Tabs.tsx +320 -0
  331. package/client/src/components/Tooltip.tsx +47 -0
  332. package/client/src/dashboard/API/zip.ts +151 -0
  333. package/client/src/dashboard/AccessControl/AccessControl.tsx +164 -0
  334. package/client/src/dashboard/AccessControl/AccessControlRuleEditor.tsx +373 -0
  335. package/client/src/dashboard/AccessControl/AccessRuleEditorFooter.tsx +241 -0
  336. package/client/src/dashboard/AccessControl/AccessRuleSummary.tsx +159 -0
  337. package/client/src/dashboard/AccessControl/ContextDataSelector.tsx +89 -0
  338. package/client/src/dashboard/AccessControl/ContextFilter.tsx +161 -0
  339. package/client/src/dashboard/AccessControl/ExistingAccessRules.tsx +168 -0
  340. package/client/src/dashboard/AccessControl/Methods/MethodDefinition.tsx +156 -0
  341. package/client/src/dashboard/AccessControl/Methods/MethodDefinitionEditAsJson.tsx +73 -0
  342. package/client/src/dashboard/AccessControl/Methods/MethodFunctionDefinition.tsx +97 -0
  343. package/client/src/dashboard/AccessControl/Methods/ReferencesDefinition.tsx +155 -0
  344. package/client/src/dashboard/AccessControl/Methods/useCodeEditorTsTypes.ts +152 -0
  345. package/client/src/dashboard/AccessControl/OptionControllers/DynamicFields.tsx +145 -0
  346. package/client/src/dashboard/AccessControl/OptionControllers/FieldFilterControl.tsx +193 -0
  347. package/client/src/dashboard/AccessControl/OptionControllers/FilterControl.tsx +207 -0
  348. package/client/src/dashboard/AccessControl/PasswordlessSetup.tsx +90 -0
  349. package/client/src/dashboard/AccessControl/PermissionTypes/PAllTables.tsx +50 -0
  350. package/client/src/dashboard/AccessControl/PermissionTypes/PCustomTables.tsx +237 -0
  351. package/client/src/dashboard/AccessControl/PermissionTypes/PRunSQL.tsx +92 -0
  352. package/client/src/dashboard/AccessControl/PublishedWorkspaceSelector.tsx +290 -0
  353. package/client/src/dashboard/AccessControl/RuleTypeControls/ComparablePGPolicies.tsx +179 -0
  354. package/client/src/dashboard/AccessControl/RuleTypeControls/DeleteRuleControl.tsx +95 -0
  355. package/client/src/dashboard/AccessControl/RuleTypeControls/ExampleComparablePolicy.tsx +112 -0
  356. package/client/src/dashboard/AccessControl/RuleTypeControls/InsertRuleControl.tsx +115 -0
  357. package/client/src/dashboard/AccessControl/RuleTypeControls/RuleToggle.tsx +19 -0
  358. package/client/src/dashboard/AccessControl/RuleTypeControls/SelectRuleControl.tsx +186 -0
  359. package/client/src/dashboard/AccessControl/RuleTypeControls/SyncRuleControl.tsx +130 -0
  360. package/client/src/dashboard/AccessControl/RuleTypeControls/UpdateRuleControl.tsx +207 -0
  361. package/client/src/dashboard/AccessControl/RuleTypeControls/getComparablePGPolicy.ts +130 -0
  362. package/client/src/dashboard/AccessControl/TableRules/FileTableAccessControlInfo.tsx +161 -0
  363. package/client/src/dashboard/AccessControl/TableRules/TablePermissionControls.tsx +251 -0
  364. package/client/src/dashboard/AccessControl/TableRules/TableRulesPopup.tsx +167 -0
  365. package/client/src/dashboard/AccessControl/TableRules/useLocalTableRulesErrors.ts +27 -0
  366. package/client/src/dashboard/AccessControl/UserStats.tsx +83 -0
  367. package/client/src/dashboard/AccessControl/UserSyncConfig.tsx +168 -0
  368. package/client/src/dashboard/AccessControl/UserTypeSelect.tsx +86 -0
  369. package/client/src/dashboard/AccessControl/useAccessControlSearchParams.ts +81 -0
  370. package/client/src/dashboard/AccessControl/useEditedAccessRule.ts +293 -0
  371. package/client/src/dashboard/AskLLM/AskLLM.tsx +91 -0
  372. package/client/src/dashboard/AskLLM/Chat/AskLLMChat.tsx +208 -0
  373. package/client/src/dashboard/AskLLM/Chat/AskLLMChatHeader.tsx +127 -0
  374. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMChatMessage.tsx +77 -0
  375. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMChatMessageContent.tsx +96 -0
  376. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMChatMessageContentText.tsx +57 -0
  377. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMChatMessageHeader.tsx +129 -0
  378. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMGroupedToolCallsMessage.tsx +122 -0
  379. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMSingleChatMessage.tsx +44 -0
  380. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/LLMChatMessage/LLMToolCallIcon.tsx +12 -0
  381. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/Agent/Agent.tsx +161 -0
  382. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/Agent/AgentGoalToolCall.tsx +59 -0
  383. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgentDefinition.tsx +206 -0
  384. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflow.tsx +242 -0
  385. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowActions.tsx +245 -0
  386. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowActivity/AgenticWorkflowActivity.tsx +225 -0
  387. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowActivity/ToolCall.tsx +137 -0
  388. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowActivity/useAgenticWorkflowActivityItems.ts +70 -0
  389. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowDefinition.tsx +173 -0
  390. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowDetails.tsx +141 -0
  391. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowMessage.tsx +103 -0
  392. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/AgenticWorkflowSchemaDrift.tsx +146 -0
  393. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/ContainerConfigurationEditor.tsx +184 -0
  394. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/McpToolAccess.tsx +156 -0
  395. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/UserInput.tsx +393 -0
  396. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/UserInputColumnValues.tsx +61 -0
  397. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/hooks/useAgenticWorkflowState.ts +50 -0
  398. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AgenticWorkflow/hooks/useUserInput.ts +27 -0
  399. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/AskUserQuestions.tsx +249 -0
  400. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/CreateTables.tsx +32 -0
  401. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DockerContainer.tsx +296 -0
  402. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DoclingConvertedDocument/DoclingDocument.d.ts +154 -0
  403. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DoclingConvertedDocument/DoclingDocumentViewer.tsx +98 -0
  404. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DoclingConvertedDocument/DoclingDocumentViewerPage.tsx +42 -0
  405. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DoclingConvertedDocument/DoclingTable.tsx +166 -0
  406. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DoclingConvertedDocument/DoclingText.tsx +99 -0
  407. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/DoclingConvertedDocument/DoclingToolUseView.tsx +47 -0
  408. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/ExecuteSQL.tsx +34 -0
  409. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/LoadSuggestedDashboards.tsx +172 -0
  410. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/RequestToolAccess.tsx +272 -0
  411. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/RunCodeInSandbox.tsx +33 -0
  412. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/RunTypescriptInNodejs.tsx +48 -0
  413. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/ToolUseResultError.tsx +29 -0
  414. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/WebSearch/Favicon.tsx +34 -0
  415. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/WebSearch/Markdown.tsx +21 -0
  416. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/WebSearch/WebSearch.tsx +70 -0
  417. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/Webdev/CreateComponentQuickFeedbackPreview.tsx +104 -0
  418. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/common/DatabaseAccessPermissions.tsx +63 -0
  419. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/common/HeaderList.tsx +26 -0
  420. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/common/useJSONBParsedData.ts +16 -0
  421. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/common/useSendToolUseResult.ts +46 -0
  422. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/common/useToolUseResultString.ts +27 -0
  423. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesMCPTools/common/useTypedToolUseResultData.ts +85 -0
  424. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ProstglesToolUseMessage/ProstglesToolUseMessage.tsx +127 -0
  425. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/InChatToolApprover.tsx +82 -0
  426. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/ToolUseChatMessage.tsx +109 -0
  427. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/ToolUseChatMessageBtn.tsx +51 -0
  428. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/ToolUseChatMessageBtnTextSummary.tsx +45 -0
  429. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/ToolUseChatMessageJSONData.tsx +132 -0
  430. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/ToolUseChatMessageResult.tsx +57 -0
  431. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/ToolUseReRunBtn.tsx +71 -0
  432. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/useToolUseChatMessage.ts +51 -0
  433. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/ToolUseChatMessage/utils/getToolUseResult.ts +40 -0
  434. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/hooks/useLLMChatMessageGrouper.tsx +168 -0
  435. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/hooks/useLLMChatMessages.tsx +157 -0
  436. package/client/src/dashboard/AskLLM/Chat/AskLLMChatMessages/setChatPrompt.ts +116 -0
  437. package/client/src/dashboard/AskLLM/Chat/AskLLMChatSettings.tsx +88 -0
  438. package/client/src/dashboard/AskLLM/Chat/useAskLLMChatSend.ts +111 -0
  439. package/client/src/dashboard/AskLLM/Chat/useLLMChat.tsx +126 -0
  440. package/client/src/dashboard/AskLLM/Chat/useLLMSchemaStr.ts +207 -0
  441. package/client/src/dashboard/AskLLM/ChatActionBar/AskLLMChatActionBar.tsx +34 -0
  442. package/client/src/dashboard/AskLLM/ChatActionBar/AskLLMChatActionBarDatabaseAccess.tsx +273 -0
  443. package/client/src/dashboard/AskLLM/ChatActionBar/AskLLMChatActionBarMCPTools.tsx +102 -0
  444. package/client/src/dashboard/AskLLM/ChatActionBar/AskLLMChatActionBarMCPToolsBtn.tsx +167 -0
  445. package/client/src/dashboard/AskLLM/ChatActionBar/AskLLMChatActionBarModelSelector.tsx +238 -0
  446. package/client/src/dashboard/AskLLM/ChatActionBar/AskLLMChatActionBarPromptSelector.tsx +206 -0
  447. package/client/src/dashboard/AskLLM/ChatActionBar/PromptAndAllowedMcpToolsSchemaPreviews.tsx +85 -0
  448. package/client/src/dashboard/AskLLM/LLMModelSelector.tsx +270 -0
  449. package/client/src/dashboard/AskLLM/Setup/AddLLMPromptForm.tsx +33 -0
  450. package/client/src/dashboard/AskLLM/Setup/AskLLMAccessControl.tsx +246 -0
  451. package/client/src/dashboard/AskLLM/Setup/LLMProviderSetup.tsx +68 -0
  452. package/client/src/dashboard/AskLLM/Setup/LLMSetupProvider.tsx +111 -0
  453. package/client/src/dashboard/AskLLM/Setup/ProstglesSignup.tsx +108 -0
  454. package/client/src/dashboard/AskLLM/Setup/SetupLLMCredentials.tsx +89 -0
  455. package/client/src/dashboard/AskLLM/Tools/AskLLMToolApprover.tsx +279 -0
  456. package/client/src/dashboard/AskLLM/Tools/loadGeneratedWorkspaces/loadGeneratedBarchart.ts +126 -0
  457. package/client/src/dashboard/AskLLM/Tools/loadGeneratedWorkspaces/loadGeneratedMap.ts +58 -0
  458. package/client/src/dashboard/AskLLM/Tools/loadGeneratedWorkspaces/loadGeneratedTable.ts +159 -0
  459. package/client/src/dashboard/AskLLM/Tools/loadGeneratedWorkspaces/loadGeneratedTimechart.ts +78 -0
  460. package/client/src/dashboard/AskLLM/Tools/loadGeneratedWorkspaces/loadGeneratedWorkspaces.ts +168 -0
  461. package/client/src/dashboard/AskLLM/Tools/useAskLLMToolApprover.ts +99 -0
  462. package/client/src/dashboard/AskLLM/useLocalLLM.ts +84 -0
  463. package/client/src/dashboard/BackupAndRestore/AutomaticBackups.tsx +212 -0
  464. package/client/src/dashboard/BackupAndRestore/BackupsControls.tsx +291 -0
  465. package/client/src/dashboard/BackupAndRestore/BackupsInProgress.tsx +98 -0
  466. package/client/src/dashboard/BackupAndRestore/CloudStorageCredentialSelector.tsx +215 -0
  467. package/client/src/dashboard/BackupAndRestore/CodeConfirmation.tsx +205 -0
  468. package/client/src/dashboard/BackupAndRestore/CompletedBackups/DeleteAllBackups.tsx +58 -0
  469. package/client/src/dashboard/BackupAndRestore/CompletedBackups.tsx +276 -0
  470. package/client/src/dashboard/BackupAndRestore/DumpLocationOptions.tsx +40 -0
  471. package/client/src/dashboard/BackupAndRestore/DumpRestoreAlerts.tsx +82 -0
  472. package/client/src/dashboard/BackupAndRestore/PGDumpOptions.tsx +299 -0
  473. package/client/src/dashboard/BackupAndRestore/RenderBackupLogs.tsx +48 -0
  474. package/client/src/dashboard/BackupAndRestore/RenderBackupStatus.tsx +58 -0
  475. package/client/src/dashboard/BackupAndRestore/Restore/Restore.tsx +205 -0
  476. package/client/src/dashboard/BackupAndRestore/Restore/RestoreOptions.tsx +148 -0
  477. package/client/src/dashboard/BackupAndRestore/Restore/useRestoreDatabaseFromFile.ts +73 -0
  478. package/client/src/dashboard/BackupAndRestore/useBackupsControlsState.ts +39 -0
  479. package/client/src/dashboard/Charts/CanvasChart.ts +746 -0
  480. package/client/src/dashboard/Charts/TimeChart/TimeChart.tsx +232 -0
  481. package/client/src/dashboard/Charts/TimeChart/getBinValueLabels.ts +125 -0
  482. package/client/src/dashboard/Charts/TimeChart/getCssVariableValue.ts +6 -0
  483. package/client/src/dashboard/Charts/TimeChart/getTimeAxisTicks.ts +426 -0
  484. package/client/src/dashboard/Charts/TimeChart/getTimechartBinSize.ts +121 -0
  485. package/client/src/dashboard/Charts/TimeChart/getTimechartTooltipIntersections.ts +94 -0
  486. package/client/src/dashboard/Charts/TimeChart/getTimechartTooltipShapes.ts +318 -0
  487. package/client/src/dashboard/Charts/TimeChart/measureText.ts +34 -0
  488. package/client/src/dashboard/Charts/TimeChart/onDeltaTimechart.ts +65 -0
  489. package/client/src/dashboard/Charts/TimeChart/onRenderTimechart.ts +354 -0
  490. package/client/src/dashboard/Charts/TimeChart/prepareTimechartData.ts +185 -0
  491. package/client/src/dashboard/Charts/constants.ts +8 -0
  492. package/client/src/dashboard/Charts/createHiPPICanvas.ts +31 -0
  493. package/client/src/dashboard/Charts/drawMonotoneXCurve.ts +171 -0
  494. package/client/src/dashboard/Charts/drawShapes/drawLinkLine.ts +29 -0
  495. package/client/src/dashboard/Charts/drawShapes/drawShapes.ts +217 -0
  496. package/client/src/dashboard/Charts/drawShapes/drawShapesOnSVG.ts +481 -0
  497. package/client/src/dashboard/Charts/drawShapes/findShortestPathAroundRectangles.ts +241 -0
  498. package/client/src/dashboard/Charts/drawShapes/getLinkLinePoints.ts +124 -0
  499. package/client/src/dashboard/Charts/drawShapes/getTimechartGradientPeakSections.ts +27 -0
  500. package/client/src/dashboard/Charts/drawShapes/shortestLinkLineV2.ts +182 -0
  501. package/client/src/dashboard/Charts/roundRect.ts +42 -0
  502. package/client/src/dashboard/Charts.tsx +216 -0
  503. package/client/src/dashboard/CodeEditor/CodeEditor.tsx +288 -0
  504. package/client/src/dashboard/CodeEditor/CodeEditorWithSaveButton.tsx +208 -0
  505. package/client/src/dashboard/CodeEditor/registerLogLang.ts +128 -0
  506. package/client/src/dashboard/CodeEditor/utils/getMonacoJsonSchemas.ts +31 -0
  507. package/client/src/dashboard/CodeEditor/utils/installGoToDefinition.ts +40 -0
  508. package/client/src/dashboard/CodeEditor/utils/navigateTo.ts +61 -0
  509. package/client/src/dashboard/CodeEditor/utils/resolveDefinition..ts +33 -0
  510. package/client/src/dashboard/CodeEditor/utils/setMonacoErrorMarkers.ts +67 -0
  511. package/client/src/dashboard/CodeEditor/utils/useSetMonacoJsonSchemas.ts +60 -0
  512. package/client/src/dashboard/CodeEditor/utils/useSetMonacoTsLibraries.ts +157 -0
  513. package/client/src/dashboard/CodeExample.tsx +34 -0
  514. package/client/src/dashboard/ConnectionConfig/APIDetails/APICodeExamples.tsx +280 -0
  515. package/client/src/dashboard/ConnectionConfig/APIDetails/APIDetails.tsx +111 -0
  516. package/client/src/dashboard/ConnectionConfig/APIDetails/APIDetailsHttp.tsx +123 -0
  517. package/client/src/dashboard/ConnectionConfig/APIDetails/APIDetailsTokens.tsx +137 -0
  518. package/client/src/dashboard/ConnectionConfig/APIDetails/APIDetailsWs.tsx +98 -0
  519. package/client/src/dashboard/ConnectionConfig/APIDetails/AllowedOriginCheck.tsx +104 -0
  520. package/client/src/dashboard/ConnectionConfig/APIDetails/getApiEndpoint.ts +8 -0
  521. package/client/src/dashboard/ConnectionConfig/ConnectionConfig.tsx +267 -0
  522. package/client/src/dashboard/ConnectionConfig/ConnectionConfigSync.tsx +123 -0
  523. package/client/src/dashboard/ConnectionConfig/ServerSideFunctions.tsx +46 -0
  524. package/client/src/dashboard/ConnectionConfig/WebApp/WebAppConfig.tsx +90 -0
  525. package/client/src/dashboard/ConnectionConfig/WebApp/WebAppConfigComponents.tsx +47 -0
  526. package/client/src/dashboard/ConnectionConfig/WebApp/WebAppConfigFooterActions.tsx +137 -0
  527. package/client/src/dashboard/ConnectionConfig/WebApp/WebAppConfigSetup.tsx +135 -0
  528. package/client/src/dashboard/ConnectionConfig/WebApp/hooks/useWebAppConfigActiveSection.ts +12 -0
  529. package/client/src/dashboard/ConnectionConfig/WebApp/hooks/useWebAppConfigState.ts +76 -0
  530. package/client/src/dashboard/ConnectionConfig/useConnectionConfigSearchParams.ts +35 -0
  531. package/client/src/dashboard/ConnectionSelector.tsx +58 -0
  532. package/client/src/dashboard/Dashboard/CloseSaveSQLPopup.tsx +81 -0
  533. package/client/src/dashboard/Dashboard/DBS.ts +19 -0
  534. package/client/src/dashboard/Dashboard/Dashboard.tsx +667 -0
  535. package/client/src/dashboard/Dashboard/DashboardCenteredLayoutResizer.tsx +56 -0
  536. package/client/src/dashboard/Dashboard/PALETTE.ts +36 -0
  537. package/client/src/dashboard/Dashboard/ViewRenderer.tsx +498 -0
  538. package/client/src/dashboard/Dashboard/addChart.ts +261 -0
  539. package/client/src/dashboard/Dashboard/addLink.ts +48 -0
  540. package/client/src/dashboard/Dashboard/addWindow.ts +51 -0
  541. package/client/src/dashboard/Dashboard/cardLayout.ts +28 -0
  542. package/client/src/dashboard/Dashboard/cloneWorkspace.ts +102 -0
  543. package/client/src/dashboard/Dashboard/dashboardUtils.ts +377 -0
  544. package/client/src/dashboard/Dashboard/debuggingUtils.ts +112 -0
  545. package/client/src/dashboard/Dashboard/getTables.ts +31 -0
  546. package/client/src/dashboard/Dashboard/getViewRendererUtils.ts +108 -0
  547. package/client/src/dashboard/Dashboard/onLinkTable.ts +45 -0
  548. package/client/src/dashboard/Dashboard/useAddViewToWorkspace.ts +92 -0
  549. package/client/src/dashboard/DashboardMenu/CreateTable.tsx +307 -0
  550. package/client/src/dashboard/DashboardMenu/DashboardHotkeys.tsx +38 -0
  551. package/client/src/dashboard/DashboardMenu/DashboardMenu.tsx +183 -0
  552. package/client/src/dashboard/DashboardMenu/DashboardMenuContent.tsx +203 -0
  553. package/client/src/dashboard/DashboardMenu/DashboardMenuHeader.tsx +86 -0
  554. package/client/src/dashboard/DashboardMenu/DashboardMenuHotkeys.tsx +102 -0
  555. package/client/src/dashboard/DashboardMenu/DashboardMenuResizer.tsx +68 -0
  556. package/client/src/dashboard/DashboardMenu/DashboardMenuSettings.tsx +241 -0
  557. package/client/src/dashboard/DashboardMenu/NewTableMenu.tsx +121 -0
  558. package/client/src/dashboard/DashboardMenu/SavedAgenticWorkflowsAndContainers.tsx +149 -0
  559. package/client/src/dashboard/DashboardMenu/SettingsSection.tsx +22 -0
  560. package/client/src/dashboard/DashboardMenu/TableList.tsx +141 -0
  561. package/client/src/dashboard/DashboardMenu/useTableSizeInfo.ts +98 -0
  562. package/client/src/dashboard/DatabaseAccessEditor/DatabaseAccessEditor.tsx +174 -0
  563. package/client/src/dashboard/DatabaseAccessEditor/DatabaseAccessEditorCustomTables.tsx +149 -0
  564. package/client/src/dashboard/DatabaseAccessEditor/TableAccessAdvancedOptions.tsx +128 -0
  565. package/client/src/dashboard/DatabaseAccessEditor/TableAccessAdvancedOptionsMenu.tsx +65 -0
  566. package/client/src/dashboard/DatabaseAccessEditor/TableAccessDetails.tsx +163 -0
  567. package/client/src/dashboard/DatabaseAccessEditor/TableAccessEditor.tsx +229 -0
  568. package/client/src/dashboard/DatabaseAccessEditor/getTableSchemaDriftState.ts +65 -0
  569. package/client/src/dashboard/DatabaseAccessEditor/useDatabaseAccessEditorTables.tsx +99 -0
  570. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseControl.tsx +139 -0
  571. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseControlRouter.tsx +192 -0
  572. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseTypes/AgeFilter.tsx +148 -0
  573. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseTypes/GeoFilter.tsx +255 -0
  574. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseTypes/ListFilter/ListFilter.tsx +235 -0
  575. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseTypes/ListFilter/fetchListFilterOptions.ts +76 -0
  576. package/client/src/dashboard/DetailedFilterControl/DetailedFilterBaseTypes/NumberOrDateFilter.tsx +206 -0
  577. package/client/src/dashboard/DetailedFilterControl/DetailedFilterControl.tsx +157 -0
  578. package/client/src/dashboard/DetailedFilterControl/FTS_LANGUAGES.ts +35 -0
  579. package/client/src/dashboard/DetailedFilterControl/FilterWrapper.css +7 -0
  580. package/client/src/dashboard/DetailedFilterControl/FilterWrapper.tsx +339 -0
  581. package/client/src/dashboard/DetailedFilterControl/validateFilter.ts +46 -0
  582. package/client/src/dashboard/Feedback.tsx +145 -0
  583. package/client/src/dashboard/FileImporter/FileImporter.tsx +770 -0
  584. package/client/src/dashboard/FileImporter/FileImporterFooter.tsx +100 -0
  585. package/client/src/dashboard/FileImporter/checkCSVColumnDataTypes.tsx +139 -0
  586. package/client/src/dashboard/FileImporter/importFile.ts +303 -0
  587. package/client/src/dashboard/FileImporter/parseCSVFile.ts +123 -0
  588. package/client/src/dashboard/FileImporter/setFile.ts +251 -0
  589. package/client/src/dashboard/FileTableControls/CreateFileColumn.tsx +189 -0
  590. package/client/src/dashboard/FileTableControls/FileColumnConfigControls.tsx +191 -0
  591. package/client/src/dashboard/FileTableControls/FileColumnConfigEditor.tsx +251 -0
  592. package/client/src/dashboard/FileTableControls/FileStorageControls.tsx +294 -0
  593. package/client/src/dashboard/FileTableControls/FileStorageDelete.tsx +106 -0
  594. package/client/src/dashboard/FileTableControls/FileStorageReferencedTablesConfig.tsx +80 -0
  595. package/client/src/dashboard/FileTableControls/FileTableConfigControls.tsx +69 -0
  596. package/client/src/dashboard/FileTableControls/hooks/useFileTableConfigControls.ts +70 -0
  597. package/client/src/dashboard/FileTableControls/hooks/useSetFileStorage.ts +128 -0
  598. package/client/src/dashboard/JSONBColumnEditor.tsx +60 -0
  599. package/client/src/dashboard/LinkMenu.tsx +332 -0
  600. package/client/src/dashboard/Map/DeckGLFeatureEditor.tsx +645 -0
  601. package/client/src/dashboard/Map/DeckGLMap.css +45 -0
  602. package/client/src/dashboard/Map/DeckGLMap.tsx +576 -0
  603. package/client/src/dashboard/Map/DeckGLWrapped.ts +312 -0
  604. package/client/src/dashboard/Map/InMapControls.tsx +137 -0
  605. package/client/src/dashboard/Map/MVTLayerProps.ts +306 -0
  606. package/client/src/dashboard/Map/fitBounds.ts +63 -0
  607. package/client/src/dashboard/Map/mapDrawUtils.ts +129 -0
  608. package/client/src/dashboard/Map/mapUtils.ts +183 -0
  609. package/client/src/dashboard/RTComp.tsx +165 -0
  610. package/client/src/dashboard/RenderFilter.tsx +174 -0
  611. package/client/src/dashboard/SQLEditor/SQLCompletion/CommonMatchImports.ts +366 -0
  612. package/client/src/dashboard/SQLEditor/SQLCompletion/KEYWORDS.ts +448 -0
  613. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/MatchCreate.ts +294 -0
  614. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/MatchCreateView.ts +106 -0
  615. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/matchCreateIndex.ts +220 -0
  616. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/matchCreatePolicy.ts +108 -0
  617. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/matchCreateRule.tsx +99 -0
  618. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/matchCreateTable.ts +336 -0
  619. package/client/src/dashboard/SQLEditor/SQLCompletion/MacthCreate/matchCreateTrigger.ts +84 -0
  620. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchAlter/MatchAlter.tsx +258 -0
  621. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchAlter/matchAlterPolicy.ts +50 -0
  622. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchAlter/matchAlterTable.ts +325 -0
  623. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchAlter/matchCreateOrAlterUser.tsx +192 -0
  624. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchComment.ts +86 -0
  625. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchCopy.ts +367 -0
  626. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchDrop.ts +161 -0
  627. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchFirst.ts +471 -0
  628. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchGrant.ts +331 -0
  629. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchInsert.tsx +123 -0
  630. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchLast.ts +10 -0
  631. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchPublication.ts +126 -0
  632. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchReassign.ts +35 -0
  633. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchReindex.ts +36 -0
  634. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchSelect.ts +623 -0
  635. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchSet.ts +183 -0
  636. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchSubscription.ts +231 -0
  637. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchUpdate.ts +79 -0
  638. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchVacuum.ts +86 -0
  639. package/client/src/dashboard/SQLEditor/SQLCompletion/MatchWith.ts +222 -0
  640. package/client/src/dashboard/SQLEditor/SQLCompletion/MathDelete.ts +18 -0
  641. package/client/src/dashboard/SQLEditor/SQLCompletion/PSQL.ts +136 -0
  642. package/client/src/dashboard/SQLEditor/SQLCompletion/STARTING_KEYWORDS.ts +931 -0
  643. package/client/src/dashboard/SQLEditor/SQLCompletion/TableKWDs.ts +479 -0
  644. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/checkIfInsideDollarFunctionDefinition.ts +88 -0
  645. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/checkIfUnfinishedParenthesis.ts +74 -0
  646. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/getCodeBlock.ts +627 -0
  647. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/getQueryReturnType.ts +274 -0
  648. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/getTableExpressionReturnTypes.ts +243 -0
  649. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/getTabularExpressions.ts +428 -0
  650. package/client/src/dashboard/SQLEditor/SQLCompletion/completionUtils/getTokens.ts +239 -0
  651. package/client/src/dashboard/SQLEditor/SQLCompletion/getExpected.ts +176 -0
  652. package/client/src/dashboard/SQLEditor/SQLCompletion/getJoinSuggestions.ts +193 -0
  653. package/client/src/dashboard/SQLEditor/SQLCompletion/getMatch.ts +62 -0
  654. package/client/src/dashboard/SQLEditor/SQLCompletion/getPGObjects.ts +1270 -0
  655. package/client/src/dashboard/SQLEditor/SQLCompletion/getPrevTokensNoParantheses.ts +234 -0
  656. package/client/src/dashboard/SQLEditor/SQLCompletion/jsonbPathSuggest.ts +188 -0
  657. package/client/src/dashboard/SQLEditor/SQLCompletion/monacoSQLSetup/registerHover.ts +138 -0
  658. package/client/src/dashboard/SQLEditor/SQLCompletion/monacoSQLSetup/registerSuggestions.ts +549 -0
  659. package/client/src/dashboard/SQLEditor/SQLCompletion/suggestColumnLike.ts +251 -0
  660. package/client/src/dashboard/SQLEditor/SQLCompletion/suggestCondition.ts +320 -0
  661. package/client/src/dashboard/SQLEditor/SQLCompletion/suggestFuncArgs.ts +105 -0
  662. package/client/src/dashboard/SQLEditor/SQLCompletion/suggestTableLike.ts +104 -0
  663. package/client/src/dashboard/SQLEditor/SQLCompletion/suggestValue.ts +125 -0
  664. package/client/src/dashboard/SQLEditor/SQLCompletion/withKWDs.ts +507 -0
  665. package/client/src/dashboard/SQLEditor/SQLEditorSuggestions.ts +1883 -0
  666. package/client/src/dashboard/SQLEditor/SQLSmartEditor.tsx +124 -0
  667. package/client/src/dashboard/SQLEditor/SQL_SNIPPETS.ts +43 -0
  668. package/client/src/dashboard/SQLEditor/W_SQLEditor.css +15 -0
  669. package/client/src/dashboard/SQLEditor/W_SQLEditor.tsx +746 -0
  670. package/client/src/dashboard/SQLEditor/addSqlEditorFunctions.ts +74 -0
  671. package/client/src/dashboard/SQLEditor/defineCustomMonacoSQLTheme.ts +74 -0
  672. package/client/src/dashboard/SQLEditor/getFormattedSql.ts +154 -0
  673. package/client/src/dashboard/SQLEditor/registerFunctionSuggestions.ts +175 -0
  674. package/client/src/dashboard/SQLEditor/utils/scrollToLineIfNeeded.ts +17 -0
  675. package/client/src/dashboard/SQLEditor/utils/setMonacEditorError.ts +93 -0
  676. package/client/src/dashboard/SampleSchemas.tsx +50 -0
  677. package/client/src/dashboard/SchemaGraph/ERDSchema/ERDSchema.tsx +175 -0
  678. package/client/src/dashboard/SchemaGraph/ERDSchema/getInitialPlacement.ts +115 -0
  679. package/client/src/dashboard/SchemaGraph/ERDSchema/getInitialPlacementV2.ts +343 -0
  680. package/client/src/dashboard/SchemaGraph/ERDSchema/useCanvasPanZoom.ts +54 -0
  681. package/client/src/dashboard/SchemaGraph/ERDSchema/useDrawHiddenSvgForNativeTextSearch.ts +80 -0
  682. package/client/src/dashboard/SchemaGraph/ERDSchema/useDrawSchemaShapes.ts +242 -0
  683. package/client/src/dashboard/SchemaGraph/ERDSchema/useFetchSchemaForDiagram.ts +276 -0
  684. package/client/src/dashboard/SchemaGraph/ERDSchema/usePanShapes.ts +160 -0
  685. package/client/src/dashboard/SchemaGraph/ERDSchema/useSchemaShapes.ts +352 -0
  686. package/client/src/dashboard/SchemaGraph/SchemaGraph.tsx +55 -0
  687. package/client/src/dashboard/SchemaGraph/SchemaGraphControls.tsx +226 -0
  688. package/client/src/dashboard/SchemaGraph/types.ts +29 -0
  689. package/client/src/dashboard/SearchAll/SearchAll.tsx +77 -0
  690. package/client/src/dashboard/SearchAll/SearchAllContent.tsx +63 -0
  691. package/client/src/dashboard/SearchAll/SearchAllHeader.tsx +71 -0
  692. package/client/src/dashboard/SearchAll/SearchMatchRow.tsx +103 -0
  693. package/client/src/dashboard/SearchAll/hooks/useSearchAllState.ts +46 -0
  694. package/client/src/dashboard/SearchAll/hooks/useSearchListProps.tsx +178 -0
  695. package/client/src/dashboard/SearchAll/hooks/useSearchTables.tsx +163 -0
  696. package/client/src/dashboard/SearchAll/hooks/useTablesAndViewsSearchItems.ts +55 -0
  697. package/client/src/dashboard/SilverGrid/SilverGrid.tsx +531 -0
  698. package/client/src/dashboard/SilverGrid/SilverGridChild.tsx +403 -0
  699. package/client/src/dashboard/SilverGrid/SilverGridChildHeader.tsx +235 -0
  700. package/client/src/dashboard/SilverGrid/SilverGridResizer.tsx +129 -0
  701. package/client/src/dashboard/SilverGrid/TreeBuilder.ts +261 -0
  702. package/client/src/dashboard/SmartCard/SmartCard.tsx +218 -0
  703. package/client/src/dashboard/SmartCard/SmartCardActions.tsx +113 -0
  704. package/client/src/dashboard/SmartCard/SmartCardColumn.tsx +49 -0
  705. package/client/src/dashboard/SmartCard/getSelectForFieldConfigs.ts +44 -0
  706. package/client/src/dashboard/SmartCard/parseFieldConfigs.tsx +165 -0
  707. package/client/src/dashboard/SmartCard/useFieldConfigParser.ts +55 -0
  708. package/client/src/dashboard/SmartCard/useSmartCardColumns.ts +46 -0
  709. package/client/src/dashboard/SmartCardList/SmartCardList.tsx +291 -0
  710. package/client/src/dashboard/SmartCardList/SmartCardListHeaderControls.tsx +130 -0
  711. package/client/src/dashboard/SmartCardList/SmartCardListJoinedNewRecords.tsx +97 -0
  712. package/client/src/dashboard/SmartCardList/useSmartCardListState.ts +273 -0
  713. package/client/src/dashboard/SmartFilter/AddJoinFilter.tsx +97 -0
  714. package/client/src/dashboard/SmartFilter/MinimisedFilter.css +13 -0
  715. package/client/src/dashboard/SmartFilter/MinimisedFilter.tsx +208 -0
  716. package/client/src/dashboard/SmartFilter/SmartAddFilter.tsx +324 -0
  717. package/client/src/dashboard/SmartFilter/SmartFilter.tsx +182 -0
  718. package/client/src/dashboard/SmartFilter/SmartSearch/SmartSearch.css +4 -0
  719. package/client/src/dashboard/SmartFilter/SmartSearch/SmartSearch.tsx +230 -0
  720. package/client/src/dashboard/SmartFilter/SmartSearch/getSmartSearchRows.ts +277 -0
  721. package/client/src/dashboard/SmartFilter/SmartSearch/onSearchItems.tsx +146 -0
  722. package/client/src/dashboard/SmartFilter/SortByControl.tsx +81 -0
  723. package/client/src/dashboard/SmartFilter/smartFilterUtils.ts +97 -0
  724. package/client/src/dashboard/SmartFilterBar/SmartFilterBar.tsx +178 -0
  725. package/client/src/dashboard/SmartFilterBar/SmartFilterBarFilters.tsx +103 -0
  726. package/client/src/dashboard/SmartFilterBar/SmartFilterBarRightActions.tsx +212 -0
  727. package/client/src/dashboard/SmartFilterBar/SmartFilterBarSearch.tsx +115 -0
  728. package/client/src/dashboard/SmartFilterBar/SmartFilterBarSort.tsx +108 -0
  729. package/client/src/dashboard/SmartFilterBar/useSmartFilterBarState.ts +100 -0
  730. package/client/src/dashboard/SmartForm/ChipArrayEditor.tsx +169 -0
  731. package/client/src/dashboard/SmartForm/InsertButton.tsx +89 -0
  732. package/client/src/dashboard/SmartForm/JoinedRecords/JoinedRecords.tsx +155 -0
  733. package/client/src/dashboard/SmartForm/JoinedRecords/JoinedRecordsAddRow.tsx +182 -0
  734. package/client/src/dashboard/SmartForm/JoinedRecords/JoinedRecordsSection.tsx +168 -0
  735. package/client/src/dashboard/SmartForm/JoinedRecords/getJoinFilter.ts +31 -0
  736. package/client/src/dashboard/SmartForm/JoinedRecords/useJoinedRecordsSections.ts +246 -0
  737. package/client/src/dashboard/SmartForm/JoinedRecords/useJoinedSectionFieldConfigs.tsx +120 -0
  738. package/client/src/dashboard/SmartForm/SmartForm.tsx +368 -0
  739. package/client/src/dashboard/SmartForm/SmartFormField/RenderValue/RenderJson.tsx +72 -0
  740. package/client/src/dashboard/SmartForm/SmartFormField/RenderValue.tsx +294 -0
  741. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormField.tsx +349 -0
  742. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldFileSection.tsx +51 -0
  743. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldForeignKey.tsx +253 -0
  744. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldLinkedData.tsx +207 -0
  745. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldLinkedDataInsert/SmartFormFieldLinkedDataInsert.tsx +165 -0
  746. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldLinkedDataInsert/useSmartFormFieldLinkedDataInsert.tsx +77 -0
  747. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldLinkedDataSearch.tsx +91 -0
  748. package/client/src/dashboard/SmartForm/SmartFormField/SmartFormFieldRightButtons.tsx +110 -0
  749. package/client/src/dashboard/SmartForm/SmartFormField/ViewMoreSmartCardList.tsx +86 -0
  750. package/client/src/dashboard/SmartForm/SmartFormField/fetchColumnValueSuggestions.ts +92 -0
  751. package/client/src/dashboard/SmartForm/SmartFormField/fetchForeignKeyOptions.tsx +348 -0
  752. package/client/src/dashboard/SmartForm/SmartFormField/fieldUtils.ts +228 -0
  753. package/client/src/dashboard/SmartForm/SmartFormField/useNestedInsertDefaultData.ts +28 -0
  754. package/client/src/dashboard/SmartForm/SmartFormField/useSmartFormFieldAsJSON.tsx +87 -0
  755. package/client/src/dashboard/SmartForm/SmartFormField/useSmartFormFieldOnChange.ts +65 -0
  756. package/client/src/dashboard/SmartForm/SmartFormFieldList.tsx +190 -0
  757. package/client/src/dashboard/SmartForm/SmartFormFileSection.tsx +110 -0
  758. package/client/src/dashboard/SmartForm/SmartFormFooter/SmartFormFooterButtons.tsx +133 -0
  759. package/client/src/dashboard/SmartForm/SmartFormFooter/useSmartFormActions.ts +265 -0
  760. package/client/src/dashboard/SmartForm/SmartFormNewRowDataHandler.ts +168 -0
  761. package/client/src/dashboard/SmartForm/SmartFormPopup/SmartFormPopupWrapper.tsx +92 -0
  762. package/client/src/dashboard/SmartForm/SmartFormPopup/SmartFormPrevNext.tsx +33 -0
  763. package/client/src/dashboard/SmartForm/SmartFormPopup/SmartFormViewAsMarkdown.tsx +83 -0
  764. package/client/src/dashboard/SmartForm/SmartFormPopup/useSmartFormPrevNext.ts +20 -0
  765. package/client/src/dashboard/SmartForm/SmartFormPopup/useSmartFormSubTitle.ts +44 -0
  766. package/client/src/dashboard/SmartForm/SmartFormUpperFooter/SmartFormUpperFooter.tsx +198 -0
  767. package/client/src/dashboard/SmartForm/SmartFormUpperFooter/useActiveJoinedRecordsTab.ts +65 -0
  768. package/client/src/dashboard/SmartForm/constants.ts +1 -0
  769. package/client/src/dashboard/SmartForm/useNewRowDataHandler.ts +386 -0
  770. package/client/src/dashboard/SmartForm/useSmartForm.ts +67 -0
  771. package/client/src/dashboard/SmartForm/useSmartFormColumns.ts +127 -0
  772. package/client/src/dashboard/SmartForm/useSmartFormMode.ts +243 -0
  773. package/client/src/dashboard/SmartSelect.tsx +228 -0
  774. package/client/src/dashboard/SmartTable.tsx +383 -0
  775. package/client/src/dashboard/StatusMonitor/StatusMonitor.tsx +41 -0
  776. package/client/src/dashboard/StatusMonitor/StatusMonitorBlockedByPid.tsx +35 -0
  777. package/client/src/dashboard/StatusMonitor/StatusMonitorConnections.tsx +127 -0
  778. package/client/src/dashboard/StatusMonitor/StatusMonitorInfoHeader/StatusMonitorInfoHeader.tsx +122 -0
  779. package/client/src/dashboard/StatusMonitor/StatusMonitorInfoHeader/StatusMonitorInfoHeaderCpu.tsx +122 -0
  780. package/client/src/dashboard/StatusMonitor/StatusMonitorInfoHeader/StatusMonitorInfoHeaderMemory.tsx +21 -0
  781. package/client/src/dashboard/StatusMonitor/StatusMonitorProcList.tsx +292 -0
  782. package/client/src/dashboard/StatusMonitor/StatusMonitorProcListControlsHeader.tsx +85 -0
  783. package/client/src/dashboard/TableConfig/ProcessLogs.tsx +65 -0
  784. package/client/src/dashboard/TableConfig/TableConfig.tsx +88 -0
  785. package/client/src/dashboard/TimeSeries.tsx +29 -0
  786. package/client/src/dashboard/UserManager.tsx +54 -0
  787. package/client/src/dashboard/W_Barchart/W_Barchart.tsx +104 -0
  788. package/client/src/dashboard/W_Barchart/fetchSQLBarchartData.ts +7 -0
  789. package/client/src/dashboard/W_Barchart/useBarchartData.ts +176 -0
  790. package/client/src/dashboard/W_Map/OSM/OverpassQuery.tsx +21 -0
  791. package/client/src/dashboard/W_Map/OSM/fetchOSMCountryBoundary.ts +73 -0
  792. package/client/src/dashboard/W_Map/OSM/getOSMData.ts +240 -0
  793. package/client/src/dashboard/W_Map/OSM/osmToGeoJSON.ts +198 -0
  794. package/client/src/dashboard/W_Map/OSM/osmTypes.ts +1856 -0
  795. package/client/src/dashboard/W_Map/W_Map.tsx +747 -0
  796. package/client/src/dashboard/W_Map/W_MapMenu.tsx +188 -0
  797. package/client/src/dashboard/W_Map/controls/MapBasemapOptions.tsx +268 -0
  798. package/client/src/dashboard/W_Map/controls/MapInfoSection.tsx +95 -0
  799. package/client/src/dashboard/W_Map/controls/MapOSMQuery.tsx +174 -0
  800. package/client/src/dashboard/W_Map/controls/MapOpacityMenu.tsx +60 -0
  801. package/client/src/dashboard/W_Map/fetchData/fetchMapLayerData.ts +401 -0
  802. package/client/src/dashboard/W_Map/fetchData/getMapData.ts +161 -0
  803. package/client/src/dashboard/W_Map/fetchData/getMapDataExtent.ts +86 -0
  804. package/client/src/dashboard/W_Map/fetchData/getMapLayerQueries.ts +232 -0
  805. package/client/src/dashboard/W_Map/getMapFeatureStyle.ts +160 -0
  806. package/client/src/dashboard/W_Map/onMapHover.ts +118 -0
  807. package/client/src/dashboard/W_Method/FunctionLabel.tsx +24 -0
  808. package/client/src/dashboard/W_Method/NewMethod.tsx +108 -0
  809. package/client/src/dashboard/W_Method/PublishedMethods.tsx +218 -0
  810. package/client/src/dashboard/W_Method/W_Method.tsx +48 -0
  811. package/client/src/dashboard/W_Method/W_MethodControls.tsx +338 -0
  812. package/client/src/dashboard/W_Method/W_MethodMenu.tsx +162 -0
  813. package/client/src/dashboard/W_QuickMenu.tsx +228 -0
  814. package/client/src/dashboard/W_SQL/CSVRender.tsx +18 -0
  815. package/client/src/dashboard/W_SQL/CopyResultBtn.tsx +246 -0
  816. package/client/src/dashboard/W_SQL/MonacoLanguageRegister.ts +701 -0
  817. package/client/src/dashboard/W_SQL/SQLHotkeys.tsx +23 -0
  818. package/client/src/dashboard/W_SQL/TestSQL.ts +52 -0
  819. package/client/src/dashboard/W_SQL/W_SQL.tsx +679 -0
  820. package/client/src/dashboard/W_SQL/W_SQLBottomBar/W_SQLBottomBar.tsx +484 -0
  821. package/client/src/dashboard/W_SQL/W_SQLBottomBar/W_SQLBottomBarProcStats.tsx +67 -0
  822. package/client/src/dashboard/W_SQL/W_SQLMenu.tsx +403 -0
  823. package/client/src/dashboard/W_SQL/W_SQLResults.tsx +161 -0
  824. package/client/src/dashboard/W_SQL/customRenderers.tsx +126 -0
  825. package/client/src/dashboard/W_SQL/demoScripts/createTables.ts +262 -0
  826. package/client/src/dashboard/W_SQL/demoScripts/mainTestScripts.ts +269 -0
  827. package/client/src/dashboard/W_SQL/demoScripts/testBugs.ts +596 -0
  828. package/client/src/dashboard/W_SQL/demoScripts/testMiscAndBugs.ts +61 -0
  829. package/client/src/dashboard/W_SQL/demoScripts/testSqlCharts.ts +117 -0
  830. package/client/src/dashboard/W_SQL/getChartableSQL.ts +169 -0
  831. package/client/src/dashboard/W_SQL/getDemoUtils.ts +260 -0
  832. package/client/src/dashboard/W_SQL/getSQLResultTableColumns.ts +56 -0
  833. package/client/src/dashboard/W_SQL/monacoEditorTypes.ts +13 -0
  834. package/client/src/dashboard/W_SQL/parseExplainResult.ts +99 -0
  835. package/client/src/dashboard/W_SQL/parseSQLError.ts +55 -0
  836. package/client/src/dashboard/W_SQL/parseSqlResultCols.ts +96 -0
  837. package/client/src/dashboard/W_SQL/runSQL/getQueryTotalRowCount.ts +38 -0
  838. package/client/src/dashboard/W_SQL/runSQL/runSQL.ts +432 -0
  839. package/client/src/dashboard/W_SQL/runSQLErrorHints.ts +150 -0
  840. package/client/src/dashboard/W_Table/CardView/CardItem/CardItemBody.tsx +151 -0
  841. package/client/src/dashboard/W_Table/CardView/CardItem/CardItemHeader.tsx +150 -0
  842. package/client/src/dashboard/W_Table/CardView/CardItem/CardViewRow.tsx +160 -0
  843. package/client/src/dashboard/W_Table/CardView/CardView.tsx +87 -0
  844. package/client/src/dashboard/W_Table/CardView/CardViewColumn.tsx +82 -0
  845. package/client/src/dashboard/W_Table/CardView/CardViewKanban.tsx +87 -0
  846. package/client/src/dashboard/W_Table/CardView/DragHeader.tsx +46 -0
  847. package/client/src/dashboard/W_Table/CardView/constants.ts +1 -0
  848. package/client/src/dashboard/W_Table/CardView/useCardViewState.ts +50 -0
  849. package/client/src/dashboard/W_Table/CardView/useDragHeader.ts +280 -0
  850. package/client/src/dashboard/W_Table/ColumnMenu/AddColumnMenu.tsx +193 -0
  851. package/client/src/dashboard/W_Table/ColumnMenu/AddComputedColumn/AddComputedColMenu.tsx +650 -0
  852. package/client/src/dashboard/W_Table/ColumnMenu/AddComputedColumn/FunctionColumnList.tsx +75 -0
  853. package/client/src/dashboard/W_Table/ColumnMenu/AddComputedColumn/QuickAddComputedColumn.tsx +129 -0
  854. package/client/src/dashboard/W_Table/ColumnMenu/AddComputedColumn/useAddComputedColumn.ts +175 -0
  855. package/client/src/dashboard/W_Table/ColumnMenu/AlterColumn/AlterColumn.tsx +421 -0
  856. package/client/src/dashboard/W_Table/ColumnMenu/AlterColumn/AlterColumnFileOptions.tsx +84 -0
  857. package/client/src/dashboard/W_Table/ColumnMenu/AlterColumn/ColumnEditor.tsx +229 -0
  858. package/client/src/dashboard/W_Table/ColumnMenu/AlterColumn/CreateColumn.tsx +150 -0
  859. package/client/src/dashboard/W_Table/ColumnMenu/AlterColumn/ReferenceEditor.tsx +243 -0
  860. package/client/src/dashboard/W_Table/ColumnMenu/AlterColumn/alterColumnUtilts.ts +53 -0
  861. package/client/src/dashboard/W_Table/ColumnMenu/ColorPicker.tsx +251 -0
  862. package/client/src/dashboard/W_Table/ColumnMenu/ColumnDisplayFormat/ChipStylePalette.tsx +127 -0
  863. package/client/src/dashboard/W_Table/ColumnMenu/ColumnDisplayFormat/ColumnDisplayFormat.tsx +116 -0
  864. package/client/src/dashboard/W_Table/ColumnMenu/ColumnDisplayFormat/ConditionalCellIconStyleControls.tsx +140 -0
  865. package/client/src/dashboard/W_Table/ColumnMenu/ColumnDisplayFormat/ConditionalCellStyleControls.tsx +235 -0
  866. package/client/src/dashboard/W_Table/ColumnMenu/ColumnDisplayFormat/NestedColumnRender.tsx +172 -0
  867. package/client/src/dashboard/W_Table/ColumnMenu/ColumnDisplayFormat/columnFormatUtils.tsx +330 -0
  868. package/client/src/dashboard/W_Table/ColumnMenu/ColumnList.tsx +291 -0
  869. package/client/src/dashboard/W_Table/ColumnMenu/ColumnMenu.tsx +537 -0
  870. package/client/src/dashboard/W_Table/ColumnMenu/ColumnQuickStats/ColumnQuickStats.tsx +176 -0
  871. package/client/src/dashboard/W_Table/ColumnMenu/ColumnQuickStats/useColumnQuickStats.ts +169 -0
  872. package/client/src/dashboard/W_Table/ColumnMenu/ColumnSelect/ColumnSelect.tsx +54 -0
  873. package/client/src/dashboard/W_Table/ColumnMenu/ColumnSelect/getColumnListItem.tsx +97 -0
  874. package/client/src/dashboard/W_Table/ColumnMenu/ColumnSortMenu.tsx +146 -0
  875. package/client/src/dashboard/W_Table/ColumnMenu/ColumnStyleControls/ColumnStyleControls.tsx +258 -0
  876. package/client/src/dashboard/W_Table/ColumnMenu/ColumnStyleControls/getValueColors.ts +101 -0
  877. package/client/src/dashboard/W_Table/ColumnMenu/ColumnsMenu.tsx +178 -0
  878. package/client/src/dashboard/W_Table/ColumnMenu/FunctionSelector/FunctionExtraArguments.tsx +140 -0
  879. package/client/src/dashboard/W_Table/ColumnMenu/FunctionSelector/FunctionSelector.tsx +89 -0
  880. package/client/src/dashboard/W_Table/ColumnMenu/FunctionSelector/functions.ts +438 -0
  881. package/client/src/dashboard/W_Table/ColumnMenu/JoinPathSelectorV2.tsx +212 -0
  882. package/client/src/dashboard/W_Table/ColumnMenu/LinkedColumn/LinkedColumn.tsx +295 -0
  883. package/client/src/dashboard/W_Table/ColumnMenu/LinkedColumn/LinkedColumnFooter.tsx +94 -0
  884. package/client/src/dashboard/W_Table/ColumnMenu/LinkedColumn/LinkedColumnSelect.tsx +160 -0
  885. package/client/src/dashboard/W_Table/ColumnMenu/NestedTimechartControls.tsx +167 -0
  886. package/client/src/dashboard/W_Table/ColumnMenu/SummariseColumns.tsx +126 -0
  887. package/client/src/dashboard/W_Table/ColumnMenu/UpdateColumnGlobalConfig.tsx +69 -0
  888. package/client/src/dashboard/W_Table/ColumnMenu/getNestedColumnTable.ts +83 -0
  889. package/client/src/dashboard/W_Table/ColumnMenu/rgba2hex.ts +36 -0
  890. package/client/src/dashboard/W_Table/JoinPathSelector/JoinPathItem.tsx +133 -0
  891. package/client/src/dashboard/W_Table/JoinPathSelector/JoinPathSelector.tsx +100 -0
  892. package/client/src/dashboard/W_Table/JoinPathSelector/getJoinTree.ts +79 -0
  893. package/client/src/dashboard/W_Table/NodeCountChecker.tsx +58 -0
  894. package/client/src/dashboard/W_Table/ProstglesTable.css +64 -0
  895. package/client/src/dashboard/W_Table/QuickFilterGroupsControl.tsx +86 -0
  896. package/client/src/dashboard/W_Table/RowCard.tsx +102 -0
  897. package/client/src/dashboard/W_Table/TableMenu/AddChartMenu.tsx +288 -0
  898. package/client/src/dashboard/W_Table/TableMenu/AutoRefreshMenu.tsx +118 -0
  899. package/client/src/dashboard/W_Table/TableMenu/TableDisplayOptionsJSON.tsx +71 -0
  900. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu.tsx +365 -0
  901. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_AccessRules.tsx +127 -0
  902. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_Constraints.tsx +140 -0
  903. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_CurrentQuery.tsx +82 -0
  904. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_DisplayOptions.tsx +266 -0
  905. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_Indexes.tsx +179 -0
  906. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_Policies.tsx +197 -0
  907. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_TableInfo.tsx +184 -0
  908. package/client/src/dashboard/W_Table/TableMenu/W_TableMenu_Triggers.tsx +199 -0
  909. package/client/src/dashboard/W_Table/TableMenu/getAndFixWColumnsConfig.tsx +116 -0
  910. package/client/src/dashboard/W_Table/TableMenu/getChartCols.ts +153 -0
  911. package/client/src/dashboard/W_Table/TableMenu/getTableMeta.ts +205 -0
  912. package/client/src/dashboard/W_Table/TooManyColumnsWarning.tsx +72 -0
  913. package/client/src/dashboard/W_Table/W_Table.tsx +772 -0
  914. package/client/src/dashboard/W_Table/W_Table_Content.tsx +51 -0
  915. package/client/src/dashboard/W_Table/colorBlend.ts +75 -0
  916. package/client/src/dashboard/W_Table/getTableData/getTableData.ts +291 -0
  917. package/client/src/dashboard/W_Table/getTableData/getTableFilter.ts +66 -0
  918. package/client/src/dashboard/W_Table/tableUtils/StyledTableColumn.tsx +322 -0
  919. package/client/src/dashboard/W_Table/tableUtils/getColWInfo.ts +48 -0
  920. package/client/src/dashboard/W_Table/tableUtils/getColWidth.ts +160 -0
  921. package/client/src/dashboard/W_Table/tableUtils/getEditColumn.tsx +143 -0
  922. package/client/src/dashboard/W_Table/tableUtils/getFullColumnConfig.ts +43 -0
  923. package/client/src/dashboard/W_Table/tableUtils/getJoinPaths.ts +89 -0
  924. package/client/src/dashboard/W_Table/tableUtils/getRowFilter.ts +114 -0
  925. package/client/src/dashboard/W_Table/tableUtils/getTableCols.tsx +258 -0
  926. package/client/src/dashboard/W_Table/tableUtils/getTableDataRequestSignature.ts +32 -0
  927. package/client/src/dashboard/W_Table/tableUtils/getTableSelect.ts +235 -0
  928. package/client/src/dashboard/W_Table/tableUtils/kFormatter.ts +12 -0
  929. package/client/src/dashboard/W_Table/tableUtils/onRenderColumn.tsx +107 -0
  930. package/client/src/dashboard/W_Table/tableUtils/prepareColsForRender.ts +69 -0
  931. package/client/src/dashboard/W_Table/tableUtils/tableUtils.ts +298 -0
  932. package/client/src/dashboard/W_TimeChart/AddTimeChartFilter.tsx +347 -0
  933. package/client/src/dashboard/W_TimeChart/W_TimeChart.tsx +405 -0
  934. package/client/src/dashboard/W_TimeChart/W_TimeChartHeaderControls.tsx +140 -0
  935. package/client/src/dashboard/W_TimeChart/W_TimeChartLayerLegend.tsx +99 -0
  936. package/client/src/dashboard/W_TimeChart/W_TimeChartMenu.tsx +228 -0
  937. package/client/src/dashboard/W_TimeChart/fetchData/constants.ts +5 -0
  938. package/client/src/dashboard/W_TimeChart/fetchData/fetchAndSetTimechartLayerData.ts +141 -0
  939. package/client/src/dashboard/W_TimeChart/fetchData/fetchTimechartLayer.ts +291 -0
  940. package/client/src/dashboard/W_TimeChart/fetchData/getTimeChartData.ts +163 -0
  941. package/client/src/dashboard/W_TimeChart/fetchData/getTimeChartLayers.ts +137 -0
  942. package/client/src/dashboard/W_TimeChart/fetchData/getTimeChartLayersWithBins.ts +296 -0
  943. package/client/src/dashboard/W_TimeChart/fetchData/getTimeChartSelectParams.ts +41 -0
  944. package/client/src/dashboard/W_TimeChart/fetchData/getTimeLayerDataSignature.ts +22 -0
  945. package/client/src/dashboard/W_TimeChart/fetchData/getTimechartExtentFilter.ts +48 -0
  946. package/client/src/dashboard/Window/ChildWindowLayout.tsx +149 -0
  947. package/client/src/dashboard/Window/Window.tsx +322 -0
  948. package/client/src/dashboard/WindowControls/AddChartLayer.tsx +142 -0
  949. package/client/src/dashboard/WindowControls/ColorByLegend/ColorByLegend.tsx +256 -0
  950. package/client/src/dashboard/WindowControls/ColorByLegend/getGroupByValueColor.ts +50 -0
  951. package/client/src/dashboard/WindowControls/DataLayerManager/DataLayer.tsx +182 -0
  952. package/client/src/dashboard/WindowControls/DataLayerManager/DataLayerDataSource.tsx +243 -0
  953. package/client/src/dashboard/WindowControls/DataLayerManager/DataLayerManager.tsx +157 -0
  954. package/client/src/dashboard/WindowControls/DataLayerManager/LayerColorPicker.tsx +56 -0
  955. package/client/src/dashboard/WindowControls/DataLayerManager/MapLayerStyling.tsx +192 -0
  956. package/client/src/dashboard/WindowControls/DataLayerManager/useSortedLayerQueries.ts +34 -0
  957. package/client/src/dashboard/WindowControls/OSMLayerOptions.tsx +62 -0
  958. package/client/src/dashboard/WindowControls/SQLChartLayerEditor.tsx +38 -0
  959. package/client/src/dashboard/WindowControls/TimeChartLayerOptions.tsx +336 -0
  960. package/client/src/dashboard/WorkspaceMenu/WorkspaceAddBtn.tsx +104 -0
  961. package/client/src/dashboard/WorkspaceMenu/WorkspaceDeleteBtn.tsx +87 -0
  962. package/client/src/dashboard/WorkspaceMenu/WorkspaceMenu.css +13 -0
  963. package/client/src/dashboard/WorkspaceMenu/WorkspaceMenu.tsx +124 -0
  964. package/client/src/dashboard/WorkspaceMenu/WorkspaceMenuDropDown.tsx +178 -0
  965. package/client/src/dashboard/WorkspaceMenu/WorkspaceSettings.tsx +99 -0
  966. package/client/src/dashboard/WorkspaceMenu/useWorkspaces.ts +78 -0
  967. package/client/src/dashboard/getCrossFilters.ts +251 -0
  968. package/client/src/dashboard/localSettings.ts +94 -0
  969. package/client/src/dashboard/setPan.ts +358 -0
  970. package/client/src/dashboard/shortestPath.ts +137 -0
  971. package/client/src/demo/AppVideoDemo.tsx +132 -0
  972. package/client/src/demo/MousePointer.tsx +39 -0
  973. package/client/src/demo/demoUtils.ts +214 -0
  974. package/client/src/demo/recordDemoUtils.ts +87 -0
  975. package/client/src/demo/scripts/AIAssistantDemo.ts +60 -0
  976. package/client/src/demo/scripts/accessControlDemo.ts +44 -0
  977. package/client/src/demo/scripts/backupDemo.ts +50 -0
  978. package/client/src/demo/scripts/dashboardDemo.ts +215 -0
  979. package/client/src/demo/scripts/fileDemo.ts +24 -0
  980. package/client/src/demo/scripts/schemaDiagramDemo.ts +13 -0
  981. package/client/src/demo/scripts/sqlVideoDemo.ts +539 -0
  982. package/client/src/demo/scripts/videoDemoAccessControlScripts.ts +245 -0
  983. package/client/src/exports.ts +15 -0
  984. package/client/src/hooks/createStore.ts +24 -0
  985. package/client/src/hooks/useDebouncedCallback.ts +27 -0
  986. package/client/src/hooks/useThrottledCallback.ts +41 -0
  987. package/client/src/hooks/useTypedSearchParams.ts +81 -0
  988. package/client/src/i18n/LanguageSelector.tsx +33 -0
  989. package/client/src/i18n/i18nUtils.ts +187 -0
  990. package/client/src/i18n/translations/de.json +453 -0
  991. package/client/src/i18n/translations/es.json +425 -0
  992. package/client/src/i18n/translations/fr.json +425 -0
  993. package/client/src/i18n/translations/hi.json +431 -0
  994. package/client/src/i18n/translations/ru.json +431 -0
  995. package/client/src/i18n/translations/translations.ts +477 -0
  996. package/client/src/i18n/translations/zh.json +423 -0
  997. package/client/src/index.css +57 -0
  998. package/client/src/index.html.ejs +37 -0
  999. package/client/src/index.tsx +17 -0
  1000. package/client/src/pages/Account/Account.tsx +150 -0
  1001. package/client/src/pages/Account/ChangePassword.tsx +96 -0
  1002. package/client/src/pages/Account/Sessions.tsx +248 -0
  1003. package/client/src/pages/Account/Setup2FA.tsx +244 -0
  1004. package/client/src/pages/AccountMenu.tsx +146 -0
  1005. package/client/src/pages/Alerts.tsx +182 -0
  1006. package/client/src/pages/AppContextProvider.tsx +26 -0
  1007. package/client/src/pages/ComponentList.tsx +108 -0
  1008. package/client/src/pages/ElectronSetup/ElectronSetup.tsx +122 -0
  1009. package/client/src/pages/ElectronSetup/ElectronSetupStateDB.tsx +141 -0
  1010. package/client/src/pages/ElectronSetup/useElectronSetup.ts +147 -0
  1011. package/client/src/pages/Login/AuthNotifPopup.tsx +37 -0
  1012. package/client/src/pages/Login/Login.tsx +133 -0
  1013. package/client/src/pages/Login/LoginTotpForm.tsx +72 -0
  1014. package/client/src/pages/Login/LoginWithProviders.tsx +62 -0
  1015. package/client/src/pages/Login/SocialIcons.css +4 -0
  1016. package/client/src/pages/Login/SocialIcons.tsx +85 -0
  1017. package/client/src/pages/NewConnection/NewConnectionForm.tsx +572 -0
  1018. package/client/src/pages/NewConnection/NewConnectionFormFields.tsx +314 -0
  1019. package/client/src/pages/NewConnection/NewConnectionFormOptions.tsx +194 -0
  1020. package/client/src/pages/NewConnection/SchemaFilter.tsx +87 -0
  1021. package/client/src/pages/NewConnection/newConnectionUtils.ts +50 -0
  1022. package/client/src/pages/NonHTTPSWarning.tsx +51 -0
  1023. package/client/src/pages/NotFound.tsx +22 -0
  1024. package/client/src/pages/ProjectConnection/PrglContextProvider.tsx +47 -0
  1025. package/client/src/pages/ProjectConnection/ProjectConnection.tsx +110 -0
  1026. package/client/src/pages/ProjectConnection/ProjectConnectionError.tsx +76 -0
  1027. package/client/src/pages/ProjectConnection/useProjectDb.ts +253 -0
  1028. package/client/src/pages/ProjectLogs.tsx +227 -0
  1029. package/client/src/pages/ServerSettings/AuthProvidersSetup/AuthProvidersSetup.tsx +199 -0
  1030. package/client/src/pages/ServerSettings/AuthProvidersSetup/useProviderProps.ts +39 -0
  1031. package/client/src/pages/ServerSettings/EmailAuthSetup.tsx +209 -0
  1032. package/client/src/pages/ServerSettings/EmailAuthSetupIngredients/EmailSMTPAndTemplateSetup.tsx +158 -0
  1033. package/client/src/pages/ServerSettings/EmailAuthSetupIngredients/EmailSMTPSetup.tsx +128 -0
  1034. package/client/src/pages/ServerSettings/EmailAuthSetupIngredients/EmailTemplateSetup.tsx +111 -0
  1035. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/McpServerOAuthConfig.tsx +41 -0
  1036. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/McpServerOAuthConfigActions.tsx +187 -0
  1037. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/McpServerOAuthConfigAuthorizeUrlBtn.tsx +55 -0
  1038. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/McpServerOAuthConfigCredentials.tsx +81 -0
  1039. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/McpServerOAuthConfigTopControls.tsx +120 -0
  1040. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/WebMcpConfig.tsx +162 -0
  1041. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/CustomConfigComponents/useMcpServerOAuthConfigState.ts +132 -0
  1042. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/MCPServerConfigButton.tsx +121 -0
  1043. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/MCPServerConfigEditor.tsx +206 -0
  1044. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/MCPServerConfigProvider.tsx +67 -0
  1045. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/useMCPServerConfigState.tsx +107 -0
  1046. package/client/src/pages/ServerSettings/MCPServers/MCPServerConfig/useMCPServerEnable.ts +131 -0
  1047. package/client/src/pages/ServerSettings/MCPServers/MCPServerFooterActions/MCPServerFooterActions.tsx +108 -0
  1048. package/client/src/pages/ServerSettings/MCPServers/MCPServerFooterActions/MCPServerLogs.tsx +46 -0
  1049. package/client/src/pages/ServerSettings/MCPServers/MCPServerFooterActions/MCPServersInstall.tsx +81 -0
  1050. package/client/src/pages/ServerSettings/MCPServers/MCPServerHeaderCheckbox.tsx +120 -0
  1051. package/client/src/pages/ServerSettings/MCPServers/MCPServerTools/MCPServerTools.tsx +95 -0
  1052. package/client/src/pages/ServerSettings/MCPServers/MCPServerTools/MCPServerToolsGroupToggle.tsx +96 -0
  1053. package/client/src/pages/ServerSettings/MCPServers/MCPServerTools/useMcpServerIcons.ts +87 -0
  1054. package/client/src/pages/ServerSettings/MCPServers/MCPServerTools/useMcpToolsSelectOptions.tsx +33 -0
  1055. package/client/src/pages/ServerSettings/MCPServers/MCPServers.tsx +140 -0
  1056. package/client/src/pages/ServerSettings/MCPServers/MCPServersHeader.tsx +47 -0
  1057. package/client/src/pages/ServerSettings/MCPServers/MCPServersToolbar/AddMCPServer.tsx +196 -0
  1058. package/client/src/pages/ServerSettings/MCPServers/MCPServersToolbar/MCPServersToolbar.tsx +77 -0
  1059. package/client/src/pages/ServerSettings/MCPServers/MCPServersToolbar/useAddMCPServer.ts +253 -0
  1060. package/client/src/pages/ServerSettings/MCPServers/useMCPChatAllowedTools.ts +25 -0
  1061. package/client/src/pages/ServerSettings/MCPServers/useMCPServersListProps.tsx +118 -0
  1062. package/client/src/pages/ServerSettings/OAuthProviderSetup.tsx +258 -0
  1063. package/client/src/pages/ServerSettings/SecuritySettings.tsx +154 -0
  1064. package/client/src/pages/ServerSettings/ServerSettings.tsx +151 -0
  1065. package/client/src/pages/ServerSettings/Services.tsx +231 -0
  1066. package/client/src/pages/ServerSettings/useEditableData.ts +55 -0
  1067. package/client/src/pages/TopControls.tsx +182 -0
  1068. package/client/src/pages/projectUtils.ts +0 -0
  1069. package/client/src/theme/ThemeSelector.tsx +36 -0
  1070. package/client/src/theme/useAppTheme.ts +47 -0
  1071. package/client/src/theme/useSystemTheme.ts +23 -0
  1072. package/client/src/useAppState/PrglCoreContextProvider.tsx +76 -0
  1073. package/client/src/useAppState/useAppState.ts +92 -0
  1074. package/client/src/useAppState/useDBSClient.ts +104 -0
  1075. package/client/src/useAppState/useServerState.ts +62 -0
  1076. package/client/src/useAppState/useUserData.ts +1 -0
  1077. package/client/src/utils/colorUtils.ts +48 -0
  1078. package/client/src/utils/hashCode.ts +52 -0
  1079. package/client/src/utils/utils.ts +207 -0
  1080. package/client/static/favicon-32x32.png +0 -0
  1081. package/client/static/logos/anthropic.svg +3 -0
  1082. package/client/static/logos/google.svg +25 -0
  1083. package/client/static/logos/ollama.svg +7 -0
  1084. package/client/static/logos/openai.svg +2 -0
  1085. package/client/static/logos/openrouter.svg +1 -0
  1086. package/client/static/mcp-oauth-close.js +5 -0
  1087. package/client/static/prostgles-logo.svg +39 -0
  1088. package/client/static/util.css +2024 -0
  1089. package/client/static/v2.svg +25 -0
  1090. package/client/tsconfig.eslint.json +5 -0
  1091. package/client/tsconfig.json +40 -0
  1092. package/client/tslint.json +5 -0
  1093. package/common/DBGeneratedSchema.ts +953 -0
  1094. package/common/DashboardTypes.ts +533 -0
  1095. package/common/KeyObjMap.ts +100 -0
  1096. package/common/OAuthUtils.ts +285 -0
  1097. package/common/authTypesAndConstants.ts +1 -0
  1098. package/common/columnDisplayFormat.schema.ts +211 -0
  1099. package/common/electronInitTypes.ts +56 -0
  1100. package/common/filterUtils.ts +491 -0
  1101. package/common/getJsonSchemaAsTs.ts +335 -0
  1102. package/common/llmUtils.ts +133 -0
  1103. package/common/managedTableSchema.ts +38 -0
  1104. package/common/mcp/databaseAccessSchema.ts +70 -0
  1105. package/common/mcp/db.mcp.schema.ts +280 -0
  1106. package/common/mcp/documents.mcp.schema.ts +45 -0
  1107. package/common/mcp/documentsServiceInputSchema.ts +129 -0
  1108. package/common/mcp/runCodeInSandboxSchema.ts +85 -0
  1109. package/common/mcp/startAgenticWorkflowSchema.ts +180 -0
  1110. package/common/mcp/tableOptionsJsonbSchema.ts +151 -0
  1111. package/common/mcp/tablePermissionsSchema.ts +101 -0
  1112. package/common/mcp/ui.mcp.schema.ts +496 -0
  1113. package/common/mcp/userInputSchema.ts +87 -0
  1114. package/common/mcp/web.mcp.schema.ts +245 -0
  1115. package/common/mcp/webdev.mcp.schema.ts +138 -0
  1116. package/common/mcpUtils.ts +75 -0
  1117. package/common/prostglesApiTypes.ts +551 -0
  1118. package/common/prostglesMcp.ts +35 -0
  1119. package/common/psql_queries.json +657 -0
  1120. package/common/publishUtils.ts +600 -0
  1121. package/common/tsconfig.json +22 -0
  1122. package/common/utils.ts +525 -0
  1123. package/docker-compose.yml +99 -0
  1124. package/docs/01_Overview.md +25 -0
  1125. package/docs/02_Installation_(Docker).md +37 -0
  1126. package/docs/03_Installation_(Desktop_Version).md +27 -0
  1127. package/docs/04_Navigation_bar.md +37 -0
  1128. package/docs/05_Connections.md +108 -0
  1129. package/docs/06_Connection_dashboard.md +58 -0
  1130. package/docs/07_Import_file.md +15 -0
  1131. package/docs/08_Agentic_workflows.md +27 -0
  1132. package/docs/09_Schema_diagram.md +63 -0
  1133. package/docs/10_SQL_editor.md +69 -0
  1134. package/docs/11_Table_view.md +188 -0
  1135. package/docs/12_Map_view.md +56 -0
  1136. package/docs/13_Timechart_view.md +49 -0
  1137. package/docs/14_AI_Assistant.md +64 -0
  1138. package/docs/15_Connection_configuration.md +20 -0
  1139. package/docs/16_Access_control.md +12 -0
  1140. package/docs/17_File_storage.md +8 -0
  1141. package/docs/18_Backup_and_Restore.md +22 -0
  1142. package/docs/19_API.md +20 -0
  1143. package/docs/20_Server_Settings.md +28 -0
  1144. package/docs/21_Account.md +21 -0
  1145. package/docs/22_Command_Palette.md +10 -0
  1146. package/docs/screenshots/table_timechart.dark.svgif.svg +375 -0
  1147. package/docs/screenshots/table_timechart.svgif.svg +1102 -0
  1148. package/docs/screenshots/timechart.dark.svgif.svg +221 -0
  1149. package/docs/screenshots/timechart.svgif.svg +846 -0
  1150. package/e2e/icon512.png +0 -0
  1151. package/e2e/package-lock.json +401 -0
  1152. package/e2e/package.json +31 -0
  1153. package/e2e/playwright.config.js +65 -0
  1154. package/e2e/playwright.config.ts +32 -0
  1155. package/e2e/test-local.sh +5 -0
  1156. package/e2e/tests/Testing.ts +724 -0
  1157. package/e2e/tests/command_palette.spec.ts +114 -0
  1158. package/e2e/tests/configTest/.env.example +10 -0
  1159. package/e2e/tests/configTest/constants.ts +13 -0
  1160. package/e2e/tests/configTest/functions.ts +14 -0
  1161. package/e2e/tests/configTest/index.ts +84 -0
  1162. package/e2e/tests/configTest/package.json +17 -0
  1163. package/e2e/tests/configTest/tsconfig.json +13 -0
  1164. package/e2e/tests/config_deploy.spec.ts +386 -0
  1165. package/e2e/tests/create_docs.spec.ts +231 -0
  1166. package/e2e/tests/create_load_test_users.spec.ts +47 -0
  1167. package/e2e/tests/demo_video.spec.ts +139 -0
  1168. package/e2e/tests/demo_video_setup.spec.ts +118 -0
  1169. package/e2e/tests/fileBrowserGoToPath.ts +53 -0
  1170. package/e2e/tests/load_test.spec.ts +53 -0
  1171. package/e2e/tests/main.spec.ts +3820 -0
  1172. package/e2e/tests/mockSMTPServer.ts +81 -0
  1173. package/e2e/tests/saveDocs.ts +55 -0
  1174. package/e2e/tests/svgScreenshots/SVG_SCREENSHOT_DETAILS.ts +132 -0
  1175. package/e2e/tests/svgScreenshots/account.svgif.ts +14 -0
  1176. package/e2e/tests/svgScreenshots/aiAssistant.svgif.ts +235 -0
  1177. package/e2e/tests/svgScreenshots/aiAssistantAgenticWorkflow.svgif.ts +339 -0
  1178. package/e2e/tests/svgScreenshots/aiAssistantAgenticWorkflowGovApi.svgif.ts +116 -0
  1179. package/e2e/tests/svgScreenshots/backupAndRestore.svgif.ts +143 -0
  1180. package/e2e/tests/svgScreenshots/commandPalette.svgif.ts +69 -0
  1181. package/e2e/tests/svgScreenshots/dashboard.svgif.ts +271 -0
  1182. package/e2e/tests/svgScreenshots/electronSetup.svgif.ts +32 -0
  1183. package/e2e/tests/svgScreenshots/fileImporter.svgif.ts +39 -0
  1184. package/e2e/tests/svgScreenshots/getOverviewSvgifSpecs.svgif.ts +288 -0
  1185. package/e2e/tests/svgScreenshots/map.svgif.ts +50 -0
  1186. package/e2e/tests/svgScreenshots/navbar.svgif.ts +22 -0
  1187. package/e2e/tests/svgScreenshots/newConnection.svgif.ts +26 -0
  1188. package/e2e/tests/svgScreenshots/schemaDiagram.svgif.ts +82 -0
  1189. package/e2e/tests/svgScreenshots/sqlEditor.svgif.ts +348 -0
  1190. package/e2e/tests/svgScreenshots/table.svgif.ts +167 -0
  1191. package/e2e/tests/svgScreenshots/tableTimechart.svgif.ts +507 -0
  1192. package/e2e/tests/svgScreenshots/timechart.svgif.ts +138 -0
  1193. package/e2e/tests/svgScreenshots/utils/constants.ts +23 -0
  1194. package/e2e/tests/svgScreenshots/utils/dedent.ts +9 -0
  1195. package/e2e/tests/svgScreenshots/utils/getFilesFromDir.ts +30 -0
  1196. package/e2e/tests/svgScreenshots/utils/getSceneUtils.ts +200 -0
  1197. package/e2e/tests/svgScreenshots/utils/removeOtherElements.ts +26 -0
  1198. package/e2e/tests/svgScreenshots/utils/saveSVGScreenshot.ts +67 -0
  1199. package/e2e/tests/svgScreenshots/utils/saveSVGifs.ts +74 -0
  1200. package/e2e/tests/svgScreenshots/utils/saveSVGs.ts +61 -0
  1201. package/e2e/tests/svgScreenshots/utils/startScreencast.ts +118 -0
  1202. package/e2e/tests/svgScreenshots/utils/svgScreenshotsCompleteReferenced.ts +98 -0
  1203. package/e2e/tests/svgScreenshots/utils/svgifToWebm.ts +196 -0
  1204. package/e2e/tests/svgScreenshots/utils/typeSendAddScenes.ts +86 -0
  1205. package/e2e/tests/testAskLLM/agenticWorkflowToolUses.ts +294 -0
  1206. package/e2e/tests/testAskLLM/createComponentToolUse.ts +49 -0
  1207. package/e2e/tests/testAskLLM/createReceipts.ts +183 -0
  1208. package/e2e/tests/testAskLLM/getAskUserToolUse.ts +36 -0
  1209. package/e2e/tests/testAskLLM/hello.mp3 +0 -0
  1210. package/e2e/tests/testAskLLM/mcpSandboxToolUse.ts +64 -0
  1211. package/e2e/tests/testAskLLM/mockRemoteMcp/Dockerfile +32 -0
  1212. package/e2e/tests/testAskLLM/mockRemoteMcp/package-lock.json +2120 -0
  1213. package/e2e/tests/testAskLLM/mockRemoteMcp/package.json +20 -0
  1214. package/e2e/tests/testAskLLM/mockRemoteMcp/server.ts +144 -0
  1215. package/e2e/tests/testAskLLM/mockRemoteMcp/start-mock-mcp.sh +93 -0
  1216. package/e2e/tests/testAskLLM/sample.pdf +35 -0
  1217. package/e2e/tests/testAskLLM/sampleToolUseData.ts +1413 -0
  1218. package/e2e/tests/testAskLLM/scenarios/geoQuestion.scenario.ts +110 -0
  1219. package/e2e/tests/testAskLLM/scenarios/hygieneRatingsApi.scenario.ts +62 -0
  1220. package/e2e/tests/testAskLLM/scenarios/receiptImport/receiptImport.scenario.ts +53 -0
  1221. package/e2e/tests/testAskLLM/speechToTextTest.ts +101 -0
  1222. package/e2e/tests/testAskLLM/stringify.ts +1 -0
  1223. package/e2e/tests/testAskLLM/testAskLLM.ts +558 -0
  1224. package/e2e/tests/testAskLLM/utils.ts +34 -0
  1225. package/e2e/tests/tsconfig.json +16 -0
  1226. package/e2e/tests/utils/constants.ts +22 -0
  1227. package/e2e/tests/utils/goTo.ts +87 -0
  1228. package/e2e/tests/utils/isPortFree.ts +19 -0
  1229. package/e2e/tests/utils/utils.ts +1319 -0
  1230. package/e2e/tsconfig.json +5 -0
  1231. package/electron/README.md +34 -0
  1232. package/electron/build.sh +74 -0
  1233. package/electron/e2e-electron/electron.spec.tsx +214 -0
  1234. package/electron/e2e-electron/tsconfig.json +10 -0
  1235. package/electron/forge.config.js +26 -0
  1236. package/electron/getProtocolHandler.ts +41 -0
  1237. package/electron/handleErrors.ts +25 -0
  1238. package/electron/icon512.png +0 -0
  1239. package/electron/image.ico +0 -0
  1240. package/electron/images/generate_from_svg.sh +13 -0
  1241. package/electron/images/icon.ico +0 -0
  1242. package/electron/images/icon512.png +0 -0
  1243. package/electron/images/icon512notpadded.png +0 -0
  1244. package/electron/images/loading-effect.css +43 -0
  1245. package/electron/images/prostgles-logo-rounded.svg +46 -0
  1246. package/electron/images/prostgles-logo.svg +39 -0
  1247. package/electron/images/rounded/256x256.png +0 -0
  1248. package/electron/images/rounded/512.png +0 -0
  1249. package/electron/images/rounded/512x512.png +0 -0
  1250. package/electron/images/rounded/64x64.png +0 -0
  1251. package/electron/images/rounded/icon512.png +0 -0
  1252. package/electron/loadingHTML.ts +70 -0
  1253. package/electron/main.ts +125 -0
  1254. package/electron/mainWindow.ts +155 -0
  1255. package/electron/package-lock.json +3916 -0
  1256. package/electron/package.json +111 -0
  1257. package/electron/playwright.config.ts +17 -0
  1258. package/electron/screenCapture.bat +275 -0
  1259. package/electron/scripts/patch-builder.mjs +25 -0
  1260. package/electron/setContextMenu.ts +56 -0
  1261. package/electron/start.sh +10 -0
  1262. package/electron/test-linux-macos.sh +1 -0
  1263. package/electron/test-linux.sh +2 -0
  1264. package/electron/test-setup.js +8 -0
  1265. package/electron/test-w-debug.sh +1 -0
  1266. package/electron/test.sh +1 -0
  1267. package/electron/tsconfig.json +22 -0
  1268. package/electron/win-inno-setup.ts +100 -0
  1269. package/electron/win.js +3 -0
  1270. package/package.json +33 -0
  1271. package/releases/v1.0.0.md +5 -0
  1272. package/releases/v2.0.0.md +25 -0
  1273. package/releases/v2.2.2.md +13 -0
  1274. package/releases/v2.2.3.md +1 -0
  1275. package/releases/v2.2.4.md +1 -0
  1276. package/releases/v2.2.5.md +1 -0
  1277. package/releases/v2.3.1.md +5 -0
  1278. package/releases/v2.3.5.md +7 -0
  1279. package/scripts/check_release_ready.sh +53 -0
  1280. package/scripts/demo/record-local.sh +13 -0
  1281. package/scripts/demo/split-video.sh +6 -0
  1282. package/scripts/get_version.sh +11 -0
  1283. package/scripts/npm_publish_dev.sh +6 -0
  1284. package/scripts/release.sh +35 -0
  1285. package/scripts/start-dev-electron.sh +14 -0
  1286. package/scripts/start-dev.sh +18 -0
  1287. package/scripts/start-prod.sh +5 -0
  1288. package/scripts/test.sh +62 -0
  1289. package/scripts/update_docker_image_versions.sh +28 -0
  1290. package/server/.vscode/settings.json +3 -0
  1291. package/server/eslint.config.mjs +83 -0
  1292. package/server/licenses.json +3821 -0
  1293. package/server/package-lock.json +7252 -0
  1294. package/server/package.json +84 -0
  1295. package/server/sample_schemas/_crypto.sql +95 -0
  1296. package/server/sample_schemas/cleaning.sql +49 -0
  1297. package/server/sample_schemas/cloud_computing.sql +63 -0
  1298. package/server/sample_schemas/countries.sql +29 -0
  1299. package/server/sample_schemas/crypto/index.ts +3 -0
  1300. package/server/sample_schemas/crypto/onMount.ts +802 -0
  1301. package/server/sample_schemas/crypto/package.json +7 -0
  1302. package/server/sample_schemas/crypto/tableConfig.ts +80 -0
  1303. package/server/sample_schemas/crypto/tsconfig.json +12 -0
  1304. package/server/sample_schemas/crypto/workspaceConfig.ts +261 -0
  1305. package/server/sample_schemas/financial.sql +49 -0
  1306. package/server/sample_schemas/food_delivery/connection.ts +1007 -0
  1307. package/server/sample_schemas/food_delivery/databaseConfig.ts +116 -0
  1308. package/server/sample_schemas/food_delivery/index.ts +8 -0
  1309. package/server/sample_schemas/food_delivery/onInit.sql +1507 -0
  1310. package/server/sample_schemas/food_delivery/onMount.ts +149 -0
  1311. package/server/sample_schemas/food_delivery/package.json +4 -0
  1312. package/server/sample_schemas/food_delivery/tsconfig.json +16 -0
  1313. package/server/sample_schemas/food_delivery/workspaceConfig.ts +53 -0
  1314. package/server/sample_schemas/lodging.sql +48 -0
  1315. package/server/sample_schemas/maps.sql +73 -0
  1316. package/server/sample_schemas/property_management/index.ts +2 -0
  1317. package/server/sample_schemas/property_management/onMount.ts +55 -0
  1318. package/server/sample_schemas/property_management/package.json +4 -0
  1319. package/server/sample_schemas/property_management/tsconfig.json +16 -0
  1320. package/server/sample_schemas/property_management/workspaceConfig.ts +92 -0
  1321. package/server/sample_schemas/sales.sql +51 -0
  1322. package/server/sample_schemas/sample.sql +72 -0
  1323. package/server/sample_schemas/testschema.ts +21 -0
  1324. package/server/sample_schemas/weather/index.ts +1 -0
  1325. package/server/sample_schemas/weather/onMount.ts +284 -0
  1326. package/server/sample_schemas/weather/package.json +4 -0
  1327. package/server/sample_schemas/weather/tsconfig.json +16 -0
  1328. package/server/scripts/preparePackage.mjs +18 -0
  1329. package/server/src/BackupManager/BackupManager.ts +297 -0
  1330. package/server/src/BackupManager/checkAutomaticBackup.ts +143 -0
  1331. package/server/src/BackupManager/getInstalledPrograms.ts +203 -0
  1332. package/server/src/BackupManager/pgDump.ts +242 -0
  1333. package/server/src/BackupManager/pgRestore.ts +238 -0
  1334. package/server/src/BackupManager/pipeFromCommand.ts +94 -0
  1335. package/server/src/BackupManager/pipeToCommand.ts +66 -0
  1336. package/server/src/BackupManager/utils.ts +124 -0
  1337. package/server/src/ConnectionManager/ConnectionManager.ts +613 -0
  1338. package/server/src/ConnectionManager/applyStartupSchemaConfig.ts +95 -0
  1339. package/server/src/ConnectionManager/connectionManagerUtils.ts +164 -0
  1340. package/server/src/ConnectionManager/connectionOnReady.ts +76 -0
  1341. package/server/src/ConnectionManager/dbsConnectionOptions.ts +109 -0
  1342. package/server/src/ConnectionManager/getConnectionAuth.ts +37 -0
  1343. package/server/src/ConnectionManager/getConnectionHttpServer.ts +112 -0
  1344. package/server/src/ConnectionManager/getConnectionPublish.ts +119 -0
  1345. package/server/src/ConnectionManager/getConnectionServerFunctions.ts +108 -0
  1346. package/server/src/ConnectionManager/getConnectionSocketPath.ts +12 -0
  1347. package/server/src/ConnectionManager/getHotReloadConfigs.ts +161 -0
  1348. package/server/src/ConnectionManager/getInitiatedPostgresqlPIDs.ts +84 -0
  1349. package/server/src/ConnectionManager/getSchemaConfig.ts +84 -0
  1350. package/server/src/ConnectionManager/initConnectionManager.ts +147 -0
  1351. package/server/src/ConnectionManager/modifyClientSchema.ts +146 -0
  1352. package/server/src/ConnectionManager/parseTableConfig.ts +231 -0
  1353. package/server/src/ConnectionManager/saveCertificates.ts +68 -0
  1354. package/server/src/ConnectionManager/startConnection.ts +353 -0
  1355. package/server/src/ConnectionManager/startConnectionOnRequestHandler.ts +63 -0
  1356. package/server/src/ConnectionManager/syncSchemaConfig.ts +98 -0
  1357. package/server/src/Logger.ts +150 -0
  1358. package/server/src/McpHub/AnthropicMcpHub/McpHub.ts +144 -0
  1359. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/authenticateMcpServer.ts +98 -0
  1360. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/connectToRemoteMCPServer.ts +176 -0
  1361. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/createMcpOAuthProvider.ts +257 -0
  1362. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/getMcpOAuthMetadata.ts +112 -0
  1363. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/getRemoteMcpServerParameters.ts +82 -0
  1364. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/saveServerInfo.ts +76 -0
  1365. package/server/src/McpHub/AnthropicMcpHub/McpOAuth/updateRemoteMcpAuthorizationCode.ts +100 -0
  1366. package/server/src/McpHub/AnthropicMcpHub/McpTypes.ts +189 -0
  1367. package/server/src/McpHub/AnthropicMcpHub/connectToMCPServer.ts +132 -0
  1368. package/server/src/McpHub/AnthropicMcpHub/createMcpServerHandlers.ts +116 -0
  1369. package/server/src/McpHub/AnthropicMcpHub/installMCPServer.ts +195 -0
  1370. package/server/src/McpHub/AnthropicMcpHub/runShellCommand.ts +53 -0
  1371. package/server/src/McpHub/AnthropicMcpHub/startMcpHub.ts +111 -0
  1372. package/server/src/McpHub/DefaultMCPServers/DefaultMCPServers.ts +153 -0
  1373. package/server/src/McpHub/DefaultMCPServers/mcpGithub.ts +968 -0
  1374. package/server/src/McpHub/DockerSandbox/createBridgeInternalDockerNetwork.ts +35 -0
  1375. package/server/src/McpHub/DockerSandbox/createContainer.spec.ts +195 -0
  1376. package/server/src/McpHub/DockerSandbox/createContainer.ts +125 -0
  1377. package/server/src/McpHub/DockerSandbox/dockerMCPServerProxy/dockerContainerAuthRegistry.ts +150 -0
  1378. package/server/src/McpHub/DockerSandbox/dockerMCPServerProxy/dockerMCPServerProxy.ts +395 -0
  1379. package/server/src/McpHub/DockerSandbox/dockerMCPServerProxy/getDockerGatewayIP.ts +27 -0
  1380. package/server/src/McpHub/DockerSandbox/executeDockerCommand.ts +152 -0
  1381. package/server/src/McpHub/DockerSandbox/getContainerLogs.ts +17 -0
  1382. package/server/src/McpHub/DockerSandbox/getDockerRunArgs.ts +114 -0
  1383. package/server/src/McpHub/DockerSandbox/runContainerWithProxyAccess.ts +99 -0
  1384. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServerTypes.ts +143 -0
  1385. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Db.mcp.ts +281 -0
  1386. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Documents.mcp.ts +89 -0
  1387. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/createAgenticWorkflow.ts +247 -0
  1388. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/assertTablesExistInFutureSchema.ts +14 -0
  1389. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/getValidatedMcpServerToolsAllowed.ts +155 -0
  1390. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/parseDDLStatements.ts +84 -0
  1391. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/quoteIdent.ts +139 -0
  1392. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/validateAgenticWorkflowDefinitions.ts +102 -0
  1393. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/validateDatabaseAccessDefinitions.ts +212 -0
  1394. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/validateUserInput.ts +159 -0
  1395. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/definitionValidation/validateUserInputDefinitions.ts +36 -0
  1396. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/execution/getVolumesFromUserInput.ts +134 -0
  1397. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/execution/startAgenticWorkflowContainer.ts +341 -0
  1398. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/proxyHandlers/createWorkflowExecutionHandlers.ts +155 -0
  1399. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/proxyHandlers/getAgentConfigWithDefaults.ts +96 -0
  1400. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/proxyHandlers/setupOrchestrationToolPermissions.ts +64 -0
  1401. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/addInstrumentationToTsLogic.ts +350 -0
  1402. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/callWorkflowProxy.ts +99 -0
  1403. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/defineAgenticWorkflow.spec.ts +110 -0
  1404. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/defineAgenticWorkflow.ts +576 -0
  1405. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/defineAgenticWorkflowHandlers.ts +127 -0
  1406. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/defineAgenticWorkflowHandlers.types.ts +72 -0
  1407. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/definitionHandler.ts +104 -0
  1408. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/ensureWorkflowIsExecuted.ts +53 -0
  1409. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/getTsLogicSummary.ts +639 -0
  1410. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/orchestrationToolHandlers.ts +55 -0
  1411. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSdk/tableHandlers.ts +108 -0
  1412. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSetup/getAgenticWorkflowDockerCoreFiles.spec.ts +26 -0
  1413. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSetup/getAgenticWorkflowDockerCoreFiles.ts +225 -0
  1414. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSetup/getDefineAgenticWorkflowTsWithDbAndMcpTypes.ts +187 -0
  1415. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSetup/getOrchestrationContainerFiles.ts +31 -0
  1416. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/runtimeSetup/getToolTypescriptSchemas.ts +84 -0
  1417. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/agenticWorkflow/startAgenticWorkflow.ts +181 -0
  1418. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/fetchTools.ts +48 -0
  1419. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/runCodeInSandboxContainer.ts +133 -0
  1420. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/schemas/getAgenticToolSchemas.ts +55 -0
  1421. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/schemas/getContainerToolProxyAccessInstructions.ts +22 -0
  1422. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/schemas/getContainerToolSchemas.ts +46 -0
  1423. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/schemas/prostglesUiToolSchemas.ts +23 -0
  1424. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/schemas/suggestDashboardsToolSchema.ts +26 -0
  1425. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/startAgent.ts +166 -0
  1426. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Prostgles/validateCreateDashboards.ts +249 -0
  1427. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Ui.mcp.ts +343 -0
  1428. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Web/Web.mcp.ts +265 -0
  1429. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Web/checkConfigAccess.spec.ts +112 -0
  1430. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Web/checkConfigAccess.ts +263 -0
  1431. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/Web/getDocumentText.ts +34 -0
  1432. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/WebDev.mcp.ts +114 -0
  1433. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/tools/createComponent.ts +94 -0
  1434. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/tools/createComponentQuickFeedbackPreview.ts +53 -0
  1435. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/tools/getWebDevChatAndConnection.ts +12 -0
  1436. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/tools/searchWebDevFiles.spec.ts +82 -0
  1437. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/tools/searchWebDevFiles.ts +118 -0
  1438. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/WebDev/tools/utils.ts +30 -0
  1439. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/getClientDBHandlersForChat.ts +46 -0
  1440. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers/getExistingTablesSchema.ts +230 -0
  1441. package/server/src/McpHub/ProstglesMcpHub/ProstglesMCPServers.ts +30 -0
  1442. package/server/src/McpHub/ProstglesMcpHub/ProstglesMcpHub.ts +244 -0
  1443. package/server/src/McpHub/callMCPServerTool.ts +148 -0
  1444. package/server/src/McpHub/getMcpServerParameters.ts +204 -0
  1445. package/server/src/McpHub/insertMcpServerList.ts +49 -0
  1446. package/server/src/McpHub/reloadMcpServerTools.ts +123 -0
  1447. package/server/src/McpHub/testMCPServerConfig.ts +29 -0
  1448. package/server/src/McpHub/utils.ts +1 -0
  1449. package/server/src/ServiceManager/ServiceManager.spec.ts +27 -0
  1450. package/server/src/ServiceManager/ServiceManager.ts +162 -0
  1451. package/server/src/ServiceManager/ServiceManagerTypes.ts +136 -0
  1452. package/server/src/ServiceManager/buildService.ts +138 -0
  1453. package/server/src/ServiceManager/dockerInspect.ts +33 -0
  1454. package/server/src/ServiceManager/enableService.ts +41 -0
  1455. package/server/src/ServiceManager/getDockerBuildHash.ts +57 -0
  1456. package/server/src/ServiceManager/getSelectedConfigEnvs.ts +47 -0
  1457. package/server/src/ServiceManager/getServiceEndpoints.ts +122 -0
  1458. package/server/src/ServiceManager/initialiseServices.ts +56 -0
  1459. package/server/src/ServiceManager/resolveBinary.ts +41 -0
  1460. package/server/src/ServiceManager/services/documents/documents.service.ts +178 -0
  1461. package/server/src/ServiceManager/services/documents/documents.service.types.ts +43 -0
  1462. package/server/src/ServiceManager/services/documents/src/Dockerfile +29 -0
  1463. package/server/src/ServiceManager/services/documents/src/layout_postprocessor.py +707 -0
  1464. package/server/src/ServiceManager/services/documents/src/requirements.txt +3 -0
  1465. package/server/src/ServiceManager/services/frontendDev/frontendDev.service.ts +19 -0
  1466. package/server/src/ServiceManager/services/frontendDev/src/.prettierrc +3 -0
  1467. package/server/src/ServiceManager/services/frontendDev/src/client/.env.development +1 -0
  1468. package/server/src/ServiceManager/services/frontendDev/src/client/Dockerfile +5 -0
  1469. package/server/src/ServiceManager/services/frontendDev/src/client/README.md +6 -0
  1470. package/server/src/ServiceManager/services/frontendDev/src/client/eslint.config.js +27 -0
  1471. package/server/src/ServiceManager/services/frontendDev/src/client/index.html +13 -0
  1472. package/server/src/ServiceManager/services/frontendDev/src/client/package.json +32 -0
  1473. package/server/src/ServiceManager/services/frontendDev/src/client/public/vite.svg +1 -0
  1474. package/server/src/ServiceManager/services/frontendDev/src/client/src/App.css +42 -0
  1475. package/server/src/ServiceManager/services/frontendDev/src/client/src/App.tsx +19 -0
  1476. package/server/src/ServiceManager/services/frontendDev/src/client/src/api/DBGeneratedSchema.d.ts +33 -0
  1477. package/server/src/ServiceManager/services/frontendDev/src/client/src/api/ProstglesProvider.tsx +61 -0
  1478. package/server/src/ServiceManager/services/frontendDev/src/client/src/assets/react.svg +1 -0
  1479. package/server/src/ServiceManager/services/frontendDev/src/client/src/components/SampleComponent/SampleComponent.tsx +11 -0
  1480. package/server/src/ServiceManager/services/frontendDev/src/client/src/index.css +68 -0
  1481. package/server/src/ServiceManager/services/frontendDev/src/client/src/main.tsx +23 -0
  1482. package/server/src/ServiceManager/services/frontendDev/src/client/src/pages/ComponentPreview.tsx +31 -0
  1483. package/server/src/ServiceManager/services/frontendDev/src/client/src/pages/Home.tsx +36 -0
  1484. package/server/src/ServiceManager/services/frontendDev/src/client/tsconfig.app.json +28 -0
  1485. package/server/src/ServiceManager/services/frontendDev/src/client/tsconfig.json +7 -0
  1486. package/server/src/ServiceManager/services/frontendDev/src/client/tsconfig.node.json +26 -0
  1487. package/server/src/ServiceManager/services/frontendDev/src/client/vite.config.ts +17 -0
  1488. package/server/src/ServiceManager/services/frontendDev/src/e2e/package.json +24 -0
  1489. package/server/src/ServiceManager/services/frontendDev/src/e2e/playwright.config.ts +36 -0
  1490. package/server/src/ServiceManager/services/frontendDev/src/e2e/tests/coverage.ts +67 -0
  1491. package/server/src/ServiceManager/services/frontendDev/src/e2e/tests/main.spec.ts +21 -0
  1492. package/server/src/ServiceManager/services/frontendDev/src/e2e/tests/tsconfig.json +13 -0
  1493. package/server/src/ServiceManager/services/frontendDev/src/e2e/tsconfig.json +13 -0
  1494. package/server/src/ServiceManager/services/frontendDev/src/package.json +15 -0
  1495. package/server/src/ServiceManager/services/frontendDev/src/tsconfig.base.json +32 -0
  1496. package/server/src/ServiceManager/services/speechToText/TRANSCRIBE_OUTPUT_SCHEMA.ts +53 -0
  1497. package/server/src/ServiceManager/services/speechToText/speechToText.service.ts +125 -0
  1498. package/server/src/ServiceManager/services/speechToText/src/Dockerfile +31 -0
  1499. package/server/src/ServiceManager/services/speechToText/src/app.py +115 -0
  1500. package/server/src/ServiceManager/services/speechToText/src/requirements.txt +3 -0
  1501. package/server/src/ServiceManager/services/webSearchSearxng/src/Dockerfile +12 -0
  1502. package/server/src/ServiceManager/services/webSearchSearxng/src/limiter.toml +0 -0
  1503. package/server/src/ServiceManager/services/webSearchSearxng/src/settings.yml +11 -0
  1504. package/server/src/ServiceManager/services/webSearchSearxng/webSearchSearxng.service.ts +36 -0
  1505. package/server/src/ServiceManager/startService.ts +196 -0
  1506. package/server/src/ServiceManager/stopService.ts +23 -0
  1507. package/server/src/ServiceManager/withRetries.ts +19 -0
  1508. package/server/src/authConfig/OAuthProviders/getOAuthLoginProviders.ts +67 -0
  1509. package/server/src/authConfig/OAuthProviders/loginWithProvider.ts +94 -0
  1510. package/server/src/authConfig/authUtils.ts +19 -0
  1511. package/server/src/authConfig/createPasswordlessAdminSessionIfNeeded.ts +86 -0
  1512. package/server/src/authConfig/createPublicUserSessionIfAllowed.ts +48 -0
  1513. package/server/src/authConfig/emailProvider/getEmailAuthProvider.ts +44 -0
  1514. package/server/src/authConfig/emailProvider/getEmailSenderWithMockTest.ts +96 -0
  1515. package/server/src/authConfig/emailProvider/onEmailRegistration.ts +116 -0
  1516. package/server/src/authConfig/getActiveSession.ts +76 -0
  1517. package/server/src/authConfig/getAuth.ts +171 -0
  1518. package/server/src/authConfig/getLogin.ts +206 -0
  1519. package/server/src/authConfig/getUser.ts +108 -0
  1520. package/server/src/authConfig/onMagicLinkOrOTP.ts +171 -0
  1521. package/server/src/authConfig/onUseOrSocketConnected.ts +43 -0
  1522. package/server/src/authConfig/sessionUtils.ts +120 -0
  1523. package/server/src/authConfig/startRateLimitedLoginAttempt.ts +201 -0
  1524. package/server/src/authConfig/subscribeToAuthSetupChanges.ts +144 -0
  1525. package/server/src/authConfig/upsertSession.ts +48 -0
  1526. package/server/src/cli/cli.ts +217 -0
  1527. package/server/src/cli/cliUtils.ts +50 -0
  1528. package/server/src/cloudClients/cloudClients.ts +116 -0
  1529. package/server/src/connectionUtils/getConnectionDetails.ts +76 -0
  1530. package/server/src/connectionUtils/testDBConnection.ts +167 -0
  1531. package/server/src/connectionUtils/validateConnection.ts +114 -0
  1532. package/server/src/createHttpAndIOServers/createHttpServer.ts +147 -0
  1533. package/server/src/createHttpAndIOServers/createIOWebsocketServer.ts +31 -0
  1534. package/server/src/createHttpAndIOServers/getCorsOptions.ts +58 -0
  1535. package/server/src/createHttpAndIOServers/setHttpAppSecurity.ts +124 -0
  1536. package/server/src/electronConfig.ts +223 -0
  1537. package/server/src/envVars.ts +45 -0
  1538. package/server/src/getPSQLQueries.ts +123 -0
  1539. package/server/src/index.ts +273 -0
  1540. package/server/src/init/CSP_DEFAULTS.ts +41 -0
  1541. package/server/src/init/addDevImageProxyRoute.ts +74 -0
  1542. package/server/src/init/cleanupTestDatabases.ts +51 -0
  1543. package/server/src/init/initExpressAndIOServers.ts +127 -0
  1544. package/server/src/init/initUsers.ts +113 -0
  1545. package/server/src/init/insertStateDatabase.ts +72 -0
  1546. package/server/src/init/isRetryableError.ts +50 -0
  1547. package/server/src/init/logOutgoingHttpRequests.ts +15 -0
  1548. package/server/src/init/prostglesOnReady.ts +147 -0
  1549. package/server/src/init/saveTypescriptFilesForProduction.ts +113 -0
  1550. package/server/src/init/setDBSRoutesForElectron.ts +206 -0
  1551. package/server/src/init/startDevHotReloadNotifier.ts +39 -0
  1552. package/server/src/init/startProstgles.ts +220 -0
  1553. package/server/src/init/tryStartProstgles.ts +177 -0
  1554. package/server/src/init/utils.ts +44 -0
  1555. package/server/src/init.sql +1 -0
  1556. package/server/src/methods/getPidStats.ts +336 -0
  1557. package/server/src/methods/getPidStatsFromProc.ts +125 -0
  1558. package/server/src/methods/statusMonitorUtils.ts +148 -0
  1559. package/server/src/publish/getPublishLLM.ts +246 -0
  1560. package/server/src/publish/getPublishLlmChats.ts +73 -0
  1561. package/server/src/publish/publish.ts +398 -0
  1562. package/server/src/schemaConfig.ts +97 -0
  1563. package/server/src/serverFunctions/adminServerFunctions/getAdminServerFunctions.ts +477 -0
  1564. package/server/src/serverFunctions/adminServerFunctions/getAgenticWorkflowFunctions.ts +186 -0
  1565. package/server/src/serverFunctions/adminServerFunctions/getBackupServerFunctions.ts +178 -0
  1566. package/server/src/serverFunctions/adminServerFunctions/getDefineAdminFunction.ts +11 -0
  1567. package/server/src/serverFunctions/adminServerFunctions/getMcpServerFunctions.ts +283 -0
  1568. package/server/src/serverFunctions/adminServerFunctions/getWebAppServerFunctions.ts +228 -0
  1569. package/server/src/serverFunctions/adminServerFunctions/webApp/buildWebApp.ts +38 -0
  1570. package/server/src/serverFunctions/adminServerFunctions/webApp/getReactComponents copy.ts +188 -0
  1571. package/server/src/serverFunctions/adminServerFunctions/webApp/getReactComponents.ts +287 -0
  1572. package/server/src/serverFunctions/adminServerFunctions/webApp/getReactRenderTree.ts +180 -0
  1573. package/server/src/serverFunctions/adminServerFunctions/webApp/getTemplatedWebAppConnection.ts +23 -0
  1574. package/server/src/serverFunctions/adminServerFunctions/webApp/getValidatedWebAppPath.spec.ts +77 -0
  1575. package/server/src/serverFunctions/adminServerFunctions/webApp/getValidatedWebAppPath.ts +22 -0
  1576. package/server/src/serverFunctions/adminServerFunctions/webApp/readWebAppFiles.ts +45 -0
  1577. package/server/src/serverFunctions/adminServerFunctions/webApp/runDockerForWebApp.ts +56 -0
  1578. package/server/src/serverFunctions/adminServerFunctions/webApp/testWebApp.ts +30 -0
  1579. package/server/src/serverFunctions/adminServerFunctions/webApp/writeWebAppFiles.ts +91 -0
  1580. package/server/src/serverFunctions/applySampleSchema.ts +96 -0
  1581. package/server/src/serverFunctions/askLLM/LLMResponseTypes.ts +315 -0
  1582. package/server/src/serverFunctions/askLLM/agentConstants.ts +42 -0
  1583. package/server/src/serverFunctions/askLLM/askLLM.ts +540 -0
  1584. package/server/src/serverFunctions/askLLM/checkLLMLimit.ts +59 -0
  1585. package/server/src/serverFunctions/askLLM/checkMaxCostLimitForChat.ts +51 -0
  1586. package/server/src/serverFunctions/askLLM/defaultPrompts/base.prompt.ts +26 -0
  1587. package/server/src/serverFunctions/askLLM/defaultPrompts/createAgenticWorkflow.prompt.ts +53 -0
  1588. package/server/src/serverFunctions/askLLM/defaultPrompts/createDashboards.prompt.ts +15 -0
  1589. package/server/src/serverFunctions/askLLM/fetchLLMResponse.ts +105 -0
  1590. package/server/src/serverFunctions/askLLM/getCompactedMessages.ts +101 -0
  1591. package/server/src/serverFunctions/askLLM/getFullPrompt.ts +86 -0
  1592. package/server/src/serverFunctions/askLLM/getLLMRequestBody.ts +368 -0
  1593. package/server/src/serverFunctions/askLLM/getLLMToolsAllowedInThisChat.ts +179 -0
  1594. package/server/src/serverFunctions/askLLM/getLLMUsageCost.ts +91 -0
  1595. package/server/src/serverFunctions/askLLM/getPastMessages.ts +9 -0
  1596. package/server/src/serverFunctions/askLLM/getUserMessageCost.ts +21 -0
  1597. package/server/src/serverFunctions/askLLM/getValidatedAskLLMChatOptions.ts +59 -0
  1598. package/server/src/serverFunctions/askLLM/handleToolUseResultConfirmation.ts +87 -0
  1599. package/server/src/serverFunctions/askLLM/parseLLMResponseObject.ts +206 -0
  1600. package/server/src/serverFunctions/askLLM/prostglesLLMTools/getDbConnectionWithPermissions.ts +94 -0
  1601. package/server/src/serverFunctions/askLLM/prostglesLLMTools/getMCPServerTools.ts +28 -0
  1602. package/server/src/serverFunctions/askLLM/prostglesLLMTools/getMcpToolsWithDynamicDescription.ts +77 -0
  1603. package/server/src/serverFunctions/askLLM/prostglesLLMTools/getTemplateUserConnection.ts +182 -0
  1604. package/server/src/serverFunctions/askLLM/readFetchStream.ts +69 -0
  1605. package/server/src/serverFunctions/askLLM/refreshModels.ts +223 -0
  1606. package/server/src/serverFunctions/askLLM/runApprovedTools/getMostSimilar.ts +55 -0
  1607. package/server/src/serverFunctions/askLLM/runApprovedTools/runAgentGoalTool.ts +116 -0
  1608. package/server/src/serverFunctions/askLLM/runApprovedTools/runApprovedTools.ts +348 -0
  1609. package/server/src/serverFunctions/askLLM/runApprovedTools/validateLastMessageToolUseRequests.ts +33 -0
  1610. package/server/src/serverFunctions/askLLM/setupLLM.ts +176 -0
  1611. package/server/src/serverFunctions/askLLM/setupLLMProviders.ts +186 -0
  1612. package/server/src/serverFunctions/deleteConnection.ts +111 -0
  1613. package/server/src/serverFunctions/getConnectionAndDatabaseConfig.ts +27 -0
  1614. package/server/src/serverFunctions/getNodeTypes.spec.ts +80 -0
  1615. package/server/src/serverFunctions/getNodeTypes.ts +306 -0
  1616. package/server/src/serverFunctions/getServerFunctions.ts +163 -0
  1617. package/server/src/serverFunctions/getServerFunctionsContext.ts +29 -0
  1618. package/server/src/serverFunctions/prostglesSignup.ts +28 -0
  1619. package/server/src/serverFunctions/setFileStorage.ts +107 -0
  1620. package/server/src/serverFunctions/userServerFunctions/approveToolUse.ts +146 -0
  1621. package/server/src/serverFunctions/userServerFunctions/getLLMAccessParams.ts +21 -0
  1622. package/server/src/serverFunctions/userServerFunctions/getUserServerFunctions.ts +260 -0
  1623. package/server/src/tableConfig/tableConfig.ts +374 -0
  1624. package/server/src/tableConfig/tableConfigAccessControl.ts +212 -0
  1625. package/server/src/tableConfig/tableConfigAgenticWorkflow.ts +174 -0
  1626. package/server/src/tableConfig/tableConfigBackups.ts +160 -0
  1627. package/server/src/tableConfig/tableConfigConnections.ts +182 -0
  1628. package/server/src/tableConfig/tableConfigDatabaseConfig.ts +714 -0
  1629. package/server/src/tableConfig/tableConfigGlobalSettings.ts +40 -0
  1630. package/server/src/tableConfig/tableConfigLinks.ts +273 -0
  1631. package/server/src/tableConfig/tableConfigLlm/tableConfigLlm.ts +347 -0
  1632. package/server/src/tableConfig/tableConfigLlm/tableConfigLlmChats.ts +361 -0
  1633. package/server/src/tableConfig/tableConfigLlm/tableConfigLlmExtraRequestData.ts +50 -0
  1634. package/server/src/tableConfig/tableConfigMCPServers.ts +676 -0
  1635. package/server/src/tableConfig/tableConfigMigrations.ts +26 -0
  1636. package/server/src/tableConfig/tableConfigPublishedMethods.ts +120 -0
  1637. package/server/src/tableConfig/tableConfigServices.ts +61 -0
  1638. package/server/src/tableConfig/tableConfigUsers.ts +227 -0
  1639. package/server/src/tableConfig/tableConfigWebApp.ts +17 -0
  1640. package/server/src/tableConfig/tableConfigWindows.ts +164 -0
  1641. package/server/src/tableConfig/tableConfigWorkspaces.ts +100 -0
  1642. package/server/src/tableConfig/tablePermissionsSchema.ts +66 -0
  1643. package/server/src/testElectron.ts +33 -0
  1644. package/server/src/upsertConnection.ts +73 -0
  1645. package/server/src/utils/assertIconExists.ts +24 -0
  1646. package/server/src/utils/isPortFree.ts +40 -0
  1647. package/server/src/utils/tout.ts +7 -0
  1648. package/server/test-runner.mjs +28 -0
  1649. package/server/tsconfig.json +45 -0
  1650. package/server/tslint.json +8 -0
@@ -0,0 +1,3820 @@
1
+ import { chromium, expect, test, type Locator } from "@playwright/test";
2
+ import { authenticator } from "otplib";
3
+ import { speechToTextTest } from "testAskLLM/speechToTextTest";
4
+
5
+ import { execSync, spawn } from "child_process";
6
+ import { fileBrowserGoToPath } from "fileBrowserGoToPath";
7
+ import { writeFileSync } from "fs";
8
+ import { mkdir } from "fs/promises";
9
+ import { join, resolve } from "path";
10
+ import {
11
+ localNoAuthSetup,
12
+ QUERIES,
13
+ TEST_DB_NAME,
14
+ USERS,
15
+ } from "utils/constants";
16
+ import { goTo } from "utils/goTo";
17
+ import { isPortFree } from "utils/isPortFree";
18
+ import { startMockSMTPServer } from "./mockSMTPServer";
19
+ import { setupAskLLMToolUse, testAskLLMCode } from "./testAskLLM/testAskLLM";
20
+ import { getCommandElemSelector, getDataKey, getDataLabel } from "./Testing";
21
+ import {
22
+ clickAndWait,
23
+ clickInsertRow,
24
+ closeWorkspaceWindows,
25
+ createAccessRule,
26
+ createAccessRuleForTestDB,
27
+ createDatabase,
28
+ deleteExistingLLMChat,
29
+ disablePwdlessAdminAndCreateUser,
30
+ dropConnectionAndDatabase,
31
+ enableAskLLM,
32
+ enableMCPServers,
33
+ fileName,
34
+ fillLoginFormAndSubmit,
35
+ fillSmartForm,
36
+ forEachLocator,
37
+ getAskLLMLastMessage,
38
+ getLLMResponses,
39
+ getMonacoEditorBySelector,
40
+ getMonacoValue,
41
+ getSearchListItem,
42
+ getSelector,
43
+ getTableWindow,
44
+ getTimeout,
45
+ insertRow,
46
+ login,
47
+ loginWhenSignupIsEnabled,
48
+ monacoType,
49
+ newChat,
50
+ openConnection,
51
+ openTable,
52
+ PageWIds,
53
+ restoreFromBackup,
54
+ runDbsMethod,
55
+ runDbSql,
56
+ runDbsSql,
57
+ runSql,
58
+ scrollElementIntoView,
59
+ selectAndUpsertFile,
60
+ sendAskLLMMessage,
61
+ setModelByText,
62
+ setPromptByText,
63
+ setTableRule,
64
+ setupMagicLinkAuth,
65
+ setWspColLayout,
66
+ toggleMCPTools,
67
+ TWENTY_SECONDS_OR_MORE,
68
+ typeConfirmationCode,
69
+ uploadFile,
70
+ } from "./utils/utils";
71
+
72
+ import { ROOT_DIR } from "svgScreenshots/utils/constants";
73
+ import { MINUTE } from "common/utils";
74
+
75
+ const schemaGraphTestDbName = "financial.sql";
76
+ const DB_NAMES = {
77
+ test: TEST_DB_NAME,
78
+ food_delivery: "food_delivery",
79
+ // sample_database: "sample_database",
80
+ video_demo_database: "prostgles_video_demo",
81
+ };
82
+ const backupDir = resolve(__dirname, "../demo/backups");
83
+
84
+ const viewPortSize = { width: 1080, height: 1080 };
85
+ test.use({
86
+ /** Increase size to ensure agentic workflow fits all logs */
87
+ viewport: viewPortSize,
88
+ });
89
+
90
+ test.describe.configure({ mode: "serial" });
91
+ test.describe("Main test", () => {
92
+ if (process.env.ONLY_VIDEO) {
93
+ test.skip();
94
+ }
95
+ let getEmails: () => any[];
96
+
97
+ test.beforeAll(async () => {
98
+ ({ getEmails } = startMockSMTPServer());
99
+ console.log("getEmails", getEmails());
100
+ return { getEmails };
101
+ });
102
+
103
+ test.beforeEach(async ({ page, browser }, testInfo) => {
104
+ page.on("console", console.log);
105
+ page.on("pageerror", console.error);
106
+ await page.waitForTimeout(200);
107
+
108
+ if (testInfo.title.includes("[no-backup]")) return;
109
+
110
+ // Do auth + backup/restore in an isolated helper context
111
+ const helperContext = await browser.newContext();
112
+ const helperPage = (await helperContext.newPage()) as PageWIds;
113
+
114
+ await login(helperPage, USERS.test_user, "/login");
115
+ const backupName = testInfo.title;
116
+
117
+ const restoreCount = await runDbsMethod(helperPage, "restoreConnections", {
118
+ backupName,
119
+ });
120
+
121
+ if (!restoreCount) {
122
+ await runDbsMethod(helperPage, "backupConnections", {
123
+ name: backupName,
124
+ allActive: true,
125
+ });
126
+ }
127
+ await helperPage.request.post("/logout").catch(() => {});
128
+ await helperContext.close();
129
+ });
130
+
131
+ const deleteAllBackups = async (page: PageWIds) => {
132
+ await page.getByTestId("config.bkp").click();
133
+ await page
134
+ .getByTestId("BackupsControls.Completed")
135
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
136
+ const canDelete = await page.getByRole("button", { name: "Delete all..." });
137
+ if (await canDelete.count()) {
138
+ await canDelete.click();
139
+ await typeConfirmationCode(page);
140
+ await page
141
+ .getByRole("button", { name: "Force delete backups", exact: true })
142
+ .click();
143
+ await page.waitForTimeout(1e3);
144
+ }
145
+ };
146
+
147
+ test("port 3089 must be available for mcpsandbox test [no-backup]", async () => {
148
+ const free = await isPortFree(3089);
149
+ await expect(free).toBe(true);
150
+ });
151
+
152
+ test("Connecting with an existing sid to a fresh instance will ignore the sid IF passwordless admin did not claim a session yet [no-backup]", async ({
153
+ page: p,
154
+ }) => {
155
+ await new Promise((resolve) => setTimeout(resolve, 5000));
156
+ const page = p as PageWIds;
157
+ const url = new URL("http://localhost:3004");
158
+ await page.context().addCookies([
159
+ {
160
+ name: "sid_token",
161
+ value: "1random-sid",
162
+ domain: url.hostname,
163
+ path: "/",
164
+ httpOnly: true,
165
+ secure: url.protocol.startsWith("https"),
166
+ sameSite: "Lax",
167
+ },
168
+ ]);
169
+
170
+ await goTo(page);
171
+
172
+ await page.getByRole("link", { name: "Connections" }).click();
173
+ await page.getByRole("link", { name: "Prostgles UI state" }).click();
174
+ await page.getByTestId("Feedback").waitFor({ state: "visible" });
175
+
176
+ const browser2 = await chromium.launch();
177
+ const newPage = await browser2.newPage();
178
+
179
+ await newPage.context().addCookies([
180
+ {
181
+ name: "sid_token",
182
+ value: "2random-sid",
183
+ domain: url.hostname,
184
+ path: "/",
185
+ httpOnly: true,
186
+ secure: url.protocol.startsWith("https"),
187
+ sameSite: "Lax",
188
+ },
189
+ ]);
190
+ await goTo(newPage);
191
+ await expect(await newPage.textContent("body")).toContain(
192
+ "Only 1 session is allowed for the passwordless admin",
193
+ );
194
+ await browser2.close();
195
+ await newPage.close();
196
+
197
+ await runDbsSql(
198
+ page,
199
+ `
200
+ DELETE FROM magic_links;
201
+ DELETE FROM sessions;
202
+ DELETE FROM login_attempts`,
203
+ ).catch(async (e) => {
204
+ if (e && e.code === "40P01") {
205
+ const info = await runDbsSql(
206
+ page,
207
+ `-- Get detailed information about locks on the specific relations
208
+ SELECT
209
+ pid,
210
+ sa.usename,
211
+ sa.application_name,
212
+ sa.client_addr,
213
+ sa.query_start,
214
+ sa.state,
215
+ sa.query
216
+ FROM pg_stat_activity sa WHERE query <> ''`,
217
+ {},
218
+ { returnType: "rows" },
219
+ );
220
+ console.error("Deadlock detected:", info);
221
+ }
222
+ return Promise.reject(e);
223
+ });
224
+ });
225
+
226
+ test("Can disable passwordless admin by creating a new admin user. User data is reassigned and accessible to the new user [no-backup]", async ({
227
+ page: p,
228
+ }) => {
229
+ const page = p as PageWIds;
230
+
231
+ const goToWorkspace = async (openUsersTable = true) => {
232
+ await page
233
+ .getByRole("link", { name: "Connections" })
234
+ .click({ timeout: 6e3 });
235
+ await page.getByRole("link", { name: "Prostgles UI state" }).click();
236
+ if (openUsersTable) {
237
+ await openTable(page, "users");
238
+ }
239
+ await page
240
+ .getByTestId("dashboard.window.rowInsert")
241
+ .and(page.locator(`[data-key="users"]`))
242
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
243
+ };
244
+
245
+ await goTo(page);
246
+ await goToWorkspace();
247
+
248
+ await page.waitForTimeout(500);
249
+ if (!localNoAuthSetup) {
250
+ await goTo(page);
251
+ await disablePwdlessAdminAndCreateUser(page);
252
+ }
253
+ await login(page);
254
+ await page.waitForTimeout(500);
255
+
256
+ await goTo(page, "/new-connection");
257
+ await page.waitForTimeout(500);
258
+ await goTo(page);
259
+
260
+ /** Expect the workspace to have users table open */
261
+ await goToWorkspace(false);
262
+
263
+ /** SmartForm view mode shows correct data */
264
+ await openTable(page, "login_attempts");
265
+ await page.getByTestId("dashboard.window.viewEditRow").last().click();
266
+ await page.waitForTimeout(2e3);
267
+ const formField = await page.locator(
268
+ getSelector({ testid: "SmartFormField", dataKey: "username" }),
269
+ );
270
+
271
+ const userTypeField = await formField.textContent();
272
+ await expect(userTypeField).toEqual(`Username${USERS.test_user}`);
273
+ await page.getByTestId("SmartForm.close").waitFor({ state: "visible" });
274
+ await page.getByTestId("SmartForm.close").click();
275
+
276
+ await closeWorkspaceWindows(page);
277
+
278
+ /** SmartForm view mode shows correct buttons */
279
+ await openTable(page, "user_types");
280
+ await page.getByTestId("dashboard.window.viewEditRow").last().click();
281
+ await page.getByTestId("SmartForm.close").waitFor({ state: "visible" });
282
+ await page.getByTestId("SmartForm.delete").waitFor({ state: "visible" });
283
+ await page.getByTestId("SmartForm.close").click();
284
+ });
285
+
286
+ test("State db backup and restore works", async ({ page: p }) => {
287
+ const page = p as PageWIds;
288
+ await login(page, USERS.test_user, "/login");
289
+ await openConnection(page, "Prostgles UI state");
290
+
291
+ const table = page.locator(`[data-table-name="user_types"]`);
292
+ await expect(table).toBeVisible();
293
+ await page.getByTestId("dashboard.goToConnConfig").click({ timeout: 15e3 });
294
+ await page.getByTestId("config.bkp").click();
295
+ await page
296
+ .getByRole("button", { name: "Create backup", exact: true })
297
+ .click();
298
+ await page
299
+ .getByRole("button", { name: "Start backup", exact: true })
300
+ .click();
301
+ await page.getByText("Completed");
302
+
303
+ await page.getByTestId("config.goToConnDashboard").click();
304
+ await closeWorkspaceWindows(page);
305
+ await page.reload();
306
+ await expect(table).not.toBeAttached();
307
+
308
+ await page.getByTestId("dashboard.goToConnConfig").click({ timeout: 15e3 });
309
+ await page.getByTestId("config.bkp").click();
310
+ await page.getByTestId("BackupControls.Restore").first().click();
311
+ await typeConfirmationCode(page);
312
+
313
+ await page.getByText("Restore", { exact: true }).click();
314
+ await page.waitForTimeout(4e3);
315
+ await page.reload();
316
+ await page.getByTestId("config.goToConnDashboard").click();
317
+ await expect(table).toBeVisible();
318
+ });
319
+
320
+ test("State db restore from file works", async ({ page: p }) => {
321
+ const page = p as PageWIds;
322
+ await login(page, USERS.test_user, "/login");
323
+ await openConnection(page, "Prostgles UI state");
324
+
325
+ const table = page.locator(`[data-table-name="user_types"]`);
326
+ await expect(table).toBeVisible();
327
+ await page.getByTestId("dashboard.goToConnConfig").click({ timeout: 15e3 });
328
+ await page.getByTestId("config.bkp").click();
329
+
330
+ const [download] = await Promise.all([
331
+ page.waitForEvent("download"),
332
+ page.getByTestId("BackupsControls.Completed.download").first().click(),
333
+ ]);
334
+
335
+ const backupFilePath = join(backupDir, download.suggestedFilename());
336
+ await download.saveAs(backupFilePath);
337
+
338
+ // Optional: keep for later steps in this test
339
+ console.log("Saved backup dump:", backupFilePath);
340
+
341
+ await page.getByTestId("config.goToConnDashboard").click();
342
+ await closeWorkspaceWindows(page);
343
+ await page.reload();
344
+
345
+ await expect(table).not.toBeAttached();
346
+
347
+ await page.getByTestId("dashboard.goToConnConfig").click({ timeout: 15e3 });
348
+ await page.getByTestId("config.bkp").click();
349
+
350
+ await page.getByTestId("BackupsControls.restoreFromFile").click();
351
+
352
+ // Feed the previously downloaded dump file into the restore form
353
+ await page
354
+ .getByTestId("Popup.content")
355
+ .last()
356
+ .locator('input[type="file"]')
357
+ .setInputFiles(backupFilePath);
358
+
359
+ await typeConfirmationCode(page);
360
+
361
+ await page.getByText("Restore", { exact: true }).click();
362
+ await page.waitForTimeout(8e3);
363
+ await page.reload();
364
+
365
+ await login(page, USERS.test_user, "/login");
366
+ await openConnection(page, "Prostgles UI state");
367
+ // await page.getByTestId("config.goToConnDashboard").click();
368
+ await expect(table).toBeVisible();
369
+ });
370
+
371
+ test("Create db for Schema graph", async ({ page: p }) => {
372
+ const page = p as PageWIds;
373
+ await login(page, USERS.test_user);
374
+
375
+ await createDatabase(schemaGraphTestDbName, page, true);
376
+ });
377
+
378
+ test("Schema graph renders and can be zoomed and panned", async ({
379
+ page: p,
380
+ }) => {
381
+ const page = p as PageWIds;
382
+ await login(page, USERS.test_user);
383
+
384
+ await openConnection(page, "financial");
385
+
386
+ /** Schema diagram works */
387
+ await page.getByTestId("SchemaGraph").click();
388
+ await page.waitForTimeout(1e3);
389
+ await page
390
+ .getByText("Reset layout")
391
+ .waitFor({ state: "visible", timeout: 15e3 });
392
+
393
+ await page.getByTestId("SchemaGraph.TopControls.resetLayout").click();
394
+ await page.getByTestId("Btn.ClickConfirmation.Confirm").click();
395
+
396
+ const getDrawnInfo = async () => {
397
+ const drawnInfo: {
398
+ scale3d: [number, number, number];
399
+ zoomScale: number;
400
+ translate: { x: number; y: number };
401
+ shapes: (
402
+ | {
403
+ type: "rectangle";
404
+ coords: [number, number];
405
+ data: {
406
+ name: string;
407
+ };
408
+ }
409
+ | {
410
+ type: "linkline";
411
+ }
412
+ )[];
413
+ } = await page.evaluate(() => {
414
+ //@ts-ignore
415
+ return document.querySelector("canvas")?._drawn;
416
+ });
417
+ return drawnInfo;
418
+ };
419
+ const initialShapesInfo = await getDrawnInfo();
420
+
421
+ /** Scroll wheel zoom works */
422
+ await page.mouse.move(300, 300);
423
+ await page.mouse.wheel(100, 0);
424
+
425
+ await page.waitForTimeout(1500);
426
+
427
+ const zoomedInShapesInfo = await getDrawnInfo();
428
+ await expect(zoomedInShapesInfo.zoomScale).toBeGreaterThan(
429
+ initialShapesInfo.zoomScale,
430
+ );
431
+
432
+ const accountsTablePos = [155, 88] as const;
433
+ await page.mouse.move(...accountsTablePos);
434
+ await page.waitForTimeout(1e3);
435
+ await page.mouse.down({ button: "left" });
436
+ const newPosition = [
437
+ accountsTablePos[0] + 200,
438
+ accountsTablePos[1] + 50,
439
+ ] as const;
440
+ await page.mouse.move(...newPosition, {
441
+ steps: 5,
442
+ });
443
+ await page.waitForTimeout(1e3);
444
+ await page.mouse.up({ button: "left" });
445
+ await page.waitForTimeout(1e3);
446
+ // await page.mouse.move(...accountsTablePos, {
447
+ // steps: 5,
448
+ // });
449
+ // await page.getByTestId("Popup.close").click();
450
+ // await page.getByTestId("SchemaGraph").click();
451
+ // await page.waitForTimeout(2e3);
452
+ const movedShapesInfo = await getDrawnInfo();
453
+ const accountsTableInfo = initialShapesInfo.shapes.find(
454
+ (t) => t.type === "rectangle" && t.data.name === "accounts",
455
+ ) as
456
+ | Extract<(typeof movedShapesInfo.shapes)[number], { type: "rectangle" }>
457
+ | undefined;
458
+ const movedAccountsTableInfo = movedShapesInfo.shapes.find(
459
+ (t) => t.type === "rectangle" && t.data.name === "accounts",
460
+ ) as
461
+ | Extract<(typeof movedShapesInfo.shapes)[number], { type: "rectangle" }>
462
+ | undefined;
463
+ await expect(accountsTableInfo).toBeDefined();
464
+ await expect(movedAccountsTableInfo).toBeDefined();
465
+ await expect(movedAccountsTableInfo!.coords[0]).toBeGreaterThan(
466
+ accountsTableInfo!.coords[0],
467
+ );
468
+ });
469
+
470
+ test("Server settings and account tabs work ", async ({ page: p }) => {
471
+ const page = p as PageWIds;
472
+ await login(page, USERS.test_user, "/login");
473
+
474
+ for (const pageWithTabs of ["/server-settings", "/account"] as const) {
475
+ await goTo(page, pageWithTabs);
476
+
477
+ if (pageWithTabs === "/account") {
478
+ await page.getByTestId("ViewMoreSmartCardList").first().click();
479
+ await expect(
480
+ page.getByTestId("Popup.content").getByTestId("SmartCardList"),
481
+ ).toContainText("Description");
482
+ await page.getByTestId("Popup.close").click();
483
+ }
484
+ const tabItems = await page.getByTestId("MenuList").locator("li").all();
485
+ for (const tabItem of tabItems) {
486
+ const tabKey = await tabItem.getAttribute("data-key");
487
+ const tabText = await tabItem.textContent();
488
+ await expect(tabKey).toBeTruthy();
489
+ await expect(tabText).toBeTruthy();
490
+ await tabItem.click();
491
+ await page.waitForTimeout(500);
492
+ await expect(page.locator(".Tabs_Content h2").first()).toContainText(
493
+ tabText!,
494
+ );
495
+ }
496
+ }
497
+ });
498
+
499
+ test("Email password registration setup", async ({ page: p, browser }) => {
500
+ const page = p as PageWIds;
501
+
502
+ await login(page);
503
+
504
+ await goTo(page, "/component-list");
505
+ await expect(page.locator("body")).toContainText(
506
+ "All button heights match for loading state.",
507
+ );
508
+
509
+ await goTo(page, "/server-settings");
510
+
511
+ /** SmartForm onLoaded bug */
512
+ await page.locator(`[data-key="security"]`).click();
513
+ await page
514
+ .getByText("Allowed IPs and subnets", { exact: true })
515
+ .waitFor({ state: "visible", timeout: 15e3 });
516
+
517
+ await page.locator(`[data-key="auth"]`).click();
518
+ /** The url will be updated automatically and this will page trigger a reload */
519
+ await page.waitForTimeout(1e3);
520
+ const input = await page.getByLabel("Website URL");
521
+ await expect(await input.getAttribute("value")).toEqual(
522
+ "http://localhost:3004",
523
+ );
524
+ await page.getByTestId("EmailAuthSetup").locator("button").click();
525
+ await page.getByTestId("EmailAuthSetup.SignupType").click();
526
+ await page.locator(`[data-key="withPassword"]`).click();
527
+ const fillHostAndTest = async (hostVal: string) => {
528
+ await page.getByTestId("EmailSMTPAndTemplateSetup").click();
529
+ await page.getByText("Email Provider").click();
530
+ await page.locator(`[data-label="Host"] input`).fill(hostVal);
531
+ await page
532
+ .getByTestId("EmailSMTPAndTemplateSetup")
533
+ .getByText("Save")
534
+ .click();
535
+ };
536
+ await fillHostAndTest("invalid___prostgles-test-mock");
537
+ await page.getByText("Enabled").click();
538
+ await page.getByText("Save").click({ timeout: 10e3 });
539
+ const errNode = await page.getByTestId("EmailAuthSetup.error");
540
+ await expect(await errNode.textContent()).toContain(
541
+ // "getaddrinfo ENOTFOUND invalid___prostgles-test-mock", // or EAI_AGAIN
542
+ "getaddrinfo E",
543
+ );
544
+ await expect(await errNode.textContent()).toContain(
545
+ "invalid___prostgles-test-mock",
546
+ );
547
+ await fillHostAndTest("prostgles-test-mock");
548
+ await page.waitForTimeout(1500);
549
+ const errNode1 = await page.getByTestId("EmailAuthSetup.error");
550
+ await expect(await errNode1.count()).toBe(0);
551
+ });
552
+
553
+ test("Email password registration", async ({ page: p, browser }) => {
554
+ const page = await browser.newPage();
555
+ const newPage = p as PageWIds;
556
+ await login(page);
557
+
558
+ await goTo(newPage, "/login");
559
+
560
+ /** Test failed login throttle */
561
+ await newPage.locator("#username").fill(USERS.new_user);
562
+ await newPage.locator("#password").fill(USERS.new_user);
563
+ const start = Date.now();
564
+ await newPage.getByRole("button", { name: "Sign in" }).click();
565
+ await newPage.getByTestId("Login.error").waitFor({ state: "visible" });
566
+ await expect(Date.now() - start).toBeGreaterThan(499);
567
+ await newPage.reload();
568
+
569
+ /** Passwords do not match registration check */
570
+ await newPage.getByTestId("Login.toggle").click();
571
+ await newPage.locator("#username").fill(USERS.new_user);
572
+ await newPage.locator("#password").fill(USERS.new_user);
573
+ await newPage.getByRole("button", { name: "Sign up" }).click();
574
+ await expect(
575
+ await newPage.getByTestId("Login.error").textContent(),
576
+ ).toContain("Passwords do not match");
577
+ await newPage.locator("#new-password").fill(USERS.new_user);
578
+ await newPage.getByRole("button", { name: "Sign up" }).click();
579
+ await expect(
580
+ await newPage
581
+ .getByTestId("AuthNotifPopup")
582
+ .getByTestId("Popup.content")
583
+ .textContent(),
584
+ ).toBe(
585
+ "Email verification sent. Open the verification url or enter the code to confirm your email",
586
+ );
587
+ await newPage.getByRole("button", { name: "Ok" }).click();
588
+
589
+ const newUser = await runDbsSql(
590
+ page,
591
+ `SELECT * FROM users WHERE username = $1`,
592
+ [USERS.new_user],
593
+ { returnType: "row" },
594
+ );
595
+ const code = newUser?.registration?.email_confirmation?.confirmation_code;
596
+ await expect(typeof code).toBe("string");
597
+ await expect(code.length).toBe(6);
598
+ await newPage.locator("#email-verification-code").fill(code);
599
+ await newPage.getByRole("button", { name: "Confirm email" }).click();
600
+ await expect(
601
+ await newPage
602
+ .getByTestId("AuthNotifPopup")
603
+ .getByTestId("Popup.content")
604
+ .textContent(),
605
+ ).toBe("Your email has been confirmed. You can now sign in");
606
+ await newPage.getByRole("button", { name: "Ok" }).click();
607
+
608
+ await newPage.locator("#username").fill(USERS.new_user);
609
+ await newPage.locator("#password").fill(USERS.new_user);
610
+ await newPage.getByRole("button", { name: "Sign in" }).click();
611
+
612
+ await newPage.getByTestId("App.colorScheme").waitFor({ state: "visible" });
613
+ });
614
+
615
+ test("Enable email magic link registrations & Translations", async ({
616
+ page: p,
617
+ }) => {
618
+ const page = p as PageWIds;
619
+
620
+ await login(page);
621
+ await goTo(page, "/server-settings");
622
+ await page.locator(`[data-key="auth"]`).click();
623
+ await setupMagicLinkAuth(page);
624
+
625
+ await goTo(page, "/connections");
626
+ await page.getByTestId("App.LanguageSelector").click();
627
+ await page.locator(`[data-key="es"]`).click();
628
+ await page.waitForLoadState("networkidle");
629
+ await page.waitForTimeout(500);
630
+ await page.getByText("Nueva conexión").waitFor({ state: "visible" });
631
+ await page.getByTestId("App.LanguageSelector").click();
632
+ await page.locator(`[data-key="en"]`).click();
633
+ await page.waitForLoadState("networkidle");
634
+ await page.waitForTimeout(500);
635
+ });
636
+
637
+ test("Email magic link signup", async ({ page: p, browser }) => {
638
+ const newPage = p as PageWIds;
639
+ const page: PageWIds = await browser.newPage();
640
+
641
+ /**
642
+ * Can still login with password with email magic link registrations
643
+ */
644
+ await goTo(page, "/login");
645
+ await page.locator("#username").fill(USERS.test_user);
646
+ await page.getByRole("button", { name: "Continue" }).click();
647
+ await page.locator("#password").waitFor({ state: "visible" });
648
+ await page.locator("#password").fill(USERS.test_user);
649
+ await page.getByRole("button", { name: "Continue" }).click();
650
+ await page.getByTestId("App.colorScheme").waitFor({ state: "visible" });
651
+
652
+ await goTo(newPage, "/login");
653
+
654
+ await newPage.locator("#username").fill(USERS.new_user1);
655
+ await newPage.getByRole("button", { name: "Continue" }).click();
656
+
657
+ await expect(
658
+ await newPage
659
+ .getByTestId("AuthNotifPopup")
660
+ .getByTestId("Popup.content")
661
+ .textContent(),
662
+ ).toBe("Magic link sent. Open the url from your email to login");
663
+ await newPage.getByRole("button", { name: "Ok" }).click();
664
+
665
+ const newUser = await runDbsSql(
666
+ page,
667
+ `
668
+ SELECT *
669
+ FROM users
670
+ WHERE username = $1
671
+ `,
672
+ [USERS.new_user1],
673
+ { returnType: "row" },
674
+ );
675
+ const failedAttempts = await runDbsSql(
676
+ page,
677
+ `
678
+ DELETE -- SELECT *
679
+ FROM login_attempts
680
+ `,
681
+ undefined,
682
+ { returnType: "rows" },
683
+ );
684
+ console.log("failedAttempts", failedAttempts);
685
+ const code = newUser?.registration.otp_code;
686
+ await expect(typeof code).toBe("string");
687
+ await goTo(newPage, `/magic-link?code=${code}&email=${USERS.new_user1}`);
688
+
689
+ await newPage.getByTestId("App.colorScheme").waitFor({ state: "visible" });
690
+
691
+ await runDbsSql(
692
+ page,
693
+ `
694
+ DELETE FROM login_attempts;
695
+ `,
696
+ undefined,
697
+ { returnType: "row" },
698
+ );
699
+ });
700
+
701
+ test("System theme works as expected", async ({ page: p }) => {
702
+ const page = p as PageWIds;
703
+ await page.emulateMedia({ colorScheme: "dark" });
704
+ await goTo(page);
705
+ await page.locator("html.dark-theme").waitFor({ state: "visible" });
706
+ const darkBackgroundColor = await page.evaluate(() => {
707
+ return getComputedStyle(document.body).backgroundColor;
708
+ });
709
+ await expect(darkBackgroundColor).toBe("rgb(26, 25, 25)");
710
+
711
+ await page.emulateMedia({ colorScheme: "light" });
712
+ await goTo(page);
713
+ await page.locator("html.light-theme").waitFor({ state: "visible" });
714
+ const lightBackgroundColor = await page.evaluate(() => {
715
+ return getComputedStyle(document.body).backgroundColor;
716
+ });
717
+ await expect(lightBackgroundColor).toBe("rgb(244, 245, 247)");
718
+ });
719
+
720
+ test("Setup Free LLM assistant signup", async ({ page: p }) => {
721
+ const page = p as PageWIds;
722
+ await loginWhenSignupIsEnabled(page);
723
+ const existingCloudDb = await page
724
+ .getByRole("link", {
725
+ name: "cloud",
726
+ exact: true,
727
+ })
728
+ .count();
729
+
730
+ if (existingCloudDb) {
731
+ return;
732
+ }
733
+
734
+ const dbName = "cloud";
735
+ await createDatabase(dbName, page, false);
736
+
737
+ /** Create table */
738
+ await runDbSql(
739
+ page,
740
+ `CREATE TABLE IF NOT EXISTS example_table (id SERIAL PRIMARY KEY, name TEXT);`,
741
+ );
742
+ await expect(
743
+ page
744
+ .getByTestId("dashboard.menu.tablesSearchList")
745
+ .locator(getDataKey("example_table")),
746
+ ).toBeVisible();
747
+
748
+ await page.getByTestId("dashboard.goToConnConfig").click();
749
+
750
+ await page.getByTestId("config.auth").click();
751
+ await setupMagicLinkAuth(page);
752
+ await page.getByText("Enabled").click();
753
+ await page.getByText("Save").click();
754
+
755
+ /** Enable http api */
756
+ await page.getByTestId("config.api").click();
757
+ await page.getByText("Enabled").click();
758
+ await page.waitForTimeout(500);
759
+ await page.reload();
760
+ await page.locator("input#port").fill("3005");
761
+ await page.waitForTimeout(500);
762
+ await page.waitForEvent("load");
763
+ await page.reload();
764
+ await page.locator("input#port").waitFor({ state: "visible" });
765
+ await expect(page.locator("input#port")).toHaveValue("3005");
766
+
767
+ /** Create API token with sample html */
768
+ await page.getByTestId("config.api").click();
769
+ await page.getByTestId("APIDetailsTokens.CreateToken").click();
770
+ await page.getByTestId("APIDetailsTokens.CreateToken.generate").click();
771
+ await page.getByTestId("Popup.close").click();
772
+
773
+ await page.getByTestId("APIDetailsHttp.Examples").click();
774
+ const monacoEditor = page.getByTestId("MonacoEditor");
775
+ await monacoEditor.waitFor({ state: "visible" });
776
+ const jsContent = await monacoEditor.textContent();
777
+ const indexHtml = `
778
+ <!DOCTYPE html>
779
+ <html>
780
+ <head>
781
+ <title> Prostgles </title>
782
+ <meta charset="UTF-8">
783
+ <meta name="viewport" content="width=device-width, initial-scale=1">
784
+ <script src="./script.js"></script>
785
+ </head>
786
+ <body style="white-space: pre">
787
+
788
+ <h1>Loading...</h1>
789
+
790
+ </body>
791
+ </html>
792
+ `;
793
+ const demoDir = resolve(__dirname, "../demo");
794
+ await mkdir(demoDir, { recursive: true });
795
+ const indexFilePath = join(demoDir, "index.html");
796
+ await writeFileSync(indexFilePath, indexHtml);
797
+ const scriptFilePath = join(demoDir, "script.js");
798
+ await writeFileSync(
799
+ scriptFilePath,
800
+ `
801
+ (async () => {
802
+ ${jsContent}
803
+ document.body.innerText = JSON.stringify(schema, null, 2);
804
+ })()
805
+ `,
806
+ );
807
+
808
+ // TOOD: Check ws api as well
809
+ // await page.getByTestId("APIDetailsWs.Examples").click();
810
+ // await page.locator(getDataKey("Vanilla JS")).click();
811
+ // const [download] = await Promise.all([
812
+ // page.waitForEvent("download"),
813
+ // page.getByText("Download code sample", { exact: true }).click(),
814
+ // ]);
815
+ // await download.saveAs(filePath);
816
+ await page.getByTestId("Popup.close").click();
817
+
818
+ /** Enable Web app */
819
+ await page.getByTestId("config.webApp").click();
820
+ await page.waitForTimeout(1500);
821
+ await page.getByTestId("WebApp.directory").hover();
822
+ await page.waitForTimeout(1500);
823
+ await page.getByTestId("WebApp.directory").click();
824
+ await fileBrowserGoToPath(page.getByTestId("FileTree"), [
825
+ "ui",
826
+ "e2e",
827
+ "demo",
828
+ ]);
829
+ await page.getByText("Select directory", { exact: true }).click();
830
+ });
831
+
832
+ test("Web app", async ({ page: p }) => {
833
+ const page = p as PageWIds;
834
+ await page.goto("http://localhost:3005");
835
+ await expect(page.locator("body")).toContainText("example_table");
836
+ });
837
+
838
+ test("Setup Free LLM assistant functions", async ({ page: p }) => {
839
+ const page = p as PageWIds;
840
+ await loginWhenSignupIsEnabled(page);
841
+
842
+ /** Create cloud db */
843
+ await page.getByRole("link", { name: "Cloud" }).click();
844
+ await page.getByTestId("dashboard.goToConnConfig").click();
845
+ await page.getByTestId("config.api").click();
846
+
847
+ /** Add server-side func */
848
+ await page.getByTestId("config.methods").click();
849
+
850
+ /** This timeout is crucial in ensuring monaco editor shows suggestions */
851
+ await page.getByText("Create function").click(TWENTY_SECONDS_OR_MORE);
852
+ await page.locator("input#function_name").fill("askLLM");
853
+ await page.waitForTimeout(1e3);
854
+ await monacoType(page, ".MethodDefinition", "dbo.t", {
855
+ deleteAll: false,
856
+ pressBeforeTyping: ["ArrowUp"],
857
+ /** This helps with flaky tests done on workers */
858
+ pressAfterTyping: [
859
+ "Backspace",
860
+ "Backspace",
861
+ "Backspace",
862
+ "Backspace",
863
+ "Backspace",
864
+ ],
865
+ });
866
+ await monacoType(page, ".MethodDefinition", "dbo.t", {
867
+ deleteAll: false,
868
+ pressBeforeTyping: ["ArrowUp"],
869
+ });
870
+ await page.keyboard.press("Tab");
871
+
872
+ /** Ensure db schema suggestions work */
873
+ const initialCode =
874
+ "export const run: ProstglesMethod = async (args, { db, dbo, user, callMCPServerTool }) => {\n dbo.tx \n}";
875
+ const funcCode = await getMonacoValue(page, ".MethodDefinition");
876
+ await expect(funcCode).toEqual(initialCode);
877
+
878
+ /** Add llm server side func */
879
+ const fullCode = initialCode.replace("dbo.tx", testAskLLMCode + "dbo.tx");
880
+ await monacoType(page, ".MethodDefinition", fullCode, {
881
+ deleteAll: true,
882
+ keyPressDelay: 0,
883
+ });
884
+ const funcCode2 = await getMonacoValue(page, ".MethodDefinition");
885
+ const allWhiteSpaceAsSingleSpace = (v: string) => {
886
+ const res = v.replace(/\s+/g, " ");
887
+ return res;
888
+ };
889
+ await expect(allWhiteSpaceAsSingleSpace(funcCode2)).toEqual(
890
+ allWhiteSpaceAsSingleSpace(fullCode),
891
+ );
892
+
893
+ /** Add askLLM func args */
894
+ for (const [index, argName] of [
895
+ "messages",
896
+ "model",
897
+ "tools",
898
+ "max_tokens",
899
+ "temperature",
900
+ ].entries()) {
901
+ await page.getByTitle("Add new item").click();
902
+ await page.getByLabel("Argument name").last().fill(argName);
903
+ await page.getByLabel("Data type").last().click();
904
+ await page.locator(`[data-key="any"]`).click();
905
+ await page.waitForTimeout(500); // Popup closes but also has this "Show more" button
906
+ await page.getByTitle("Show more").click();
907
+ await page.getByText("Optional", { exact: true }).nth(index).click();
908
+ await page.waitForTimeout(500);
909
+ }
910
+ await page.getByRole("button", { name: "Add function" }).click();
911
+
912
+ /** Page will reload after func is added */
913
+ await page.waitForLoadState("networkidle");
914
+ await page.waitForTimeout(1e3);
915
+ /** JSONBSchema localValue bugs. Argument must show */
916
+ await page.getByTitle("Edit function").click();
917
+ await page.waitForTimeout(1e3);
918
+ await page.getByLabel("Argument name").last().waitFor({ state: "visible" });
919
+ await page.getByTestId("Popup.close").click();
920
+ /** This is crucial in ensuring monaco automatic text placeholder replacements don't break the code */
921
+ await setupAskLLMToolUse(page);
922
+
923
+ /**
924
+ * Publish functions for user
925
+ */
926
+ await page.getByTestId("config.ac").click();
927
+ await createAccessRule(page, "default");
928
+ await page.getByText("askLLM").click();
929
+ await page.getByText("Create rule").click();
930
+ await page.waitForTimeout(1e3);
931
+
932
+ /** Signup for free LLM assistant */
933
+ await goTo(page, "/connections");
934
+ await page.getByRole("link", { name: "Prostgles UI state" }).click();
935
+ await page.getByTestId("AskLLM").click();
936
+ await page
937
+ .getByTestId("SetupLLMCredentials.free")
938
+ .click({ ...TWENTY_SECONDS_OR_MORE });
939
+ await page.locator("input#email").fill(USERS.free_llm_user1);
940
+ await page.getByTestId("ProstglesSignup.continue").click();
941
+ await page.waitForTimeout(1e3);
942
+ const llmUser = await runDbsSql(
943
+ page,
944
+ `
945
+ SELECT *
946
+ FROM users
947
+ WHERE username = $1
948
+ `,
949
+ [USERS.free_llm_user1],
950
+ { returnType: "row" },
951
+ );
952
+ const freeLLMCode = llmUser?.registration.otp_code;
953
+ await expect(typeof freeLLMCode).toBe("string");
954
+ await page.locator("input#otp-code").fill(freeLLMCode);
955
+ await page.getByTestId("ProstglesSignup.continue").click();
956
+ await page.waitForTimeout(1e3);
957
+ await page.locator(".ProstglesSignup").waitFor({ state: "detached" });
958
+ });
959
+
960
+ test("Test LLM responses and tools", async ({ page: p }) => {
961
+ const page = p as PageWIds;
962
+ await loginWhenSignupIsEnabled(page);
963
+
964
+ await openConnection(page, "cloud");
965
+
966
+ await runDbsSql(
967
+ page,
968
+ `
969
+ UPDATE mcp_servers SET enabled = false WHERE name IN ('playwright', 'prostgles-ui');
970
+ DELETE FROM mcp_server_tools WHERE server_name IN ('playwright', 'prostgles-ui');
971
+ `,
972
+ );
973
+ await runDbSql(
974
+ page,
975
+ `
976
+ CREATE TABLE IF NOT EXISTS receipts (
977
+ id SERIAL PRIMARY KEY,
978
+ company_name TEXT,
979
+ amount NUMERIC,
980
+ currency TEXT,
981
+ date TIMESTAMP,
982
+ created_at TIMESTAMP DEFAULT NOW()
983
+ );
984
+ `,
985
+ );
986
+ /* Wait for schema change */
987
+ await page.waitForTimeout(2e3);
988
+
989
+ await deleteExistingLLMChat(page);
990
+
991
+ await page.getByTestId("Popup.close").click();
992
+
993
+ const userMessage = "hey";
994
+ const responses = await getLLMResponses(page, [userMessage]);
995
+ const messageCost = "$0";
996
+ await expect(responses).toEqual([
997
+ {
998
+ isOk: false,
999
+ response: messageCost + "free ai assistant" + userMessage,
1000
+ },
1001
+ ]);
1002
+
1003
+ await page.getByTestId("AskLLM").click();
1004
+
1005
+ await sendAskLLMMessage(page, " request_tool_access ");
1006
+ await page
1007
+ .getByTestId("RequestToolAccess.Approve")
1008
+ .click({ ...TWENTY_SECONDS_OR_MORE });
1009
+
1010
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1011
+ `Requested access to websearch tool and read access to receipts table in the database.`,
1012
+ { ...TWENTY_SECONDS_OR_MORE },
1013
+ );
1014
+ await page.getByTestId("LLMChatOptions.DatabaseAccess").click();
1015
+ await expect(page.getByTestId("DatabaseAccessEditor.Mode")).toContainText(
1016
+ "Custom",
1017
+ );
1018
+ await expect(
1019
+ page
1020
+ .getByTestId("DatabaseAccessEditor.TableRules")
1021
+ .last()
1022
+ .locator(getDataKey("receipts"))
1023
+ .locator(`button[data-color="action"]`),
1024
+ ).toContainText("SELECT", { ignoreCase: false });
1025
+ await page.getByTestId("Popup.close").last().click();
1026
+ await newChat(page);
1027
+
1028
+ await setModelByText(page, "son");
1029
+
1030
+ await expect(page.getByTestId("LLMChatOptions.MCPTools")).toContainText(
1031
+ "10",
1032
+ );
1033
+ await sendAskLLMMessage(page, " task ");
1034
+
1035
+ await page
1036
+ .getByTestId("RequestToolAccess.Approve")
1037
+ .click({ ...TWENTY_SECONDS_OR_MORE });
1038
+ await expect(page.getByTestId("RequestToolAccess")).toContainText(
1039
+ "Added tool access",
1040
+ { ...TWENTY_SECONDS_OR_MORE },
1041
+ );
1042
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1043
+ "Added fetch tool access and database permissions for receipts table.",
1044
+ { ...TWENTY_SECONDS_OR_MORE },
1045
+ );
1046
+
1047
+ await expect(page.getByTestId("LLMChatOptions.MCPTools")).toContainText(
1048
+ "12",
1049
+ );
1050
+
1051
+ const dbToolsBtn = await page
1052
+ .getByTestId("LLMChatOptions.DatabaseAccess")
1053
+ .locator("button");
1054
+ await expect(await dbToolsBtn.getAttribute("class")).toContain(
1055
+ "btn-color-action",
1056
+ );
1057
+
1058
+ // await addExistingDatabase(page, "food_delivery");
1059
+ await createDatabase("food_delivery", page, true);
1060
+ await page.getByTestId("AskLLM").click();
1061
+ await newChat(page);
1062
+
1063
+ await setPromptByText(page, "dashboard");
1064
+ await runDbSql(
1065
+ page,
1066
+ `
1067
+ CREATE TABLE IF NOT EXISTS hygiene_ratings (
1068
+ id SERIAL PRIMARY KEY,
1069
+ restaurant_name TEXT,
1070
+ hygiene_score INTEGER,
1071
+ restaurant_id int4 NOT NULL REFERENCES restaurants(id) ON DELETE CASCADE,
1072
+ inspection_date DATE
1073
+ );
1074
+ `,
1075
+ );
1076
+
1077
+ await sendAskLLMMessage(
1078
+ page,
1079
+ "I need some useful dashboards to track performance",
1080
+ );
1081
+ await page
1082
+ .getByTestId("AskLLMChat.LoadSuggestedDashboards")
1083
+ .click({ ...TWENTY_SECONDS_OR_MORE });
1084
+
1085
+ const workspaceBtn = await page.getByTestId("WorkspaceMenu.list");
1086
+ await expect(workspaceBtn).toContainText(
1087
+ "Customer Insights",
1088
+ TWENTY_SECONDS_OR_MORE,
1089
+ );
1090
+
1091
+ await page.waitForTimeout(1e3);
1092
+
1093
+ await page.locator(getDataKey("Restaurant Performance")).click();
1094
+ await page
1095
+ .getByTestId("TableBody")
1096
+ .locator(".ProgressBar")
1097
+ .first() // Table cell barcharts
1098
+ // .scrollIntoViewIfNeeded({ timeout: 60e3 });
1099
+ .waitFor({ state: "visible", timeout: 60e3 });
1100
+
1101
+ await page.getByTestId("AskLLM").click();
1102
+ await page
1103
+ .getByTestId("AskLLMChat.UnloadSuggestedDashboards")
1104
+ .click(TWENTY_SECONDS_OR_MORE);
1105
+ await expect(workspaceBtn).not.toContainText("Customer Insights");
1106
+
1107
+ await page.waitForTimeout(2e3);
1108
+
1109
+ await goTo(page, "/connections");
1110
+ await dropConnectionAndDatabase("food_delivery", page, true);
1111
+ await page.waitForTimeout(2e3);
1112
+ });
1113
+
1114
+ test("Document to markdown service and conversion works", async ({
1115
+ page: p,
1116
+ }) => {
1117
+ const page = p as PageWIds;
1118
+ await loginWhenSignupIsEnabled(page);
1119
+
1120
+ await openConnection(page, "cloud");
1121
+ await page.getByTestId("AskLLM").click();
1122
+
1123
+ /**
1124
+ * Only test locally due to service image size
1125
+ */
1126
+ if (!process.env.CI) {
1127
+ const addFile = async () => {
1128
+ const pdfFilePath = join(
1129
+ __dirname,
1130
+ "..",
1131
+ "tests",
1132
+ "testAskLLM",
1133
+ "sample.pdf",
1134
+ );
1135
+ const fileChooserPromise = page.waitForEvent("filechooser");
1136
+ await page.getByTestId("Chat.addFiles").click();
1137
+ const fileChooser = await fileChooserPromise;
1138
+ await fileChooser.setFiles(pdfFilePath);
1139
+ };
1140
+ await addFile();
1141
+ const toggle = page.getByTestId(
1142
+ "ChatFileAttachments.convertDocsToMarkdown",
1143
+ );
1144
+ await toggle.click();
1145
+ /** Expect the switch toggle to show loader */
1146
+ await expect(
1147
+ page
1148
+ .getByTestId("Chat.sendWrapper")
1149
+ .locator(".SwitchToggle")
1150
+ .getByTestId("Loading"),
1151
+ ).toBeVisible();
1152
+
1153
+ /** Service finished starting. This might take much longer if it needs installing */
1154
+ await expect(page.getByLabel("Convert docs to markdown")).toBeChecked(
1155
+ getTimeout(90e3),
1156
+ );
1157
+
1158
+ await page.keyboard.press("Control+KeyK");
1159
+ await page.waitForTimeout(1500);
1160
+ await page.keyboard.type("serv");
1161
+ await page.keyboard.press("Enter");
1162
+ await expect(
1163
+ page.locator(getDataKey("documents")).getByTitle("Stop service"),
1164
+ ).toBeVisible();
1165
+ await page.keyboard.press("Escape");
1166
+
1167
+ const itemBtn = page
1168
+ .getByTestId("Chat.attachedFiles")
1169
+ .getByTestId("MediaViewer")
1170
+ .getByText("sample.pdf");
1171
+ await expect(itemBtn).toBeVisible({ ...TWENTY_SECONDS_OR_MORE });
1172
+
1173
+ /** Shows content in popup */
1174
+ await itemBtn.click();
1175
+ await expect(page.getByTestId("Popup.header").last()).toContainText(
1176
+ "sample.pdf",
1177
+ );
1178
+
1179
+ await page.getByTestId("Popup.close").last().click();
1180
+
1181
+ /** Removing works */
1182
+ await page.getByTestId("ChatFileAttachments.removeFile").click();
1183
+ await expect(itemBtn).not.toBeAttached();
1184
+
1185
+ /** Re-adding the same file works */
1186
+ await addFile();
1187
+
1188
+ await expect(itemBtn).toBeVisible({ ...TWENTY_SECONDS_OR_MORE });
1189
+
1190
+ await page.getByTestId("Chat.send").click();
1191
+
1192
+ /** In chat file visible */
1193
+ const inChatItemBtn = page
1194
+ .getByTestId("Chat.messageList")
1195
+ .getByTestId("LLMChatMessageContent.textDocument")
1196
+ .getByText("sample.pdf");
1197
+ await expect(inChatItemBtn).toBeVisible({
1198
+ ...TWENTY_SECONDS_OR_MORE,
1199
+ });
1200
+
1201
+ /** Agent was provided the text content */
1202
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1203
+ "This is a sample PDF",
1204
+ { ...TWENTY_SECONDS_OR_MORE },
1205
+ );
1206
+
1207
+ await inChatItemBtn.click();
1208
+ await expect(page.getByTestId("Popup.header").last()).toContainText(
1209
+ "sample.pdf",
1210
+ );
1211
+ await expect(page.getByTestId("Popup.content").last()).toContainText(
1212
+ "This is a sample PDF",
1213
+ );
1214
+ await page.getByTestId("Popup.close").last().click();
1215
+ }
1216
+ });
1217
+
1218
+ test("Test LLM tools", async ({ page: p }) => {
1219
+ const page = p as PageWIds;
1220
+ await loginWhenSignupIsEnabled(page);
1221
+
1222
+ await openConnection(page, "cloud");
1223
+ await page.getByTestId("AskLLM").click();
1224
+ await newChat(page);
1225
+ await toggleMCPTools(page, ["fetch"]);
1226
+
1227
+ const mcpFetchAndExpect = async (
1228
+ expectedMsg: string,
1229
+ msgType: "last-msg" | "last-tool-use",
1230
+ ) => {
1231
+ await sendAskLLMMessage(page, " mcp ");
1232
+ await page
1233
+ .getByTestId("AskLLMToolApprover.AllowOnce")
1234
+ .click({ ...TWENTY_SECONDS_OR_MORE });
1235
+ await expect(
1236
+ page.getByRole("button", { name: "Approve Once" }),
1237
+ ).toHaveCount(0, TWENTY_SECONDS_OR_MORE);
1238
+ const mcpToolUse = await getAskLLMLastMessage(page);
1239
+
1240
+ const locatorToCheck =
1241
+ msgType === "last-msg" ? mcpToolUse : (
1242
+ page.getByTestId("AskLLM.popup").getByTestId("ToolUseMessage").last()
1243
+ );
1244
+ await expect(locatorToCheck).toContainText(expectedMsg, {
1245
+ ...TWENTY_SECONDS_OR_MORE,
1246
+ });
1247
+ };
1248
+ await mcpFetchAndExpect(
1249
+ "is blocked by MCP server configuration",
1250
+ "last-tool-use",
1251
+ );
1252
+
1253
+ /** Must allow internal subnets */
1254
+ await page
1255
+ .locator(
1256
+ getCommandElemSelector("LLMChatOptions.EnabledMcpServer") +
1257
+ getDataKey("web"),
1258
+ )
1259
+ .click();
1260
+ await page.getByTestId("MCPServerConfigButton").click();
1261
+ await page.getByLabel("Block internal subnets").click();
1262
+ await page.getByTestId("MCPServerConfig.save").click();
1263
+ await page.waitForTimeout(1e3);
1264
+ await page.getByTestId("Popup.close").last().click();
1265
+ await mcpFetchAndExpect("successfully fetched the login page", "last-msg");
1266
+
1267
+ /** Ensure chat name updates based on first message */
1268
+ await expect(page.getByTestId("LLMChat.select")).toContainText("mcp");
1269
+
1270
+ await sendAskLLMMessage(page, " mcp ");
1271
+ await page
1272
+ .getByTestId("AskLLMToolApprover.AllowOnce")
1273
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
1274
+ await page.getByTestId("Popup.close").last().click();
1275
+ await page.waitForTimeout(1e3);
1276
+ await sendAskLLMMessage(page, " interrupt tool call ");
1277
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1278
+ "Tool use requests were interrupted by the user",
1279
+ {
1280
+ ...TWENTY_SECONDS_OR_MORE,
1281
+ },
1282
+ );
1283
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1284
+ "free ai assistant interrupt tool call",
1285
+ );
1286
+
1287
+ await sendAskLLMMessage(page, " get_specific_tool_schemas ");
1288
+ // Auto-approved by default
1289
+ await page
1290
+ .getByTestId("ToolUseMessage.toggle")
1291
+ .getByText(
1292
+ 'prostgles-ui--get_specific_tool_schemas\nmcpServerTools: {"web":{"fetch":1}}',
1293
+ )
1294
+ .click();
1295
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1296
+ `Fetches from a URL`,
1297
+ );
1298
+
1299
+ await page.waitForTimeout(1e3);
1300
+ await sendAskLLMMessage(page, " mcpplaywright ");
1301
+ await page
1302
+ .getByTestId("ToolUseMessage.toggleGroup")
1303
+ .getByText("2 tool calls")
1304
+ .last()
1305
+ .click();
1306
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1307
+ `Tool name "playwright--browser_navigate" is invalid. Try enabling and reloading the tools`,
1308
+ );
1309
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1310
+ `Tool name "playwright--browser_snapshot" is invalid. Try enabling and reloading the tools`,
1311
+ );
1312
+
1313
+ await enableMCPServers(page, ["playwright"]);
1314
+ await page
1315
+ .getByText("browser_tabs")
1316
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE }); // wait for tools list to refresh
1317
+ await page.getByTestId("Popup.close").last().click();
1318
+
1319
+ await page.waitForTimeout(2e3);
1320
+ await sendAskLLMMessage(page, " mcpplaywright ");
1321
+ await page
1322
+ .getByTestId("ToolUseMessage.toggleGroup")
1323
+ .getByText("2 tool calls")
1324
+ .last()
1325
+ .click();
1326
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1327
+ `Tool name "playwright--browser_navigate" is not allowed`,
1328
+ );
1329
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1330
+ `Tool name "playwright--browser_snapshot" is not allowed`,
1331
+ );
1332
+
1333
+ await toggleMCPTools(page, ["browser_navigate", "browser_snapshot"]);
1334
+
1335
+ await sendAskLLMMessage(page, " mcpplaywright ");
1336
+ await page.waitForTimeout(2e3);
1337
+ await page.getByTestId("AskLLMToolApprover.AllowOnce").click();
1338
+ await page.waitForTimeout(200);
1339
+ await page.getByTestId("AskLLMToolApprover.AllowOnce").click();
1340
+ await page.waitForTimeout(10e3);
1341
+ await page
1342
+ .getByTestId("ToolUseMessage.toggleGroup")
1343
+ .getByText("2 tool calls")
1344
+ .last()
1345
+ .click();
1346
+ const lastToolUseBtn = await page
1347
+ .getByTestId("Chat.messageList")
1348
+ .getByText("browser_snapshot")
1349
+ .last();
1350
+ await scrollElementIntoView(lastToolUseBtn);
1351
+ await page.waitForTimeout(1e3);
1352
+ await lastToolUseBtn.click();
1353
+ await page.waitForTimeout(1e3);
1354
+ /** Can be flaky */
1355
+ await expect(page.getByTestId("MarkdownMonacoCode").last()).toContainText(
1356
+ `Page Title: Prostgles`,
1357
+ { ...TWENTY_SECONDS_OR_MORE },
1358
+ );
1359
+ await lastToolUseBtn.click();
1360
+
1361
+ await page.waitForTimeout(2e3);
1362
+ /** Test max consecutive tool call fails */
1363
+ await sendAskLLMMessage(page, " mcpfail ");
1364
+ await page.getByTestId("ToolUseMessage.toggleGroup").last().click();
1365
+ await expect(
1366
+ page
1367
+ .getByTestId("Chat.messageList")
1368
+ .getByText(`Tool name "web--invalidfetch" is invalid`),
1369
+ ).toHaveCount(5, getTimeout(30e3));
1370
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1371
+ `failed consecutive tool requests reached`,
1372
+ );
1373
+
1374
+ /** Test max consecutive tool call fails */
1375
+ for (let step = 0; step < 5; step++) {
1376
+ await sendAskLLMMessage(page, " cost ");
1377
+ }
1378
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1379
+ `Maximum number (5) of failed consecutive tool requests reached`,
1380
+ );
1381
+
1382
+ /** Test max chat cost */
1383
+ const defaultMaxCost = 5;
1384
+ const costPerMsg = 1.8;
1385
+ await newChat(page);
1386
+ for (
1387
+ let step = 0;
1388
+ step < Math.ceil(defaultMaxCost / costPerMsg) + 1;
1389
+ step++
1390
+ ) {
1391
+ await page.waitForTimeout(1500);
1392
+ await sendAskLLMMessage(page, "cost", true);
1393
+ }
1394
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1395
+ `Maximum total cost of the chat (5) reached. Current cost: 5.`,
1396
+ { ...TWENTY_SECONDS_OR_MORE },
1397
+ );
1398
+
1399
+ /** Test max speculative chat cost */
1400
+ await newChat(page);
1401
+ const costOfNodeModulesToolResult = 0.84;
1402
+ const maxCost = costPerMsg * 2 + 0.8 * costOfNodeModulesToolResult;
1403
+ await page.getByTestId("LLMChatOptions.toggle").click();
1404
+ await page.waitForTimeout(1500);
1405
+ await fillSmartForm(page, "llm_chats", {
1406
+ max_total_cost_usd: maxCost.toString(),
1407
+ });
1408
+ await page.waitForTimeout(1500);
1409
+ await page.getByTestId("Popup.close").last().click();
1410
+ await page.waitForTimeout(1500);
1411
+ await page.getByTestId("LLMChatOptions.toggle").click();
1412
+ await expect(
1413
+ page.locator("input#llm_chats-max_total_cost_usd"),
1414
+ ).toHaveValue(maxCost.toString());
1415
+ await page.getByTestId("Popup.close").last().click();
1416
+
1417
+ /** Install electron to ensure node_modules exists */
1418
+ await execSync("npm install", {
1419
+ cwd: resolve(__dirname, "../../electron"),
1420
+ });
1421
+ await enableMCPServers(page, ["filesystem"], true);
1422
+ await fileBrowserGoToPath(page.getByTestId("FileTree"), [
1423
+ "ui",
1424
+ "electron",
1425
+ "node_modules",
1426
+ ]);
1427
+
1428
+ await page.getByTestId("MCPServerConfig.save").click();
1429
+ await page.getByTestId("Popup.close").last().click();
1430
+ await toggleMCPTools(page, ["directory_tree"], true);
1431
+ for (let step = 0; step < Math.floor(maxCost / costPerMsg); step++) {
1432
+ await page.waitForTimeout(1500);
1433
+ await sendAskLLMMessage(page, "cost", true);
1434
+ }
1435
+ await sendAskLLMMessage(page, " estimated_cost ");
1436
+ await expect(
1437
+ page.getByTestId("Chat.messageList").locator(".message").last(),
1438
+ ).toContainText(
1439
+ `Maximum total cost of the chat (${maxCost}) will be reached after sending this message`,
1440
+ getTimeout(30e3),
1441
+ );
1442
+ });
1443
+
1444
+ test("Test LLM sandbox tools", async ({ page: p }) => {
1445
+ const page = p as PageWIds;
1446
+ await loginWhenSignupIsEnabled(page);
1447
+
1448
+ await openConnection(page, "cloud");
1449
+ await page.getByTestId("AskLLM").click();
1450
+ await setPromptByText(page, "dashboard");
1451
+ /* MCP Docker sandbox */
1452
+ await newChat(page);
1453
+ /* Prompt persists from the prev chat */
1454
+ await expect(page.getByTestId("LLMChatOptions.Prompt")).toContainText(
1455
+ "Create dashboards",
1456
+ );
1457
+
1458
+ await page.getByTestId("LLMChatOptions.MCPTools").click(getTimeout(10e3));
1459
+ await page
1460
+ .locator(getDataKey("prostgles-ui"))
1461
+ .getByText("run_code_in_sandbox", { exact: true })
1462
+ .waitFor({ state: "visible", ...getTimeout(15e3) });
1463
+ await page.waitForTimeout(2e3);
1464
+ /** Tools are loaded after enabling */
1465
+ await page
1466
+ .locator(getDataKey("prostgles-ui"))
1467
+ .getByTestId("MCPServerFooterActions.refreshTools")
1468
+ .click();
1469
+ await expect(page.getByTestId("Popup.content").last()).toContainText(
1470
+ ` tools for "prostgles-ui" server`,
1471
+ );
1472
+ await page.getByText("OK", { exact: true }).click();
1473
+ await page
1474
+ .locator(getDataKey("prostgles-ui"))
1475
+ .getByText("run_code_in_sandbox", { exact: true })
1476
+ .click();
1477
+ await page.waitForTimeout(1e3);
1478
+ await page.getByTestId("Popup.close").last().click();
1479
+
1480
+ const dockerRunAndExpect = async (
1481
+ result: string[] | string,
1482
+ prepareCb: (() => Promise<void>) | undefined = undefined,
1483
+ locator: Locator | undefined = undefined,
1484
+ ) => {
1485
+ await sendAskLLMMessage(page, " mcpsandbox ");
1486
+ await page
1487
+ .getByTestId("AskLLMToolApprover.AllowOnce")
1488
+ .click({ ...TWENTY_SECONDS_OR_MORE });
1489
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1490
+ "create a container that runs",
1491
+ getTimeout(60e3),
1492
+ );
1493
+ await page.waitForTimeout(3e3);
1494
+
1495
+ await prepareCb?.();
1496
+
1497
+ await page
1498
+ .getByTestId("DockerSandboxCreateContainer.stop")
1499
+ .waitFor({ state: "detached", ...getTimeout(40e3) });
1500
+
1501
+ for (const res of Array.isArray(result) ? result : [result]) {
1502
+ await expect(
1503
+ locator ?? page.getByTestId("ToolUseMessage").last(),
1504
+ ).toContainText(res, {
1505
+ ...TWENTY_SECONDS_OR_MORE,
1506
+ });
1507
+ }
1508
+ };
1509
+ await runDbSql(page, `DROP TABLE IF EXISTS users ;`);
1510
+
1511
+ await dockerRunAndExpect(
1512
+ `Validation error for userInput definition key1: the following table names do not match any new tables or existing tables: ["users"]`,
1513
+ );
1514
+
1515
+ await runDbSql(
1516
+ page,
1517
+ `CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, username TEXT);`,
1518
+ );
1519
+
1520
+ await dockerRunAndExpect(
1521
+ `cannot execute CREATE TABLE in a read-only transaction`,
1522
+ async () => {
1523
+ await page
1524
+ .getByTestId("AskLLMToolApprover.AllowOnce")
1525
+ .click({ ...TWENTY_SECONDS_OR_MORE });
1526
+ await page.waitForTimeout(1e3);
1527
+ await page.getByTestId("AskLLMToolApprover.AllowOnce").click();
1528
+ await page
1529
+ .getByTestId("ToolUseMessage")
1530
+ .last()
1531
+ .getByTestId("FullscreenWrapper.toggleFullscreen")
1532
+ .nth(1)
1533
+ .click();
1534
+ },
1535
+ page.getByTestId("DockerSandboxCreateContainer.Logs").last(),
1536
+ );
1537
+ await runDbSql(page, `DROP TABLE users;`);
1538
+
1539
+ await page.keyboard.press("Escape");
1540
+ await page
1541
+ .getByTestId("LLMChatOptions.DatabaseAccess")
1542
+ .click(TWENTY_SECONDS_OR_MORE);
1543
+
1544
+ await runDbSql(
1545
+ page,
1546
+ `CREATE TABLE IF NOT EXISTS users (
1547
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
1548
+ type TEXT NOT NULL DEFAULT 'regular',
1549
+ username TEXT NOT NULL UNIQUE,
1550
+ created_at TIMESTAMP DEFAULT NOW()
1551
+ );
1552
+ INSERT INTO users (username)
1553
+ VALUES ('fresh_user') ON CONFLICT DO NOTHING;
1554
+ `,
1555
+ );
1556
+ await page.getByTestId("DatabaseAccessEditor.Mode").click();
1557
+
1558
+ await page
1559
+ .getByTestId("DatabaseAccessEditor.Mode")
1560
+ .locator(getDataLabel("None"))
1561
+ .click();
1562
+ await page.waitForTimeout(500);
1563
+ await expect(page.getByTestId("DatabaseAccessEditor.Mode")).toContainText(
1564
+ "None",
1565
+ );
1566
+ await page.getByTestId("DatabaseAccessEditor.Mode").click();
1567
+ await page
1568
+ .getByTestId("DatabaseAccessEditor.Mode")
1569
+ .locator(getDataLabel("Run readonly SQL"))
1570
+ .click();
1571
+
1572
+ /** Auto approve to ensure the container can run the query */
1573
+ await page.getByLabel("Auto approve", { exact: true }).last().click();
1574
+ await page.getByTestId("Popup.close").last().click();
1575
+ await dockerRunAndExpect(
1576
+ [
1577
+ `username: 'fresh_user'`,
1578
+ `cannot execute CREATE TABLE in a read-only transaction`,
1579
+ ],
1580
+ async () => {
1581
+ await page
1582
+ .getByTestId("ToolUseMessage")
1583
+ .last()
1584
+ .getByTestId("FullscreenWrapper.toggleFullscreen")
1585
+ .nth(1)
1586
+ .click();
1587
+ },
1588
+ page.getByTestId("DockerSandboxCreateContainer.Logs").last(),
1589
+ );
1590
+ await page.keyboard.press("Escape");
1591
+
1592
+ /** Test stopping chat */
1593
+ await newChat(page);
1594
+ await sendAskLLMMessage(page, " longresponse ", {
1595
+ onAfterSend: async () => {
1596
+ await page.getByTestId("Chat.sendStop").click();
1597
+ },
1598
+ });
1599
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1600
+ `longresponse`,
1601
+ );
1602
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1603
+ `aborted by user`,
1604
+ );
1605
+
1606
+ /** Test parallel tool use single auto-approve */
1607
+ await newChat(page);
1608
+ await sendAskLLMMessage(page, " parallel_calls ");
1609
+
1610
+ await expect(
1611
+ page.getByTestId("ToolUseMessage.toggleGroup").last(),
1612
+ ).toContainText("3 tool calls");
1613
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1614
+ "Tool call failed. Will not retry",
1615
+ getTimeout(30e3),
1616
+ );
1617
+ await page.getByTestId("ToolUseMessage.toggleGroup").last().click();
1618
+ await expect(
1619
+ page
1620
+ .getByTestId("Chat.messageList")
1621
+ .getByText(
1622
+ 'Tool name "web--fetch" is not allowed. Must enable it for this chat',
1623
+ ),
1624
+ ).toHaveCount(3, getTimeout(30e3));
1625
+
1626
+ await newChat(page);
1627
+ await toggleMCPTools(page, ["fetch"]);
1628
+ await sendAskLLMMessage(page, " parallel_calls ");
1629
+
1630
+ /** Should not request approval for the other 2 requests */
1631
+ await page.getByTestId("AskLLMToolApprover.AllowAlways").click();
1632
+
1633
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1634
+ "Fetched in parallel successfully",
1635
+ getTimeout(30e3),
1636
+ );
1637
+ await page.getByTestId("ToolUseMessage.toggleGroup").last().click();
1638
+
1639
+ await expect(
1640
+ page.locator(
1641
+ getCommandElemSelector("ToolUseMessage.toggle") +
1642
+ `[data-color="default"]`,
1643
+ ),
1644
+ ).toHaveCount(3, getTimeout(30e3));
1645
+
1646
+ await newChat(page);
1647
+ await toggleMCPTools(page, ["websearch", "get_snapshot"]);
1648
+ await page.waitForTimeout(7e3); // wait for the server to start
1649
+ await sendAskLLMMessage(page, " websearch ");
1650
+ await page
1651
+ .getByTestId("AskLLMToolApprover.AllowAlways")
1652
+ .click(TWENTY_SECONDS_OR_MORE);
1653
+ await page.getByTestId("AskLLMToolApprover.AllowAlways").click();
1654
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1655
+ "Search done.",
1656
+ getTimeout(30e3),
1657
+ );
1658
+
1659
+ await page.getByTestId("ToolUseMessage.toggleGroup").click();
1660
+ await page.getByTestId("ToolUseMessage.toggle").first().click();
1661
+ const text = await page.getByTestId("ToolUseMessage").first().textContent();
1662
+ if (text?.includes("No results found.")) {
1663
+ // Probably due to engines limiting searches
1664
+ } else if (text?.includes("https://prostgles.com/")) {
1665
+ // Websearch results changing and not a fail
1666
+ } else {
1667
+ await expect(page.getByTestId("ToolUseMessage").first()).toContainText(
1668
+ "https:",
1669
+ // "https://www.postgresql.org/",
1670
+ );
1671
+ }
1672
+ await page.getByTestId("ToolUseMessage.toggle").first().click();
1673
+ await page.getByTestId("ToolUseMessage.toggle").last().click();
1674
+ await expect(page.getByTestId("ToolUseMessage").last()).toContainText(
1675
+ "Page Title: Prostgles UI",
1676
+ );
1677
+
1678
+ /** Speech to text */
1679
+ await speechToTextTest(page);
1680
+
1681
+ /** Create component */
1682
+ await newChat(page);
1683
+ await setPromptByText(page, "Web app development", false);
1684
+ /** The web app must be created from template */
1685
+ await page.getByTestId("WebAppConfig.createFromTemplate").click();
1686
+ await page.getByTestId("Btn.ClickConfirmation.Confirm").click();
1687
+ /** Page will reload */
1688
+ await page.waitForEvent("load");
1689
+ await page.getByTestId("AskLLM").click();
1690
+ await sendAskLLMMessage(
1691
+ page,
1692
+ " I need you to create a user list component ",
1693
+ );
1694
+ await page
1695
+ .getByTestId("AskLLMToolApprover.AllowAlways")
1696
+ .click(getTimeout(10e3));
1697
+ });
1698
+
1699
+ test("Agentic workflow", async ({ page: p }) => {
1700
+ const page = p as PageWIds;
1701
+ if (process.env.CI) {
1702
+ test.setTimeout(10 * 60e3);
1703
+ }
1704
+ await loginWhenSignupIsEnabled(page);
1705
+
1706
+ await openConnection(page, "cloud");
1707
+ await closeWorkspaceWindows(page);
1708
+ await page.getByTestId("AskLLM").click();
1709
+
1710
+ await setupAskLLMToolUse(page);
1711
+
1712
+ /** Test ask tool */
1713
+ await newChat(page);
1714
+ await sendAskLLMMessage(page, " ask_tool ");
1715
+ await page.getByTestId("AskUserQuestions").getByText("Red").first().click();
1716
+ await page
1717
+ .getByTestId("AskUserQuestions")
1718
+ .getByText("Yellow")
1719
+ .nth(1)
1720
+ .click();
1721
+ await page.getByTestId("AskUserQuestions").getByText("Blue").nth(1).click();
1722
+ await page
1723
+ .getByTestId("AskUserQuestions")
1724
+ .locator(getDataKey("table-columns"))
1725
+ .click();
1726
+ await page
1727
+ .locator(getDataKey("table-columns"))
1728
+ .locator(getDataKey("type"))
1729
+ .click();
1730
+ await page.keyboard.press("Escape");
1731
+ await page
1732
+ .getByTestId("AskUserQuestions")
1733
+ .locator(getDataKey("table-name"))
1734
+ .click();
1735
+ await page
1736
+ .locator(getDataKey("table-name"))
1737
+ .locator(getDataKey("receipts"))
1738
+ .click();
1739
+ await page
1740
+ .locator(getDataKey("free-text"))
1741
+ .locator("input")
1742
+ .fill("some free text");
1743
+ await page.getByTestId("AskUserQuestions.confirm").click();
1744
+ await expect(
1745
+ page.getByTestId("AskUserQuestions.confirm"),
1746
+ ).not.toBeAttached();
1747
+ const buttons = page.getByTestId("AskUserQuestions").locator("button");
1748
+ for (const btn of await buttons.all()) {
1749
+ await expect(btn).toBeDisabled();
1750
+ }
1751
+ await expect(page.getByTestId("AskUserQuestions")).toContainText(
1752
+ "some free text",
1753
+ );
1754
+
1755
+ await newChat(page);
1756
+ await sendAskLLMMessage(page, " ask_tool_invalid ");
1757
+ await page.waitForTimeout(1e3);
1758
+ await expect(
1759
+ page.getByTestId("AskUserQuestions").locator("button"),
1760
+ ).not.toBeAttached();
1761
+
1762
+ await newChat(page);
1763
+ await setPromptByText(page, "Create workflow");
1764
+
1765
+ /** Cleanup for any reruns */
1766
+ await page.waitForTimeout(1e3);
1767
+ await runDbSql(
1768
+ page,
1769
+ `
1770
+ DROP TABLE IF EXISTS new_users;
1771
+ DELETE FROM users WHERE type = 'from-agent';
1772
+ `,
1773
+ );
1774
+ await page.waitForTimeout(1e3);
1775
+ await sendAskLLMMessage(page, " agentic_workflow ");
1776
+
1777
+ const startWorkFlowAndExpectError = async (errorMessage: string) => {
1778
+ await page.getByTestId("AgenticWorkflow.start").click(getTimeout(60e3));
1779
+ await expect(page.getByTestId("Alert")).toContainText(
1780
+ errorMessage,
1781
+ getTimeout(60e3),
1782
+ );
1783
+ await page.getByText("OK", { exact: true }).click();
1784
+ };
1785
+
1786
+ /** Fill user input form */
1787
+ await startWorkFlowAndExpectError(
1788
+ `Missing required user input: "Enum value"`,
1789
+ );
1790
+ await page.locator(getDataKey("enum")).click();
1791
+ await page.locator(`[data-key="value1"]`).last().click();
1792
+
1793
+ await startWorkFlowAndExpectError(
1794
+ `Missing required user input: "Sort column"`,
1795
+ );
1796
+ await page.locator(getDataKey("custom") + " input").fill("a");
1797
+
1798
+ const selectFileOrFolderPath = async (fileTreeKey: string) => {
1799
+ const capitalizeFirstLetter = (s: string) =>
1800
+ s.charAt(0).toUpperCase() + s.slice(1);
1801
+ const label = capitalizeFirstLetter(fileTreeKey.replace(/-/g, " "));
1802
+ await startWorkFlowAndExpectError(
1803
+ `Missing required user input: ${JSON.stringify(label)}`,
1804
+ );
1805
+ const isMultiple = fileTreeKey.endsWith("s");
1806
+ await page.locator(getDataKey(fileTreeKey)).click();
1807
+ const path =
1808
+ fileTreeKey.includes("file") ?
1809
+ ["ui", "client", "package.json"]
1810
+ : ["ui", "client", "src"];
1811
+ await fileBrowserGoToPath(page.getByTestId("FileTree").first(), path);
1812
+ if (isMultiple) {
1813
+ await page.getByText("Done").first().click();
1814
+ }
1815
+ };
1816
+
1817
+ await selectFileOrFolderPath("file-path");
1818
+ await selectFileOrFolderPath("file-paths");
1819
+
1820
+ await startWorkFlowAndExpectError(
1821
+ `Missing required user input: "Table name"`,
1822
+ );
1823
+ await page.locator(getDataKey("table-name")).click();
1824
+ await page.locator(`[data-key="example_table"]`).last().click();
1825
+
1826
+ await selectFileOrFolderPath("folder-path");
1827
+ await selectFileOrFolderPath("folder-paths");
1828
+
1829
+ await startWorkFlowAndExpectError(
1830
+ `Missing required user input: "Table column"`,
1831
+ );
1832
+ await page.locator(getDataKey("table-column")).click();
1833
+ await page.locator(`[data-key="id"]`).last().click();
1834
+
1835
+ await startWorkFlowAndExpectError(
1836
+ `Missing required user input: "Users filter"`,
1837
+ );
1838
+ await page.getByTestId("RenderFilter.edit").click();
1839
+ await page.getByTestId("SmartAddFilter").click();
1840
+ await page.locator(getDataKey("type")).last().click();
1841
+ await page.getByTestId("SearchList.Input").last().click();
1842
+ await page.locator(`[data-label="regular"]`).first().click();
1843
+ await page.getByTestId("RenderFilter.done").click();
1844
+
1845
+ await startWorkFlowAndExpectError(
1846
+ `Missing required user input: "Table and column"`,
1847
+ );
1848
+ await page.locator(getDataKey("table-and-column")).click();
1849
+ await page.locator(`[data-label="receipts.amount"]`).click();
1850
+
1851
+ await startWorkFlowAndExpectError(
1852
+ `Missing required user input: "Table column value"`,
1853
+ );
1854
+ await page.locator(getDataKey("table-column-value")).click();
1855
+ await page.locator(`[data-key="regular"]`).last().click();
1856
+
1857
+ await selectFileOrFolderPath("file-or-folder-path");
1858
+
1859
+ await startWorkFlowAndExpectError(
1860
+ `Missing required user input: "Table column values"`,
1861
+ );
1862
+ await page.locator(getDataKey("table-column-values")).click();
1863
+ await page.locator(`[data-key="regular"]`).last().click();
1864
+ await page.keyboard.press("Escape"); // close multi select dropdown
1865
+
1866
+ await selectFileOrFolderPath("file-or-folder-paths");
1867
+
1868
+ await page.waitForTimeout(1e3);
1869
+ await page.getByTestId("AgenticWorkflow.start").click();
1870
+
1871
+ /** Progress bar works */
1872
+ await expect(page.getByTestId("Chat.messageList")).toContainText(
1873
+ "Processing user 2/",
1874
+ getTimeout(30e3),
1875
+ );
1876
+
1877
+ await page.getByTestId("AgenticWorkflow.stop").click();
1878
+ await expect(page.getByTestId("AgenticWorkflowActions")).toContainText(
1879
+ "Stopped",
1880
+ getTimeout(10e3),
1881
+ );
1882
+
1883
+ const runWorkflowAndExpectSuccess = async (
1884
+ shownText: string | string[] = ["<!DOCTYPE html>"],
1885
+ ) => {
1886
+ await page.getByTestId("AgenticWorkflow.start").click(getTimeout(30e3));
1887
+
1888
+ await expect(page.locator(".SuccessMessage")).toContainText(
1889
+ "Workflow finished successfully",
1890
+ getTimeout(120e3),
1891
+ );
1892
+
1893
+ await page
1894
+ .getByTestId("AgenticWorkflow")
1895
+ .getByTestId("FullscreenWrapper.toggleFullscreen")
1896
+ .filter({ visible: true })
1897
+ .click();
1898
+ for (const text of Array.isArray(shownText) ? shownText : [shownText]) {
1899
+ await expect(
1900
+ page.getByTestId("AgenticWorkflow").filter({ visible: true }).last(),
1901
+ ).toContainText(text);
1902
+ }
1903
+ await page
1904
+ .getByTestId("FullscreenWrapper.toggleFullscreen")
1905
+ .filter({ visible: true })
1906
+ .last()
1907
+ .click();
1908
+ };
1909
+
1910
+ /** Prevent constraint fail error */
1911
+ await runDbSql(
1912
+ page,
1913
+ `
1914
+ DROP TABLE IF EXISTS new_users;
1915
+ DELETE FROM users WHERE type = 'from-agent';
1916
+ `,
1917
+ );
1918
+ await page.waitForTimeout(1e3);
1919
+ await runWorkflowAndExpectSuccess([
1920
+ "App.css",
1921
+ "loaders.gl",
1922
+ "Failed to remove package.json",
1923
+ ]);
1924
+
1925
+ await newChat(page);
1926
+ await sendAskLLMMessage(page, " agentic_workflow_filesystem ");
1927
+ await page
1928
+ .locator(getDataKey("filesystem"))
1929
+ .getByTestId("McpToolAccess.configure")
1930
+ .click(getTimeout(60e3));
1931
+ await fileBrowserGoToPath(page.getByTestId("FileTree"), [
1932
+ "ui",
1933
+ "e2e",
1934
+ "demo",
1935
+ ]);
1936
+ await page.getByText("Enable", { exact: true }).click();
1937
+ await page.waitForTimeout(1e3);
1938
+
1939
+ await runWorkflowAndExpectSuccess([
1940
+ "forceConsistentCasingInFileNames",
1941
+ "tsconfig.base.json",
1942
+ ]);
1943
+
1944
+ await page.waitForTimeout(1e3);
1945
+ await newChat(page);
1946
+ await sendAskLLMMessage(page, " agentic_workflow_noinput ");
1947
+ await runWorkflowAndExpectSuccess();
1948
+
1949
+ /** Activity agent chats */
1950
+ await page.locator(getDataKey("Activity")).click(getTimeout(10e3));
1951
+ await page
1952
+ .getByTestId("AgenticWorkflow")
1953
+ .getByTestId("AgenticWorkflow.openChat")
1954
+ .first()
1955
+ .click();
1956
+ const agentChant = page.getByTestId("AskLLM.popup").nth(1);
1957
+ await expect(agentChant.getByTestId("Chat.messageList")).toContainText(
1958
+ "Agent goal reached",
1959
+ );
1960
+ await agentChant.getByTestId("Popup.close").click();
1961
+
1962
+ /** Activity tool calls details */
1963
+ await page
1964
+ .getByTestId("AgenticWorkflow")
1965
+ .getByTestId("AgenticWorkflow.openToolCall")
1966
+ .getByText("fetch")
1967
+ .click();
1968
+ await expect(page.getByTestId("Popup.content").last()).toContainText(
1969
+ `https://www.prostgles.com`,
1970
+ );
1971
+ await page.getByTestId("Popup.close").last().click();
1972
+
1973
+ /** Schema drift works */
1974
+ const applySchemaDriftAndStartWorkflow = async () => {
1975
+ await runDbSql(
1976
+ page,
1977
+ `
1978
+ ALTER TABLE new_users DROP COLUMN username;
1979
+ `,
1980
+ );
1981
+ await page.waitForTimeout(2e3);
1982
+ await page.getByTestId("AgenticWorkflow.start").click();
1983
+ await expect(
1984
+ page.getByTestId("AgenticWorkflowSchemaDrift"),
1985
+ ).toContainText(
1986
+ `There are tables created in this worflow that have since changed`,
1987
+ );
1988
+ };
1989
+ await applySchemaDriftAndStartWorkflow();
1990
+ await expect(page.getByTestId("AgenticWorkflowSchemaDrift")).toContainText(
1991
+ `ADD COLUMN username text`,
1992
+ );
1993
+ await page
1994
+ .getByTestId("AgenticWorkflowSchemaDrift")
1995
+ .locator(getDataKey("workflow-schema"))
1996
+ .click();
1997
+ await expect(page.getByTestId("AgenticWorkflowSchemaDrift")).toContainText(
1998
+ `CREATE TABLE IF NOT EXISTS new_users`,
1999
+ );
2000
+
2001
+ await page.getByTestId("AgenticWorkflowSchemaDrift.applyPatches").click();
2002
+ await page.getByTestId("Btn.ClickConfirmation.Confirm").click();
2003
+ await page.waitForTimeout(2e3);
2004
+ await runWorkflowAndExpectSuccess();
2005
+
2006
+ await runDbSql(page, `DELETE FROM users`); // reduce log size for next test
2007
+ await applySchemaDriftAndStartWorkflow();
2008
+ await page
2009
+ .getByTestId("AgenticWorkflowSchemaDrift.dropWorkflowTables")
2010
+ .click();
2011
+ await page.getByTestId("Btn.ClickConfirmation.Confirm").click();
2012
+ await page.waitForTimeout(2e3);
2013
+ await runWorkflowAndExpectSuccess();
2014
+
2015
+ await page.waitForTimeout(1e3);
2016
+ await newChat(page);
2017
+ await sendAskLLMMessage(page, " agentic_workflow_clashing ");
2018
+ await expect(
2019
+ page.getByTestId("AgenticWorkflow.validationErrorLogs"),
2020
+ ).toContainText(`relation "users" already exists`, getTimeout(30e3));
2021
+
2022
+ await newChat(page);
2023
+ await sendAskLLMMessage(page, " agentic_workflow_invalidTable ");
2024
+ await expect(
2025
+ page.getByTestId("AgenticWorkflow.validationErrorLogs"),
2026
+ ).toContainText(
2027
+ // `Validation error for databaseHandler usage: the following table names do not match any new tables or existing tables: ["invalid_table"]`,
2028
+ `Table "invalid_table" is used in the workflow but not included in tablePermissions`,
2029
+ getTimeout(30e3),
2030
+ );
2031
+
2032
+ await page.waitForTimeout(1e3);
2033
+ await newChat(page);
2034
+ await sendAskLLMMessage(page, " agentic_workflow_invalidPermissionTable ");
2035
+ await expect(
2036
+ page.getByTestId("AgenticWorkflow.validationErrorLogs"),
2037
+ ).toContainText(
2038
+ `"invalid_table" does not match any new or existing tables`,
2039
+ getTimeout(30e3),
2040
+ );
2041
+
2042
+ await page.waitForTimeout(1e3);
2043
+ await newChat(page);
2044
+ await sendAskLLMMessage(page, " agentic_workflow_agent_failure ");
2045
+ await page.getByTestId("AgenticWorkflow.start").click(getTimeout(90e3));
2046
+ await expect(page.getByTestId("Alert")).toContainText(
2047
+ `Agentic workflow container stopped with status: error`,
2048
+ getTimeout(30e3),
2049
+ );
2050
+ await page.getByText("OK", { exact: true }).click();
2051
+ await expect(page.getByTestId("AgenticWorkflow")).toContainText(
2052
+ `The agent failed to complete the task`,
2053
+ );
2054
+ await expect(page.getByTestId("AgenticWorkflow")).not.toContainText(
2055
+ `"<!DOCTYPE html>"`,
2056
+ );
2057
+ });
2058
+
2059
+ test("Create agent", async ({ page: p }) => {
2060
+ const page = p as PageWIds;
2061
+
2062
+ await loginWhenSignupIsEnabled(page);
2063
+ await openConnection(page, "cloud");
2064
+ await closeWorkspaceWindows(page);
2065
+ await page.getByTestId("AskLLM").click();
2066
+
2067
+ await setupAskLLMToolUse(page);
2068
+
2069
+ /** Test ask tool */
2070
+ await newChat(page);
2071
+
2072
+ await sendAskLLMMessage(page, " create_agent ");
2073
+ await page
2074
+ .getByTestId("AskLLMToolApprover.AllowOnce")
2075
+ .click(TWENTY_SECONDS_OR_MORE);
2076
+ await page
2077
+ .getByTestId("Agent")
2078
+ .getByText("View activity", { exact: true })
2079
+ .click(TWENTY_SECONDS_OR_MORE);
2080
+
2081
+ await expect(page.getByTestId("Popup.content").last()).toContainText(
2082
+ "Agent goal reached",
2083
+ getTimeout(30e3),
2084
+ );
2085
+ });
2086
+
2087
+ test("Remote MCP server", async ({ page: p }) => {
2088
+ const page = p as PageWIds;
2089
+ const imageName = "mcp-keycloak";
2090
+ const containerName = "mcp-keycloak-e2e";
2091
+
2092
+ execSync(
2093
+ `docker build -t ${imageName} ./e2e/tests/testAskLLM/mockRemoteMcp`,
2094
+ { cwd: ROOT_DIR, stdio: "inherit" },
2095
+ );
2096
+
2097
+ const container = spawn(
2098
+ "docker",
2099
+ [
2100
+ "run",
2101
+ "--rm",
2102
+ "--name",
2103
+ containerName,
2104
+ "-p",
2105
+ "8080:8080",
2106
+ "-p",
2107
+ "3000:3000",
2108
+ imageName,
2109
+ ],
2110
+ { cwd: process.cwd(), stdio: "inherit" },
2111
+ );
2112
+ try {
2113
+ test.setTimeout(4 * 60_000);
2114
+
2115
+ await expect
2116
+ .poll(
2117
+ async () => {
2118
+ try {
2119
+ const ready = await Promise.all([
2120
+ page.request.get(
2121
+ "http://localhost:3000/.well-known/oauth-protected-resource/mcp",
2122
+ ),
2123
+ page.request.get(
2124
+ "http://localhost:8080/.well-known/oauth-authorization-server/realms/mcp",
2125
+ ),
2126
+ ]);
2127
+
2128
+ return ready.every((response) => response.status() === 200);
2129
+ } catch {
2130
+ return false;
2131
+ }
2132
+ },
2133
+ {
2134
+ timeout: 2 * 60_000,
2135
+ intervals: [500, 1_000, 2_000],
2136
+ },
2137
+ )
2138
+ .toBe(true);
2139
+ await loginWhenSignupIsEnabled(page);
2140
+ await goTo(page, "/server-settings?section=mcpServers");
2141
+
2142
+ await page.getByTestId("AddMCPServer.Open").click();
2143
+ await monacoType(
2144
+ page,
2145
+ ".SmartCodeEditor",
2146
+ JSON.stringify(
2147
+ {
2148
+ mcpServers: {
2149
+ mock: { url: "http://localhost:3000/mcp" },
2150
+ },
2151
+ },
2152
+ null,
2153
+ 2,
2154
+ ),
2155
+ { deleteAllAndFill: true, pressAfterTyping: ["Backspace"] },
2156
+ );
2157
+
2158
+ await page.getByTestId("AddMCPServer.Add").click();
2159
+ await page.getByTestId("AddMCPServer.Add").waitFor({ state: "detached" });
2160
+
2161
+ const serverCard = page
2162
+ .getByTestId("SmartCardList")
2163
+ .locator(getDataKey("mock"));
2164
+ await serverCard.getByTitle("Press to enable").click();
2165
+
2166
+ /** General info */
2167
+ await expect(
2168
+ page.getByTestId("McpServerOAuthConfigTopControls.ShowServerInfo"),
2169
+ ).toHaveAttribute("title", "Show server info", { ignoreCase: false });
2170
+ await page
2171
+ .getByTestId("McpServerOAuthConfigTopControls.ShowServerInfo")
2172
+ .click();
2173
+ await expect(page.getByTestId("Popup.content").last()).toContainText(
2174
+ "authorization_endpoint",
2175
+ );
2176
+ await page.getByTestId("Popup.close").last().click();
2177
+
2178
+ /** DCR */
2179
+ await page
2180
+ .getByTestId("McpServerOAuthConfigActions.LoginWithOAuth")
2181
+ .click(TWENTY_SECONDS_OR_MORE);
2182
+ const [popup] = await Promise.all([
2183
+ page.waitForEvent("popup"),
2184
+ page
2185
+ .getByTestId(
2186
+ "McpServerOAuthConfigAuthorizeUrlBtn.OpenAuthorizationUrl",
2187
+ )
2188
+ .click(),
2189
+ ]);
2190
+ await popup.waitForLoadState("load");
2191
+ await popup.locator("#username").fill("admin1");
2192
+ await popup.locator("#password").fill("admin1");
2193
+ await popup.locator("button[name=login]").click();
2194
+ await popup.locator("button[name=accept]").click(TWENTY_SECONDS_OR_MORE);
2195
+ await popup.close();
2196
+
2197
+ const saveConfigAndRefreshToolsAndDeleteConfig = async () => {
2198
+ await expect(
2199
+ page.getByTestId("McpServerOAuthConfigActions.connectionToggle"),
2200
+ ).toHaveText("Connected", { ...TWENTY_SECONDS_OR_MORE });
2201
+ await page.getByTestId("MCPServerConfig.save").click();
2202
+ await page.waitForTimeout(1e3);
2203
+ await page
2204
+ .locator(
2205
+ getDataKey("mock") +
2206
+ " " +
2207
+ getCommandElemSelector("MCPServerFooterActions.refreshTools"),
2208
+ )
2209
+ .click(TWENTY_SECONDS_OR_MORE);
2210
+ await expect(page.getByTestId("Popup.content").last()).toContainText(
2211
+ ` tool for "mock" server`,
2212
+ );
2213
+ await page.getByText("OK", { exact: true }).click();
2214
+ await page
2215
+ .locator(
2216
+ getDataKey("mock") +
2217
+ " " +
2218
+ getCommandElemSelector("MCPServerConfigButton"),
2219
+ )
2220
+ .click();
2221
+ await page.getByText("Delete config", { exact: true }).click();
2222
+ };
2223
+ await saveConfigAndRefreshToolsAndDeleteConfig();
2224
+
2225
+ const enableServer = async () => {
2226
+ await page.waitForTimeout(3e3);
2227
+ await page
2228
+ .locator(
2229
+ getDataKey("mock") + " " + getCommandElemSelector("SwitchToggle"),
2230
+ )
2231
+ .click();
2232
+ };
2233
+
2234
+ const setAuthMode = async (
2235
+ mode: "bearer" | "client_credentials" | "authorization_code" | "cimd",
2236
+ ) => {
2237
+ await page
2238
+ .getByTestId("McpServerOAuthConfigTopControls.authMode")
2239
+ .click();
2240
+ await page
2241
+ .getByTestId("McpServerOAuthConfigTopControls.authMode")
2242
+ .locator(getDataKey(mode))
2243
+ .click();
2244
+ };
2245
+
2246
+ /** Bearer */
2247
+ await enableServer();
2248
+ await setAuthMode("bearer");
2249
+ await page.getByLabel("Bearer token").fill("test-token");
2250
+ await page
2251
+ .getByTestId("McpServerOAuthConfigActions.LoginWithOAuth")
2252
+ .click();
2253
+ await saveConfigAndRefreshToolsAndDeleteConfig();
2254
+
2255
+ /** authorization_code */
2256
+ await enableServer();
2257
+ await setAuthMode("authorization_code");
2258
+ await page.getByLabel("Client Id").fill("static-client");
2259
+ await page.getByLabel("Client Secret").fill("static-secret");
2260
+ await page
2261
+ .getByTestId("McpServerOAuthConfigActions.LoginWithOAuth")
2262
+ .click();
2263
+
2264
+ const [popup2] = await Promise.all([
2265
+ page.waitForEvent("popup"),
2266
+ page
2267
+ .getByTestId(
2268
+ "McpServerOAuthConfigAuthorizeUrlBtn.OpenAuthorizationUrl",
2269
+ )
2270
+ .click(),
2271
+ ]);
2272
+ await popup2.waitForLoadState("load");
2273
+ await popup2.locator("button[name=accept]").click(TWENTY_SECONDS_OR_MORE);
2274
+ await popup2.close();
2275
+ await saveConfigAndRefreshToolsAndDeleteConfig();
2276
+
2277
+ /** client credentials */
2278
+ await enableServer();
2279
+ await setAuthMode("client_credentials");
2280
+ await page.getByLabel("Client Id").fill("static-client");
2281
+ await page.getByLabel("Client Secret").fill("static-secret");
2282
+ await page
2283
+ .getByTestId("McpServerOAuthConfigActions.LoginWithOAuth")
2284
+ .click();
2285
+ await saveConfigAndRefreshToolsAndDeleteConfig();
2286
+
2287
+ /** TODO: CIMD */
2288
+ // await enableServer();
2289
+ // await setAuthMode("cimd");
2290
+ // const redirectUri = await page
2291
+ // .locator(`[data-label="Redirect URL"] .input-wrapper`)
2292
+ // .textContent();
2293
+ // if (!redirectUri) throw new Error("Redirect URI not found");
2294
+ // const searchParams = new URLSearchParams({ redirectUri });
2295
+ // await fetch(
2296
+ // "http://localhost:3000/set_redirect_uri_for_test?" +
2297
+ // searchParams.toString(),
2298
+ // );
2299
+ // await page
2300
+ // .getByLabel("Client metadata URL")
2301
+ // .fill("http://localhost:3000/metadata.json");
2302
+ // await saveConfigAndRefreshToolsAndDeleteConfig();
2303
+ } finally {
2304
+ container.kill("SIGTERM");
2305
+ execSync(`docker rm -f ${containerName}`, { stdio: "ignore" });
2306
+ }
2307
+ });
2308
+
2309
+ test("Disable signups", async ({ page: p }) => {
2310
+ const page = p as PageWIds;
2311
+ await loginWhenSignupIsEnabled(page);
2312
+
2313
+ /** Disable signups */
2314
+ await goTo(page, "/server-settings");
2315
+ await page.locator(`[data-key="auth"]`).click();
2316
+ await page.getByTestId("EmailAuthSetup").locator("button").click();
2317
+ await page.getByText("Enable").click();
2318
+ await page.getByText("Save").click();
2319
+
2320
+ /** Revert LLM signup */
2321
+ await runDbsSql(
2322
+ page,
2323
+ `
2324
+ UPDATE global_settings
2325
+ SET prostgles_registration = null
2326
+ `,
2327
+ );
2328
+ await runDbsSql(
2329
+ page,
2330
+ `
2331
+ DELETE FROM llm_credentials;
2332
+ TRUNCATE llm_chats CASCADE;
2333
+ `,
2334
+ );
2335
+ });
2336
+
2337
+ test("Limit login attempts max failed limit", async ({ browser }) => {
2338
+ const page: PageWIds = await browser.newPage({
2339
+ extraHTTPHeaders: {
2340
+ "x-real-ip": "1.1.1.1",
2341
+ },
2342
+ });
2343
+
2344
+ await login(page, USERS.test_user, "/login");
2345
+ await page.waitForTimeout(1500);
2346
+
2347
+ await runDbsSql(
2348
+ page,
2349
+ `DELETE FROM login_attempts; UPDATE database_configs SET login_rate_limit = '{"groupBy": "x-real-ip", "maxAttemptsPerHour": 5}'`,
2350
+ );
2351
+ await page.request.post("/logout");
2352
+ await goTo(page, "/login");
2353
+ const loginAndExpectError = async (
2354
+ errorMessage: string,
2355
+ user: string,
2356
+ lpage: PageWIds,
2357
+ ) => {
2358
+ await lpage.waitForTimeout(1e3);
2359
+ await fillLoginFormAndSubmit(lpage, user);
2360
+ await lpage
2361
+ .getByTestId("Login.error")
2362
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2363
+ await expect(
2364
+ await lpage.getByTestId("Login.error").textContent(),
2365
+ ).toContain(errorMessage);
2366
+ };
2367
+ for (let i = 0; i < 5; i++) {
2368
+ await page.reload();
2369
+ await loginAndExpectError("Invalid credentials", "invalid", page);
2370
+ }
2371
+ await loginAndExpectError("Too many failed ", "invalid", page);
2372
+ await loginAndExpectError("Too many failed ", USERS.default_user, page);
2373
+
2374
+ /** TODO: finish cookie rate test after playwright ws headers fix
2375
+ * https://github.com/microsoft/playwright/issues/28948
2376
+ */
2377
+ // const newPageC: PageWIds = await browser.newPage({
2378
+ // extraHTTPHeaders: {
2379
+ // 'x-real-ip': '1.1.1.2'
2380
+ // }
2381
+ // });
2382
+ // await login(newPageC, USERS.test_user, "/");
2383
+ // await newPageC.waitForTimeout(1e3);
2384
+ // await newPageC.getByRole('link', { name: 'Connections' }).click();
2385
+ // await goTo(newPageC, "/logout");
2386
+ // for(let i = 0; i < 5; i++){
2387
+ // const newPageCc: PageWIds = await browser.newPage({
2388
+ // extraHTTPHeaders: {
2389
+ // 'x-real-ip': '1.1.1.22'
2390
+ // },
2391
+ // storageState: {
2392
+ // cookies: [
2393
+ // { name: 'sid_token', value: "random"+i, path: "/", domain: "localhost", httpOnly: true, sameSite: "Lax", expires: Math.round((Date.now() + 36e4)/1e3), secure: false }
2394
+ // ],
2395
+ // origins: []
2396
+ // }
2397
+ // });
2398
+ // // await newPageCc.context().addCookies([
2399
+ // // { name: 'sid_token', value: "random"+i, path: "/", domain: "localhost", httpOnly: true, sameSite: "Lax" }
2400
+ // // ]);
2401
+ // await goTo(newPageCc, "/");
2402
+ // await newPageCc.waitForTimeout(1e3);
2403
+ // await newPageCc.close();
2404
+ // }
2405
+ // await loginAndExpectError("Too many failed attempts", USERS.default_user, newPageC);
2406
+
2407
+ /** Revert */
2408
+ const newPage: PageWIds = await browser.newPage({
2409
+ extraHTTPHeaders: {
2410
+ "x-real-ip": "1.1.1.3",
2411
+ },
2412
+ });
2413
+ await login(newPage, USERS.test_user, "/login");
2414
+ await newPage.waitForTimeout(1500);
2415
+ await runDbsSql(
2416
+ newPage,
2417
+ `DELETE FROM login_attempts; UPDATE database_configs SET login_rate_limit = '{"groupBy": "ip", "maxAttemptsPerHour": 5}'`,
2418
+ );
2419
+ });
2420
+
2421
+ test("Create db with owner", async ({ page: p }) => {
2422
+ const page = p as PageWIds;
2423
+ await login(page);
2424
+ const dbName = "db_with_owner";
2425
+ await createDatabase(dbName, page, false, { name: dbName, pass: dbName });
2426
+ const currUser = await runDbSql(
2427
+ page,
2428
+ `SELECT current_user`,
2429
+ {},
2430
+ { returnType: "value" },
2431
+ );
2432
+ await expect(currUser).toEqual(dbName);
2433
+ });
2434
+
2435
+ test("Ensure realtime works and is resilient to schema change", async ({
2436
+ page: p,
2437
+ }) => {
2438
+ const page = p as PageWIds;
2439
+ await login(page);
2440
+ const dbName = "db_with_owner";
2441
+ await openConnection(page, "db_with_owner");
2442
+ await runDbSql(
2443
+ page,
2444
+ `DROP TABLE IF EXISTS "table_name";
2445
+ DROP TABLE IF EXISTS "MySchema"."MyTable";
2446
+ DROP SCHEMA IF EXISTS "MySchema" CASCADE;`,
2447
+ );
2448
+ /** Ensure realtime works and is resilient to schema change */
2449
+ const createTableQuery = `CREATE TABLE "table_name" ( id SERIAL PRIMARY KEY, title VARCHAR(250), gencol TEXT GENERATED ALWAYS AS ( title || id::TEXT) stored);`;
2450
+ await runDbSql(page, createTableQuery);
2451
+ await page.reload();
2452
+ await page
2453
+ .getByTestId("dashboard.menu.tablesSearchList")
2454
+ .locator(`[data-key="table_name"]`)
2455
+ .click();
2456
+ await page.locator(`[role="columnheader"]`).nth(1).click();
2457
+ await page.locator(`[role="columnheader"]`).nth(1).click();
2458
+
2459
+ await runDbSql(
2460
+ page,
2461
+ `INSERT INTO table_name (title) VALUES('my_new_value_')`,
2462
+ );
2463
+ await runDbSql(
2464
+ page,
2465
+ `INSERT INTO table_name (title) VALUES('my_new_value_')`,
2466
+ );
2467
+ await page
2468
+ .getByText("my_new_value_1")
2469
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2470
+
2471
+ await runDbSql(page, `DROP TABLE table_name;`);
2472
+ await page
2473
+ .getByTestId("W_Table.TableNotFound")
2474
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2475
+
2476
+ await runDbSql(page, createTableQuery);
2477
+ await runDbSql(
2478
+ page,
2479
+ `INSERT INTO table_name (title) VALUES('my_new_value_')`,
2480
+ );
2481
+ await runDbSql(
2482
+ page,
2483
+ `INSERT INTO table_name (title) VALUES('my_new_value_')`,
2484
+ );
2485
+ await runDbSql(
2486
+ page,
2487
+ `INSERT INTO table_name (title) VALUES('my_new_value_')`,
2488
+ );
2489
+ await runDbSql(
2490
+ page,
2491
+ `INSERT INTO table_name (title) VALUES('my_new_value_')`,
2492
+ );
2493
+ await page
2494
+ .getByText("my_new_value_1")
2495
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2496
+
2497
+ await page
2498
+ .getByText("my_new_value_3")
2499
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2500
+ await page.waitForTimeout(4e3);
2501
+
2502
+ /** Test schema select */
2503
+ await runDbSql(
2504
+ page,
2505
+ `
2506
+ CREATE SCHEMA "MySchema";
2507
+ CREATE TABLE "MySchema"."MyTable" (
2508
+ "MyColumn" TEXT
2509
+ );
2510
+ `,
2511
+ );
2512
+ await page.getByTestId("dashboard.goToConnConfig").click();
2513
+ await page.getByTestId("NewConnectionForm.MoreOptionsToggle").click();
2514
+ await page.getByTestId("NewConnectionForm.schemaFilter").click();
2515
+ await page
2516
+ .getByTestId("NewConnectionForm.schemaFilter")
2517
+ .locator(`[data-key="MySchema"]`)
2518
+ .click();
2519
+ await page.keyboard.press("Escape");
2520
+ await page.getByTestId("Connection.edit.updateOrCreateConfirm").click();
2521
+ await page
2522
+ .getByTestId("dashboard.menu.tablesSearchList")
2523
+ .locator(getDataKey(`"MySchema"."MyTable"`))
2524
+ .click();
2525
+ await insertRow(page, `"MySchema"."MyTable"`, { MyColumn: "some value" });
2526
+ await page
2527
+ .getByText("some value")
2528
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2529
+
2530
+ await goTo(page, "localhost:3004/connections");
2531
+ await page.waitForTimeout(4e3);
2532
+ await dropConnectionAndDatabase(dbName, page);
2533
+ await page.waitForTimeout(4e3);
2534
+ await runDbsSql(page, `DROP USER db_with_owner;`);
2535
+ });
2536
+
2537
+ test("Login returnUrl", async ({ page: p }) => {
2538
+ const page = p as PageWIds;
2539
+ const requestedUrl =
2540
+ "http://localhost:3004/connections/some-connection?a=b";
2541
+ await login(page, undefined, requestedUrl);
2542
+ await page
2543
+ .getByTestId("ProjectConnection.error")
2544
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2545
+ const currentUrl = await page.url();
2546
+ await expect(currentUrl).toEqual(requestedUrl);
2547
+ });
2548
+
2549
+ test("Open redirect returnUrl", async ({ page: p }) => {
2550
+ const page = p as PageWIds;
2551
+ const requestedUrl =
2552
+ "http://localhost:3004/login?returnURL=/%2F%2Fwikipedia.org";
2553
+ await login(page, undefined, requestedUrl);
2554
+ await goTo(page, requestedUrl);
2555
+ await goTo(page, requestedUrl);
2556
+ const currentUrl = await page.url();
2557
+ await expect(currentUrl.startsWith("http://localhost:3004/")).toBe(true);
2558
+ });
2559
+
2560
+ test("Test 2FA", async ({ page: p }) => {
2561
+ const page = p as PageWIds;
2562
+
2563
+ await login(page);
2564
+
2565
+ await page.getByRole("link", { name: "test_user" }).click();
2566
+ await page.getByTestId("MenuList").locator(`[data-key="security"]`).click();
2567
+ await page.getByTestId("Setup2FA.Enable").click();
2568
+ await page.getByTestId("Setup2FA.Enable.GenerateQR").click();
2569
+ await page.getByTestId("Setup2FA.Enable.CantScanQR").click();
2570
+ const Base64Secret = (
2571
+ await page.getByTestId("Setup2FA.Enable.Base64Secret").textContent()
2572
+ )
2573
+ ?.split(" ")
2574
+ .at(-1);
2575
+ const recoveryCode = await page
2576
+ .locator("#totp_recovery_code")
2577
+ .textContent();
2578
+ const createAndFillCode = async () => {
2579
+ await page.waitForTimeout(1200);
2580
+ const code = authenticator.generate(Base64Secret ?? "");
2581
+ await page
2582
+ .getByTestId("Setup2FA.Enable.ConfirmCode")
2583
+ .locator("input")
2584
+ .fill(code);
2585
+ await page.getByTestId("Setup2FA.Enable.Confirm").click();
2586
+ };
2587
+ await createAndFillCode();
2588
+
2589
+ /** Allow 1 invalid code */
2590
+ const INVALID_CODE = "Invalid code";
2591
+ await page.waitForTimeout(300);
2592
+ const setupErrorNode = await page.getByTestId("Setup2FA.error");
2593
+ if (
2594
+ (await setupErrorNode.count()) &&
2595
+ (await setupErrorNode.textContent())?.includes(INVALID_CODE)
2596
+ ) {
2597
+ await createAndFillCode();
2598
+ }
2599
+
2600
+ /** Using token */
2601
+ await login(page);
2602
+ const fillTokenAndSignIn = async () => {
2603
+ const newCode = authenticator.generate(Base64Secret ?? "");
2604
+ await page.locator("#totp_token").fill(newCode);
2605
+ await page.getByRole("button", { name: "Sign in", exact: true }).click();
2606
+ };
2607
+ await fillTokenAndSignIn();
2608
+ await page.waitForTimeout(1e3);
2609
+
2610
+ /** Retry once when it sometimes fails */
2611
+ const errorNode = await page.getByTestId("Login.error");
2612
+ if (
2613
+ (await errorNode.count()) &&
2614
+ (await errorNode.textContent())?.includes(INVALID_CODE)
2615
+ ) {
2616
+ await page.waitForTimeout(1e3);
2617
+ await fillTokenAndSignIn();
2618
+ }
2619
+ await page
2620
+ .getByRole("link", { name: "Connections" })
2621
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2622
+
2623
+ /** Using recovery code */
2624
+ await page.request.post("/logout");
2625
+ await login(page);
2626
+ await page
2627
+ .getByRole("button", { name: "Enter recovery code", exact: true })
2628
+ .click();
2629
+ await page.locator("#totp_recovery_code").fill(recoveryCode ?? "");
2630
+ await page.getByRole("button", { name: "Sign in", exact: true }).click();
2631
+ await page.waitForTimeout(3e3);
2632
+ await page
2633
+ .getByRole("link", { name: "Connections" })
2634
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2635
+
2636
+ await page.getByRole("link", { name: "test_user" }).click();
2637
+ await page.getByTestId("MenuList").locator(`[data-key="security"]`).click();
2638
+ await page.getByTestId("Setup2FA.Disable").click();
2639
+ });
2640
+
2641
+ test("Sample database backups", async ({ page: p }) => {
2642
+ const page = p as PageWIds;
2643
+
2644
+ await login(page);
2645
+
2646
+ /** Create Sample database */
2647
+ await createDatabase("sample_database", page, false);
2648
+
2649
+ await page
2650
+ .getByTestId("dashboard.goToConnConfig")
2651
+ .waitFor({ state: "visible", ...getTimeout(10e3) });
2652
+ await page.getByTestId("dashboard.goToConnConfig").click();
2653
+ await page.getByTestId("config.details").click();
2654
+ await page.getByTestId("config.status").click();
2655
+ await page.getByTestId("config.ac").click();
2656
+ await page.getByTestId("config.methods").click();
2657
+ await page.getByTestId("config.files").click();
2658
+ await page.getByTestId("config.bkp").click();
2659
+ await page.getByTestId("config.api").click();
2660
+
2661
+ await page.getByTestId("config.bkp").click();
2662
+ /** Delete previous backups (when testing locally) */
2663
+ await deleteAllBackups(page);
2664
+
2665
+ /** Test automatic backups */
2666
+ const toggleAutomaticBackups = async () => {
2667
+ await page.getByTestId("config.bkp.AutomaticBackups").click();
2668
+ await page
2669
+ .getByTestId("config.bkp.AutomaticBackups.toggle")
2670
+ .click(getTimeout(10e3));
2671
+ await page.waitForTimeout(1e3);
2672
+ /** If it was enabled already enabled then re-enable it */
2673
+ const text = await page
2674
+ .getByTestId("config.bkp.AutomaticBackups")
2675
+ .textContent();
2676
+ if (text?.includes("Enable automatic")) {
2677
+ await toggleAutomaticBackups();
2678
+ }
2679
+ };
2680
+ await toggleAutomaticBackups();
2681
+ await page
2682
+ .getByRole("button", { name: "Restore...", exact: true })
2683
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2684
+ await deleteAllBackups(page);
2685
+
2686
+ /** Disable automatic backups */
2687
+ await toggleAutomaticBackups();
2688
+ });
2689
+
2690
+ test("Delete previous users and data (to improve local tests)", async ({
2691
+ page: p,
2692
+ }) => {
2693
+ const page = p as PageWIds;
2694
+
2695
+ await login(page);
2696
+ /** Delete previous user */
2697
+ await page.goto("localhost:3004/users", { waitUntil: "networkidle" });
2698
+ for (const username of [USERS.default_user, USERS.public_user]) {
2699
+ await page.locator(`#search-all`).fill(username);
2700
+ await page.waitForTimeout(1e3);
2701
+ // await page.keyboard.press("ArrowDown");
2702
+ await page.keyboard.press("Enter");
2703
+ await page.waitForTimeout(1e3);
2704
+ await forEachLocator(
2705
+ page,
2706
+ async () => page.getByTestId("dashboard.window.viewEditRow"),
2707
+ async (editBtn) => {
2708
+ await editBtn.click();
2709
+ await page.getByTestId("SmartForm.delete").click();
2710
+ await page.getByTestId("SmartForm.delete.confirm").click();
2711
+ await page.waitForTimeout(1e3);
2712
+ },
2713
+ );
2714
+ await page.reload();
2715
+ await page.waitForTimeout(1e3);
2716
+ }
2717
+
2718
+ /** Delete stt_mode */
2719
+ await runDbsSql(page, `UPDATE users SET options = null;`);
2720
+
2721
+ await page.goto("localhost:3004/account", { waitUntil: "networkidle" });
2722
+ await monacoType(page, `[data-label="Options"]`, `{ `, {
2723
+ // moveCursorAfterTyping: ["Right"],
2724
+ });
2725
+ await page.keyboard.type("vst", { delay: 100 });
2726
+ await page.keyboard.press("Tab");
2727
+ await page.keyboard.type("fa", { delay: 100 });
2728
+ await page.keyboard.press("Tab");
2729
+ await page.waitForTimeout(200);
2730
+ const monacoEditor = await getMonacoEditorBySelector(
2731
+ page,
2732
+ `[data-label="Options"]`,
2733
+ );
2734
+ const text = await monacoEditor.innerText();
2735
+ /** Space charCode=32 but here we get 160 */
2736
+ if (!text.includes(`"viewedSQLTips":${String.fromCharCode(160)}false`)) {
2737
+ throw `Expected "viewedSQLTips": false in ${text}`;
2738
+ }
2739
+ await page.getByRole("button", { name: "Update", exact: true }).click();
2740
+ await page
2741
+ .getByRole("button", { name: "Update row!", exact: true })
2742
+ .click();
2743
+ await page.getByRole("link", { name: "Connections", exact: true }).click();
2744
+ await page.waitForTimeout(1e3);
2745
+ const existingTestConn = await page.getByRole("link", {
2746
+ name: TEST_DB_NAME,
2747
+ exact: true,
2748
+ });
2749
+ if (await existingTestConn.isVisible()) {
2750
+ await dropConnectionAndDatabase(TEST_DB_NAME, page);
2751
+ }
2752
+ await page.waitForTimeout(1200);
2753
+ for (const dbName of Object.values(DB_NAMES)) {
2754
+ await runDbsSql(
2755
+ page,
2756
+ `DROP DATABASE IF EXISTS ${JSON.stringify(dbName)}`,
2757
+ );
2758
+ }
2759
+ });
2760
+
2761
+ test("Create and prepare test database", async ({ page: p }) => {
2762
+ const page = p as PageWIds;
2763
+
2764
+ await login(page);
2765
+ await page.getByRole("link", { name: "Connections", exact: true }).click();
2766
+ await createDatabase(TEST_DB_NAME, page);
2767
+ await page
2768
+ .getByTestId("dashboard.menu.sqlEditor")
2769
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
2770
+ const editors = await page.locator(".ProstglesSQL").count();
2771
+ if (!editors) {
2772
+ await page.getByTestId("dashboard.menu.sqlEditor").click();
2773
+ }
2774
+ if (editors > 1) {
2775
+ throw "Not ok";
2776
+ }
2777
+ await page
2778
+ .getByRole("button", { name: "Ok, don't show again", exact: true })
2779
+ .click();
2780
+
2781
+ /** Test sql key bindings */
2782
+ await page.keyboard.press("Alt+KeyE");
2783
+ const keybindings = ["Alt+KeyE", "Control+KeyE", "Control+Enter", "F5"];
2784
+ for (const key of keybindings) {
2785
+ const text = `hello${key}`;
2786
+ await monacoType(page, `.ProstglesSQL`, `SELECT '${text}'`);
2787
+ await page.keyboard.press(key);
2788
+ await page
2789
+ .locator(".W_SQLResults")
2790
+ .getByText(text, { exact: true })
2791
+ .waitFor({ state: "visible", timeout: 5e3 });
2792
+ }
2793
+ await monacoType(page, `.ProstglesSQL`, `SELECT pg_sleep(22)`);
2794
+ await page.keyboard.press("Alt+KeyE");
2795
+ await page.waitForTimeout(2e3);
2796
+ await page.keyboard.press("Escape");
2797
+ await page
2798
+ .locator(".W_SQLBottomBar .ErrorComponent")
2799
+ .getByText("canceling statement due to user request", { exact: true })
2800
+ .waitFor({ state: "visible", timeout: 5e3 });
2801
+
2802
+ /** Create schema */
2803
+ await runSql(page, QUERIES.orders);
2804
+ await page.waitForTimeout(1e3);
2805
+ await page
2806
+ .getByTestId("dashboard.menu.tablesSearchList")
2807
+ .locator(`[data-key=${JSON.stringify("orders")}]`)
2808
+ .waitFor({ state: "visible", timeout: 5e3 });
2809
+ await closeWorkspaceWindows(page);
2810
+
2811
+ /** Enable file storage */
2812
+ await page
2813
+ .getByTestId("dashboard.goToConnConfig")
2814
+ .waitFor({ state: "visible", timeout: 10e3 });
2815
+ await page.getByTestId("dashboard.goToConnConfig").click();
2816
+ await page.getByTestId("config.files").click();
2817
+ await page.getByTestId("config.files.toggle").click();
2818
+ await page.getByTestId("config.files.toggle.confirm").click();
2819
+ await page.getByTestId("config.goToConnDashboard").click();
2820
+
2821
+ /** Create table */
2822
+ await page.getByTestId("dashboard.menu.create").click();
2823
+ await page.getByText("Create table").click();
2824
+ await page
2825
+ .getByTestId("dashboard.menu.createTable.tableName")
2826
+ .getByRole("textbox")
2827
+ .fill("my_table");
2828
+ const addColumn = async (
2829
+ colName: string,
2830
+ dataType: string,
2831
+ isPkey?: boolean,
2832
+ ) => {
2833
+ await page.getByTestId("dashboard.menu.createTable.addColumn").click();
2834
+ const colEditor = await page.getByTestId("ColumnEditor.name");
2835
+ await colEditor.getByRole("textbox").fill(colName);
2836
+ await page
2837
+ .getByTestId("ColumnEditor.dataType")
2838
+ .waitFor({ state: "visible" });
2839
+ await page.keyboard.press("Tab");
2840
+ await page.keyboard.type(dataType, { delay: 300 });
2841
+ await page.keyboard.press("Enter");
2842
+ if (isPkey) {
2843
+ await page.getByText("Primary key").click();
2844
+ }
2845
+ await page
2846
+ .getByTestId("dashboard.menu.createTable.addColumn.confirm")
2847
+ .click();
2848
+ };
2849
+ await addColumn("id", "ser", true);
2850
+ await addColumn("name", "text");
2851
+ await addColumn("content", "text");
2852
+ await addColumn("secret", "text");
2853
+
2854
+ /** Add icon field */
2855
+ await page.getByTestId("dashboard.menu.createTable.addColumn").click();
2856
+ await page.getByTestId("AddColumnReference").click();
2857
+ await page
2858
+ .getByTestId("SearchList.List")
2859
+ .locator(`[data-key="files.id"]`)
2860
+ .click();
2861
+ await page
2862
+ .getByTestId("dashboard.menu.createTable.addColumn.confirm")
2863
+ .click();
2864
+
2865
+ /** Create table */
2866
+ await page.getByTestId("dashboard.menu.createTable.confirm").click();
2867
+ await page.getByTestId("SQLSmartEditor.Run").click();
2868
+
2869
+ /** Insert records into new table */
2870
+ await page.getByRole("option").getByText("My Table").click({ delay: 200 });
2871
+ await insertRow(page, "my_table", { name: "some text" });
2872
+ const deletedRowName = "some more text";
2873
+ await insertRow(page, "my_table", { name: deletedRowName });
2874
+
2875
+ /** Search row */
2876
+ await page.getByTestId("dashboard.window.toggleFilterBar").click();
2877
+ await page.locator("input#search-all").fill("2");
2878
+ await page.getByRole("option", { name: "2" }).click();
2879
+ /** This should work as well!!! */
2880
+ // await page.keyboard.press("ArrowDown", { delay: 300 });
2881
+ // await page.keyboard.press("Enter", { delay: 300 });
2882
+
2883
+ /** Backup db */
2884
+ await page
2885
+ .getByTestId("dashboard.goToConnConfig")
2886
+ .waitFor({ state: "visible", timeout: 10e3 });
2887
+ await page.getByTestId("dashboard.goToConnConfig").click();
2888
+ await page.getByTestId("config.bkp").click();
2889
+ await page
2890
+ .getByRole("button", { name: "Create backup", exact: true })
2891
+ .click();
2892
+ await page
2893
+ .getByRole("button", { name: "Start backup", exact: true })
2894
+ .click();
2895
+ await page.getByText("Completed");
2896
+
2897
+ /** Delete row */
2898
+ await page.getByTestId("config.goToConnDashboard").click();
2899
+ await page.getByTestId("dashboard.window.viewEditRow").click();
2900
+ await page.getByRole("button", { name: "Delete", exact: true }).click();
2901
+ await page.getByRole("button", { name: "Delete!", exact: true }).click();
2902
+ await page.waitForTimeout(200);
2903
+
2904
+ /** Restore db */
2905
+ await page.getByTestId("dashboard.goToConnConfig").click();
2906
+ await page.getByTestId("config.bkp").click();
2907
+ await restoreFromBackup(page);
2908
+
2909
+ /** Go to dashboard. Deleted row should be there */
2910
+ await page.waitForTimeout(2200);
2911
+ await page.getByTestId("config.goToConnDashboard").click();
2912
+ await page
2913
+ .getByText(deletedRowName)
2914
+ .waitFor({ state: "visible", timeout: 15e3 });
2915
+ await page.waitForTimeout(1200);
2916
+
2917
+ /** SearchAll for that row as well */
2918
+ await page.keyboard.press("Control+Shift+KeyF");
2919
+ await page.getByTestId("SearchAll").fill(deletedRowName);
2920
+ await page.waitForTimeout(1100);
2921
+ await page
2922
+ .getByText(`name: ${deletedRowName}`)
2923
+ .waitFor({ state: "visible", timeout: 15e3 });
2924
+ await page.keyboard.press("Escape");
2925
+
2926
+ /** Test Access control */
2927
+ await page.goto("localhost:3004/users", { waitUntil: "networkidle" });
2928
+ await page.waitForTimeout(1000);
2929
+ await insertRow(
2930
+ page,
2931
+ "users",
2932
+ { username: USERS.default_user, password: USERS.default_user },
2933
+ true,
2934
+ );
2935
+ await insertRow(
2936
+ page,
2937
+ "users",
2938
+ { username: USERS.default_user1, password: USERS.default_user1 },
2939
+ true,
2940
+ );
2941
+ // await insertRow(page, "users", { username: USERS.public_user, password: USERS.public_user, type: "public" }, true);
2942
+ });
2943
+
2944
+ test("Set access rules", async ({ page: p }) => {
2945
+ const page = p as PageWIds;
2946
+
2947
+ await createAccessRuleForTestDB(page, "default");
2948
+
2949
+ await setTableRule(
2950
+ page,
2951
+ "my_table",
2952
+ {
2953
+ select: { excludedFields: ["secret"] },
2954
+ insert: { forcedData: { name: "abc" }, excludedFields: ["secret"] },
2955
+ update: { forcedData: { name: "abc" }, excludedFields: ["secret"] },
2956
+ delete: { forcedFilter: [{ fieldName: "name", value: "abc" }] },
2957
+ },
2958
+ false,
2959
+ );
2960
+ await setTableRule(
2961
+ page,
2962
+ "orders",
2963
+ { select: {}, update: {}, insert: {}, delete: {} },
2964
+ false,
2965
+ );
2966
+ await setTableRule(
2967
+ page,
2968
+ "files",
2969
+ { select: {}, update: {}, insert: {}, delete: {} },
2970
+ true,
2971
+ );
2972
+
2973
+ /** Expect LLM to ask for API credentials */
2974
+ await page.getByTestId("AskLLM").click();
2975
+ await page.getByTestId("AskLLM.popup").waitFor({ state: "visible" });
2976
+ await page.getByTestId("SetupLLMCredentials").waitFor({ state: "visible" });
2977
+ const chatSend = await page
2978
+ .getByTestId("AskLLM.popup")
2979
+ .getByTestId("Chat.send")
2980
+ .count();
2981
+ await expect(chatSend).toBe(0);
2982
+ await page.getByTestId("Popup.close").click();
2983
+
2984
+ /** Setup LLM */
2985
+ await enableAskLLM(page, 0);
2986
+
2987
+ /** Expect LLM to work */
2988
+ const [{ isOk }] = await getLLMResponses(page, ["hehhehey"]);
2989
+ expect(isOk).toBe(true);
2990
+
2991
+ /** Clear prev chats to ensure llm limit test works */
2992
+ await runDbsSql(page, `TRUNCATE llm_chats CASCADE;`);
2993
+
2994
+ /** Save access rule */
2995
+ await page.getByTestId("config.ac.save").click();
2996
+ await page.waitForTimeout(2e3);
2997
+ });
2998
+
2999
+ test("Default user has correct permissions", async ({ page: p }) => {
3000
+ const page = p as PageWIds;
3001
+
3002
+ /** Increase test time due to doc processing */
3003
+ test.setTimeout(7 * MINUTE);
3004
+
3005
+ await page.request.post("/logout");
3006
+ await login(page, USERS.default_user);
3007
+
3008
+ await page.getByRole("link", { name: "Connections" }).click();
3009
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3010
+ await page.waitForTimeout(1000);
3011
+ await page.getByTestId("dashboard.menu").waitFor({ state: "visible" });
3012
+ await setWspColLayout(page);
3013
+ /** Open table using ctrl+P */
3014
+ await openTable(page, "my_tabl");
3015
+ await openTable(page, "ord");
3016
+ await openTable(page, "fil");
3017
+ await page.waitForTimeout(1000);
3018
+
3019
+ await uploadFile(page);
3020
+
3021
+ /* Ensure that the file is uploaded and visible in the table */
3022
+ await page
3023
+ .getByText("Show parsed document", { exact: true })
3024
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
3025
+
3026
+ await insertRow(page, "my_table", { content: USERS.default_user });
3027
+ await insertRow(page, "orders", { status: "incomplete" });
3028
+ await expect(await page.getByText("secret").count()).toBe(0);
3029
+ });
3030
+
3031
+ test("Default user1 has correct permissions", async ({ page: p }) => {
3032
+ const page = p as PageWIds;
3033
+
3034
+ await page.request.post("/logout");
3035
+ await login(page, USERS.default_user1);
3036
+
3037
+ await page.getByRole("link", { name: "Connections" }).click();
3038
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3039
+ await page.waitForTimeout(1000);
3040
+ await setWspColLayout(page);
3041
+
3042
+ /** Open table using ctrl+P */
3043
+ await openTable(page, "my_tabl");
3044
+ await openTable(page, "ord");
3045
+ await openTable(page, "fil");
3046
+ await page.waitForTimeout(1000);
3047
+
3048
+ await uploadFile(page);
3049
+
3050
+ await insertRow(page, "my_table", { content: USERS.default_user1 });
3051
+ await insertRow(page, "orders", { status: "incomplete" });
3052
+ await expect(await page.getByText("secret").count()).toBe(0);
3053
+ });
3054
+
3055
+ test("Admin user (test_user) can see all data", async ({ page: p }) => {
3056
+ const page = p as PageWIds;
3057
+
3058
+ await page.request.post("/logout");
3059
+ await login(page, USERS.test_user);
3060
+ await page.getByRole("link", { name: "Connections" }).click();
3061
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3062
+
3063
+ await setWspColLayout(page);
3064
+ await page.waitForTimeout(1e3);
3065
+
3066
+ await closeWorkspaceWindows(page);
3067
+
3068
+ /** Open table using ctrl+P */
3069
+ await openTable(page, "my_tabl");
3070
+ await openTable(page, "ord");
3071
+ await openTable(page, "file");
3072
+
3073
+ await expect(await page.getByText("abc", { exact: true }).count()).toBe(2);
3074
+ await expect(await page.getByText("incomplete").count()).toBe(2);
3075
+ await expect(await page.getByText("secret").count()).toBe(1);
3076
+ await expect(await page.getByText(fileName).count()).toBe(2);
3077
+
3078
+ /** Disable files permissions to test direct insert */
3079
+ await page.getByTestId("dashboard.goToConnConfig").click();
3080
+ await page.getByTestId("config.ac").click();
3081
+ await page.locator(`.ExistingAccessRules_Item_Header`).click();
3082
+ await setTableRule(
3083
+ page,
3084
+ "files",
3085
+ { select: {}, update: {}, insert: {}, delete: {} },
3086
+ true,
3087
+ );
3088
+ await page.getByTestId("config.ac.save").click();
3089
+ await page.waitForTimeout(2e3);
3090
+ });
3091
+
3092
+ /** Used in debugging User can insert and view */
3093
+ // test("RESEST User can insert and view files through allowed reference columns", async ({
3094
+ // page: p,
3095
+ // }) => {
3096
+ // const page = p as PageWIds;
3097
+
3098
+ // await login(page, USERS.test_user);
3099
+ // await page.getByRole("link", { name: "Connections" }).click();
3100
+ // await page.getByRole("link", { name: TEST_DB_NAME, exact: true }).click();
3101
+ // await page.waitForTimeout(1e3);
3102
+ // await runDbSql(page, `DELETE FROM my_table WHERE id > 4;`);
3103
+ // await runDbSql(
3104
+ // page,
3105
+ // `SELECT setval(
3106
+ // pg_get_serial_sequence('my_table', 'id'),
3107
+ // COALESCE((SELECT MAX(id) FROM my_table), 0),
3108
+ // true
3109
+ // );`,
3110
+ // );
3111
+ // });
3112
+
3113
+ test("User can insert and view files through allowed reference columns", async ({
3114
+ page: p,
3115
+ }) => {
3116
+ const page = p as PageWIds;
3117
+
3118
+ await login(page, USERS.default_user);
3119
+ await page.getByRole("link", { name: "Connections" }).click();
3120
+ await page.getByRole("link", { name: TEST_DB_NAME, exact: true }).click();
3121
+ await page.waitForTimeout(1e3);
3122
+
3123
+ await expect(page.getByText(fileName)).toHaveCount(0);
3124
+
3125
+ await clickInsertRow(page, "my_table");
3126
+ await selectAndUpsertFile(
3127
+ page,
3128
+ (page) => page.getByTestId("SmartFormFieldOptions.AttachFile").click(),
3129
+ () =>
3130
+ expect(
3131
+ page.getByTestId("Popup.content").locator("img"),
3132
+ // Must have blob src attribute
3133
+ ).toHaveAttribute("src", /^\s*blob:/),
3134
+ );
3135
+ const imgSrc = await page
3136
+ .getByTestId("Popup.content")
3137
+ .locator("img")
3138
+ .getAttribute("src");
3139
+ await expect(imgSrc).toContain("blob:");
3140
+ const nodes = await page.getByText(fileName).innerHTML();
3141
+ console.log({ nodes });
3142
+ await expect(page.getByText(fileName)).toHaveCount(1);
3143
+ await page.waitForTimeout(1e3);
3144
+
3145
+ const myTableContainer = page.locator(`[data-table-name="my_table"]`);
3146
+
3147
+ // Required to ensure it is not obscured by the insert btn
3148
+ await myTableContainer.getByTestId("dashboard.window.fullscreen").click();
3149
+ await myTableContainer
3150
+ .getByTestId("dashboard.window.viewEditRow")
3151
+ .last()
3152
+ .click();
3153
+
3154
+ /** Toggling records by keyboard works */
3155
+ await page.waitForTimeout(1e3); // Wait for listeners to attach?!
3156
+ await page.keyboard.press("ArrowLeft");
3157
+ await expect(page.locator(`#my_table-id`)).toHaveValue("4");
3158
+ await page.keyboard.press("ArrowRight");
3159
+
3160
+ await expect(
3161
+ page.getByTestId("Popup.content").locator("img"),
3162
+ ).toHaveAttribute(
3163
+ "src",
3164
+ // Inserted url starts with /prostgles_storage
3165
+
3166
+ /^\/prostgles_storage/,
3167
+ );
3168
+
3169
+ // Deleting works
3170
+ await page
3171
+ .locator(getDataKey("files_id"))
3172
+ .getByTestId("FormField.clear")
3173
+ .click();
3174
+ await page.getByTestId("SmartForm.update").click();
3175
+ await page
3176
+ .getByRole("button", { name: "Update row!", exact: true })
3177
+ .click();
3178
+ await page.waitForTimeout(500);
3179
+
3180
+ /** If it fails you might need to exit my_table fullscreen and it will be in the top files table */
3181
+ await expect(page.getByText(fileName)).toHaveCount(0);
3182
+
3183
+ // Updating row with file works
3184
+ await page.getByTestId("dashboard.window.viewEditRow").last().click();
3185
+ await selectAndUpsertFile(
3186
+ page,
3187
+ (page) => page.getByTestId("SmartFormFieldOptions.AttachFile").click(),
3188
+ () =>
3189
+ expect(
3190
+ page.getByTestId("Popup.content").locator("img"),
3191
+ ).toHaveAttribute("src", /^\s*blob:/),
3192
+ true,
3193
+ );
3194
+ await expect(page.getByText(fileName)).toHaveCount(1);
3195
+ });
3196
+
3197
+ test("Table tests", async ({ page: p }) => {
3198
+ const page = p as PageWIds;
3199
+ await login(page, USERS.test_user);
3200
+ await page.getByRole("link", { name: "Connections" }).click();
3201
+ await page.getByRole("link", { name: TEST_DB_NAME, exact: true }).click();
3202
+
3203
+ const wspName = "Table tests";
3204
+ /** Delete existing duplicate workspace */
3205
+ await page.getByTestId("WorkspaceMenuDropDown").click();
3206
+ await page.waitForTimeout(1e3);
3207
+ let deleted = false;
3208
+ await forEachLocator(
3209
+ page,
3210
+ async () => {
3211
+ //.getByText("WorkspaceMenu.SearchList")
3212
+ const res = await page
3213
+ .getByTestId("WorkspaceMenu.SearchList")
3214
+ .locator(`[data-key=${JSON.stringify(wspName)}]`);
3215
+ return res;
3216
+ },
3217
+ async (item) => {
3218
+ const deleteWspBtn = await item.getByTestId("WorkspaceDeleteBtn");
3219
+ deleted = true;
3220
+ await deleteWspBtn.click();
3221
+ await page.waitForTimeout(555);
3222
+ await page.getByTestId("WorkspaceDeleteBtn.Confirm").click();
3223
+ await page.waitForTimeout(555);
3224
+ },
3225
+ );
3226
+ if (!deleted) {
3227
+ await page.locator(`[data-close-popup="true"]`).click();
3228
+ }
3229
+ await page.getByTestId("WorkspaceMenuDropDown").click();
3230
+ await page.getByTestId("WorkspaceMenuDropDown.WorkspaceAddBtn").click();
3231
+ await page.waitForTimeout(1e3);
3232
+ await page.keyboard.insertText(wspName);
3233
+ await page.keyboard.press("Enter");
3234
+ await page.waitForTimeout(1e3);
3235
+ await setWspColLayout(page);
3236
+
3237
+ const query = `
3238
+ CREATE EXTENSION IF NOT EXISTS postgis;
3239
+ DROP TABLE IF EXISTS orders CASCADE;
3240
+ DROP TABLE IF EXISTS users CASCADE;
3241
+ CREATE TABLE users (id UUID PRIMARY KEY, first_name text, last_name text, email text, created_at timestamp default now(), type TEXT DEFAULT 'default', position numeric);
3242
+ ${QUERIES.orders}
3243
+ ALTER TABLE orders
3244
+ ADD COLUMN total_cost NUMERIC NOT NULL DEFAULT random() * 100;
3245
+ ALTER TABLE orders ADD COLUMN delivery_address GEOGRAPHY DEFAULT st_point(-0.08 + random()/10, 51.5 + random()/10)::GEOGRAPHY;
3246
+ ALTER TABLE orders
3247
+ ADD COLUMN created_at timestamp default now() + (random() * 10 * '1day'::interval);
3248
+ ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users;
3249
+ INSERT INTO users (id, first_name, last_name, email, type, position)
3250
+ SELECT
3251
+ user_id,
3252
+ "left"(user_id::TEXT, 8),
3253
+ "right"(user_id::TEXT, 8),
3254
+ "left"(user_id::TEXT, 8) || "right"(user_id::TEXT, 8) || '@gmail.com',
3255
+ CASE WHEN rownumid = 1 THEN 'default' WHEN rownumid = 2 THEN 'admin' WHEN random() < .5 THEN 'default' ELSE 'admin' END,
3256
+ row_number() over()
3257
+ FROM (
3258
+ SELECT *, row_number() over( PARTITION BY user_id) as dpid, row_number() over() as rownumid
3259
+ FROM (
3260
+ SELECT rownum, gen_random_uuid() as user_id
3261
+ FROM generate_series(1, 1e2) as rownum
3262
+ ) t
3263
+ ) t1
3264
+ WHERE dpid = 1;
3265
+
3266
+ INSERT INTO orders (user_id, status)
3267
+ SELECT u.id, 'completed'
3268
+ FROM (
3269
+ SELECT rownum
3270
+ FROM generate_series(1, 1e2) as rownum
3271
+ ) t
3272
+ LEFT JOIN users u ON true;
3273
+ `;
3274
+ await page.evaluate(async (query) => {
3275
+ try {
3276
+ await (window as any).sql(query);
3277
+ } catch (err) {
3278
+ document.body.innerText = JSON.stringify(err);
3279
+ }
3280
+ }, query);
3281
+
3282
+ await getSearchListItem(page, { dataKey: "users" }).click();
3283
+ const usersTable = await getTableWindow(page, "users");
3284
+
3285
+ /** Test pagination */
3286
+ let pageInput = await usersTable.getByTestId("Pagination.page");
3287
+ await expect(await pageInput.inputValue()).toBe("1");
3288
+ await expect(await pageInput.getAttribute("min")).toBe("1");
3289
+ await expect(await pageInput.getAttribute("max")).toBe("4");
3290
+ await expect(
3291
+ usersTable.getByTestId("Pagination.pageCountInfo"),
3292
+ ).toContainText(`4 pages (100 rows)`);
3293
+ await usersTable.getByTestId("Pagination.lastPage").click();
3294
+ pageInput = await usersTable.getByTestId("Pagination.page");
3295
+ await pageInput.scrollIntoViewIfNeeded();
3296
+ await expect(await pageInput.inputValue()).toBe("4");
3297
+ await usersTable.getByTestId("Pagination.firstPage").click();
3298
+ await expect(await pageInput.inputValue()).toBe("1");
3299
+ await usersTable.getByTestId("Pagination.nextPage").click();
3300
+ await expect(await pageInput.inputValue()).toBe("2");
3301
+ await usersTable.getByTestId("Pagination.lastPage").click();
3302
+ await usersTable.getByTestId("Pagination.pageSize").click();
3303
+ await page
3304
+ .getByTestId("Pagination.pageSize")
3305
+ .locator(getDataKey("50"))
3306
+ .click();
3307
+ await expect(await pageInput.inputValue()).toBe("2");
3308
+ await expect(
3309
+ await usersTable.getByTestId("Pagination.pageCountInfo").textContent(),
3310
+ ).toBe(`2 pages (100 rows)`);
3311
+
3312
+ await usersTable.getByTestId("AddColumnMenu").click();
3313
+ await getSearchListItem(page.getByTestId("AddColumnMenu"), {
3314
+ dataKey: "Referenced",
3315
+ }).click();
3316
+ await getSearchListItem(page.getByTestId("JoinPathSelectorV2"), {
3317
+ dataKey: "orders",
3318
+ }).click(TWENTY_SECONDS_OR_MORE);
3319
+ await page.getByTestId("LinkedColumn.ColumnList.toggle").click();
3320
+ await page.waitForTimeout(1e3);
3321
+ await getSearchListItem(page, { dataKey: "total_cost" })
3322
+ .getByTestId("SummariseColumn.toggle")
3323
+ .click();
3324
+ await page.waitForTimeout(1e3);
3325
+ await getSearchListItem(page.getByTestId("FunctionSelector"), {
3326
+ dataKey: "$sum",
3327
+ }).click();
3328
+ await page.getByTestId("SummariseColumn.apply").click();
3329
+ await page
3330
+ .getByTestId("LinkedColumn.ColumnListMenu")
3331
+ .getByTestId("Popup.close")
3332
+ .click();
3333
+ await page.getByTestId("LinkedColumn.Add").click();
3334
+
3335
+ await page.waitForTimeout(1e3);
3336
+ await usersTable.getByTestId("AddChartMenu.Map").click();
3337
+ await page
3338
+ .getByTestId("AddChartMenu.Map")
3339
+ .getByRole("option")
3340
+ .filter({ hasText: "orders (delivery_address)" })
3341
+ .click();
3342
+ await page.waitForTimeout(3e3);
3343
+ await page.getByTestId("dashboard.window.detachChart").click();
3344
+ await page.waitForTimeout(1e3);
3345
+ await usersTable.getByTestId("AddChartMenu.Timechart").click();
3346
+ await page
3347
+ .getByTestId("AddChartMenu.Timechart")
3348
+ .getByRole("option")
3349
+ .getByText("orders (created_at)", { exact: true })
3350
+ .click();
3351
+ await page.waitForTimeout(3e3);
3352
+ await page.getByTestId("dashboard.window.detachChart").click();
3353
+
3354
+ /** Set count all to ensure the W_TimeChart.ActiveRow below works */
3355
+ // await page.getByTestId("TimeChartLayerOptions.aggFunc").click();
3356
+ // await page.getByTestId("TimeChartLayerOptions.aggFunc.select").click();
3357
+ // await page.getByTestId("TimeChartLayerOptions.aggFunc.select").locator(`[data-key="$countAll"]`).click();
3358
+ // await page.getByTestId("Popup.close").click();
3359
+
3360
+ await page.waitForTimeout(5e3);
3361
+ /** Mouse move is needed to show tooltip and to trigger re-render so that _renderedData.x,y are defined */
3362
+ await page.mouse.move(700, 111);
3363
+ await page.mouse.move(700, 150);
3364
+ await page.mouse.click(700, 150);
3365
+ await page
3366
+ .getByTestId("W_TimeChart.ActiveRow")
3367
+ .waitFor({ state: "visible", timeout: 5e3 });
3368
+ /** Test W_TimeChart activeRow crossfilter */
3369
+ const {
3370
+ data = [],
3371
+ x = -99,
3372
+ y = -99,
3373
+ } = await page.evaluate(async () => {
3374
+ try {
3375
+ const timeChartRef = document.querySelector(".W_TimeChart")!;
3376
+ const bbox = timeChartRef.getBoundingClientRect();
3377
+ const data = (timeChartRef as any)._renderedData as {
3378
+ x: number;
3379
+ y: number;
3380
+ value: number;
3381
+ }[];
3382
+ return { data, x: bbox.x, y: bbox.y };
3383
+ } catch (err: any) {
3384
+ document.body.innerText = err.toString() + JSON.stringify(err);
3385
+ return {};
3386
+ }
3387
+ });
3388
+ const [firstPoint, secondPoint] = data;
3389
+ if (
3390
+ typeof firstPoint?.x !== "number" ||
3391
+ typeof secondPoint?.x !== "number"
3392
+ ) {
3393
+ console.error("firstPoint or secondPoint missing:", {
3394
+ firstPoint,
3395
+ secondPoint,
3396
+ });
3397
+ } else {
3398
+ await page.mouse.click(firstPoint.x + x, firstPoint.y + y);
3399
+ await page.waitForTimeout(1e3);
3400
+ await page.mouse.click(firstPoint.x + x, firstPoint.y + y); // to close it
3401
+ await page.waitForTimeout(1e3);
3402
+ await page.mouse.click(secondPoint.x + x, secondPoint.y + y);
3403
+ await page.waitForTimeout(1e3);
3404
+ }
3405
+
3406
+ // Close active row
3407
+ await page.waitForTimeout(2e3);
3408
+ const brush = await page.getByTestId("W_TimeChart.ActiveRow");
3409
+ if (await brush.isVisible()) {
3410
+ await brush.locator("button").click();
3411
+ }
3412
+
3413
+ /**
3414
+ * Ensure card view works
3415
+ */
3416
+ await usersTable.getByTestId("dashboard.window.menu").click();
3417
+ await page.waitForTimeout(1e3);
3418
+ await page.getByText("Display options").click();
3419
+ await page
3420
+ .getByTestId("table.options.displayMode")
3421
+ .locator(getDataKey("card"))
3422
+ .click();
3423
+ await page.getByTestId("table.options.cardView.groupBy").click();
3424
+ await page
3425
+ .getByTestId("SearchList.List")
3426
+ .locator(`[data-key="type"]`)
3427
+ .click();
3428
+ await page.getByTestId("table.options.cardView.orderBy").click();
3429
+ await page
3430
+ .getByTestId("SearchList.List")
3431
+ .locator(`[data-key="position"]`)
3432
+ .click();
3433
+ await page.waitForTimeout(1e3);
3434
+ await page.keyboard.press("Escape");
3435
+ await usersTable.getByTestId("dashboard.window.fullscreen").click();
3436
+ await page.waitForTimeout(3e3);
3437
+ await expect(await page.getByText("First Name").first()).toBeVisible();
3438
+
3439
+ /** Test groupBy */
3440
+ const swapFirstTwoRows = async () => {
3441
+ const groups = await page.getByTestId("CardView.group").all();
3442
+ await expect(groups.length).toBe(2);
3443
+ const [firstGroup, secondGroup] = groups;
3444
+ await page.waitForTimeout(2e3);
3445
+ const firstGroupFirstRow = await firstGroup
3446
+ .getByTestId("CardView.row")
3447
+ .first();
3448
+ const secondGroupFirstRow = await secondGroup
3449
+ .getByTestId("CardView.row")
3450
+ .first();
3451
+ const draggedText = await firstGroupFirstRow
3452
+ .getByTitle("id")
3453
+ .textContent();
3454
+ const targetText = await secondGroupFirstRow
3455
+ .getByTitle("id")
3456
+ .textContent();
3457
+ const firstDragHandle = await firstGroupFirstRow.getByTestId(
3458
+ "CardView.DragHeader",
3459
+ );
3460
+ const secondDragHandle = await secondGroupFirstRow.getByTestId(
3461
+ "CardView.DragHeader",
3462
+ );
3463
+
3464
+ const box1 = await firstDragHandle.boundingBox();
3465
+ const box2 = await secondDragHandle.boundingBox();
3466
+ if (!box1 || !box2) {
3467
+ throw "box1 or box2 missing";
3468
+ }
3469
+ await page.mouse.move(box1.x + box1.width / 2, box1.y + box1.height / 2, {
3470
+ steps: 22,
3471
+ });
3472
+ await firstDragHandle.hover();
3473
+ await page.waitForTimeout(1e3);
3474
+ await page.mouse.down({ button: "left" });
3475
+ await page.mouse.move(box2.x + box2.width / 2, box2.y + box2.height / 2, {
3476
+ steps: 111,
3477
+ });
3478
+ await page.mouse.up({ button: "left" });
3479
+ await page.waitForTimeout(5e3);
3480
+
3481
+ const newTargetText = await secondGroup
3482
+ .getByTestId("CardView.row")
3483
+ .first()
3484
+ .getByTitle("id")
3485
+ .textContent();
3486
+ return { draggedText, newTargetText };
3487
+ };
3488
+
3489
+ await swapFirstTwoRows();
3490
+ await page.waitForTimeout(1e3);
3491
+ const { draggedText, newTargetText } = await swapFirstTwoRows();
3492
+ await page.waitForTimeout(1e3);
3493
+ await expect(draggedText).toEqual(newTargetText);
3494
+ await page.waitForTimeout(2e3);
3495
+ });
3496
+
3497
+ test("API tests", async ({ page: p }) => {
3498
+ const page = p as PageWIds;
3499
+ await login(page, USERS.test_user);
3500
+ await page.getByRole("link", { name: "Connections" }).click();
3501
+ await page.getByRole("link", { name: TEST_DB_NAME, exact: true }).click();
3502
+ await page
3503
+ .getByTestId("dashboard.goToConnConfig")
3504
+ .waitFor({ state: "visible", timeout: 10e3 });
3505
+ await page.getByTestId("dashboard.goToConnConfig").click();
3506
+ await page.getByTestId("config.api").click();
3507
+
3508
+ await page
3509
+ .getByRole("button", { name: "Create token", exact: true })
3510
+ .click();
3511
+ await page.getByRole("button", { name: "Generate", exact: true }).click();
3512
+ await page.getByTestId("Popup.close").click();
3513
+ await page.getByRole("button", { name: "Examples", exact: true }).click();
3514
+ await page
3515
+ .getByRole("button", { name: "Download code sample", exact: true })
3516
+ .click();
3517
+ });
3518
+
3519
+ test("SQL Autocomplete", async ({ page: p }) => {
3520
+ const page = p as PageWIds;
3521
+ const sqlTestTimeout = { total: 9 * 6e4, sql: 8 * 6e4 };
3522
+ test.setTimeout(sqlTestTimeout.total);
3523
+
3524
+ await page.request.post("/logout");
3525
+ await login(page, USERS.test_user);
3526
+ await page.getByRole("link", { name: "Connections" }).click();
3527
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3528
+
3529
+ await page.getByTestId("dashboard.menu").waitFor({ state: "visible" });
3530
+ await page.waitForTimeout(3000);
3531
+
3532
+ /** Ensure SQL Autocomplete works */
3533
+ await closeWorkspaceWindows(page);
3534
+ await page.getByTestId("dashboard.menu.sqlEditor").click();
3535
+ await page.getByTestId("dashboard.window.menu").click();
3536
+ await page.getByText("General").click();
3537
+
3538
+ for (const _ of new Array(5).fill(1)) {
3539
+ await page.getByText("TEST", { exact: true }).click();
3540
+ await page.waitForTimeout(100);
3541
+ }
3542
+
3543
+ const startSqlTest = async () =>
3544
+ new Promise(async (resolve, reject) => {
3545
+ page.on("dialog", (dialog) => {
3546
+ const msg = dialog.message();
3547
+ console.log("1", msg);
3548
+ if (msg.includes("does not match the expected")) {
3549
+ reject(msg);
3550
+ throw msg;
3551
+ }
3552
+ if (msg === "Demo finished successfully") {
3553
+ return resolve(1);
3554
+ }
3555
+ return dialog.accept();
3556
+ });
3557
+ });
3558
+ await runDbSql(
3559
+ page,
3560
+ `
3561
+ CREATE TABLE force_cached_col_types_reload (); -- Needed failed test rerun
3562
+ DROP TABLE force_cached_col_types_reload;`,
3563
+ );
3564
+ await startSqlTest();
3565
+ });
3566
+
3567
+ test("Admin can create and drop connections", async ({ page: p }) => {
3568
+ const page = p as PageWIds;
3569
+ await login(page, USERS.test_user);
3570
+ const dbName = "my_new_db";
3571
+ await createDatabase(dbName, page);
3572
+ await page.getByTestId("dashboard.menu").waitFor({ state: "visible" });
3573
+ await page.goBack();
3574
+
3575
+ const { connectionSelector } = await dropConnectionAndDatabase(
3576
+ dbName,
3577
+ page,
3578
+ );
3579
+ await goTo(page, "localhost:3004/connections");
3580
+ await page.reload();
3581
+ const deletedConnection = await page.locator(connectionSelector);
3582
+ await expect(await deletedConnection.count()).toEqual(0);
3583
+ });
3584
+
3585
+ test("Set public user access rules", async ({ page: p }) => {
3586
+ const page = p as PageWIds;
3587
+
3588
+ await createAccessRuleForTestDB(page, "public");
3589
+ await setTableRule(
3590
+ page,
3591
+ "my_table",
3592
+ {
3593
+ select: {},
3594
+ },
3595
+ false,
3596
+ );
3597
+ await setTableRule(
3598
+ page,
3599
+ "orders",
3600
+ { select: {}, update: {}, insert: {}, delete: {} },
3601
+ false,
3602
+ );
3603
+ await setTableRule(
3604
+ page,
3605
+ "files",
3606
+ { select: {}, update: {}, insert: {}, delete: {} },
3607
+ true,
3608
+ );
3609
+ await enableAskLLM(page, 4, true);
3610
+ await page.getByTestId("config.ac.save").click();
3611
+ await page.waitForTimeout(2e3);
3612
+ });
3613
+
3614
+ test("Public user can access all allowed sections without issues", async ({
3615
+ page: p,
3616
+ }) => {
3617
+ const page = p as PageWIds;
3618
+ await goTo(page, "localhost:3004/connections");
3619
+ await page.reload();
3620
+ await page.getByRole("link", { name: "Connections" }).click();
3621
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3622
+ await page
3623
+ .getByTestId("dashboard.menu.tablesSearchList")
3624
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
3625
+ await openTable(page, "my_tabl");
3626
+
3627
+ /** Ask LLM limit */
3628
+ const [response1, response2, response3] = await getLLMResponses(page, [
3629
+ "hey",
3630
+ "hey",
3631
+ "hey",
3632
+ ]);
3633
+ await expect(response1.isOk).toBe(true);
3634
+ await expect(response2.isOk).toBe(true);
3635
+ await expect(response3.isOk).toBe(true);
3636
+ });
3637
+
3638
+ test("Public user ask llm limit", async ({ page: p }) => {
3639
+ const page = p as PageWIds;
3640
+ await goTo(page, "localhost:3004/connections");
3641
+ await page.reload();
3642
+ await page.getByRole("link", { name: "Connections" }).click();
3643
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3644
+ await page
3645
+ .getByTestId("dashboard.menu.tablesSearchList")
3646
+ .waitFor({ state: "visible", ...TWENTY_SECONDS_OR_MORE });
3647
+ const [response1, response2] = await getLLMResponses(page, ["hey", "hey"]);
3648
+ await expect(response1.isOk).toBe(true);
3649
+ await expect(response2.isOk).toBe(false);
3650
+ });
3651
+
3652
+ test("MCP Servers", async ({ page: p }) => {
3653
+ const page = p as PageWIds;
3654
+ await login(page, USERS.test_user, "localhost:3004/login");
3655
+ await page.getByRole("link", { name: "Connections" }).click();
3656
+ await page.getByRole("link", { name: TEST_DB_NAME }).click();
3657
+
3658
+ await runDbsSql(
3659
+ page,
3660
+ `
3661
+ UPDATE mcp_servers SET enabled = false WHERE name = 'myServer';
3662
+ DELETE FROM mcp_servers WHERE name = 'myServer';
3663
+
3664
+ DELETE FROM alerts; -- left by mock mcp server oauth flows
3665
+ `,
3666
+ );
3667
+
3668
+ await page.getByTestId("AskLLM").click();
3669
+ await page.getByTestId("AskLLM.popup").waitFor({ state: "visible" });
3670
+ await page.getByTestId("LLMChatOptions.MCPTools").click();
3671
+ await page.getByTestId("AddMCPServer.Open").click();
3672
+ await monacoType(
3673
+ page,
3674
+ ".SmartCodeEditor",
3675
+ JSON.stringify(
3676
+ {
3677
+ mcpServers: {
3678
+ myServer: {
3679
+ command: "npx",
3680
+ args: [
3681
+ "-y",
3682
+ "@modelcontextprotocol/server-filesystem",
3683
+ "ALLOWED_DIR",
3684
+ ],
3685
+ env: {
3686
+ MY_TOKEN: "<YOUR_TOKEN>",
3687
+ },
3688
+ },
3689
+ },
3690
+ },
3691
+ null,
3692
+ 2,
3693
+ ),
3694
+ {
3695
+ deleteAllAndFill: true,
3696
+ /** For some reason an extra bracket is inserted */
3697
+ pressAfterTyping: ["Backspace"],
3698
+ },
3699
+ );
3700
+
3701
+ await page.locator(".SwitchToggle " + getDataKey("ALLOWED_DIR")).click();
3702
+ await page.getByTestId("AddMCPServer.Add").click();
3703
+ await page.getByTestId("AddMCPServer.Add").waitFor({ state: "detached" });
3704
+ await page
3705
+ .getByTestId("SmartCardList")
3706
+ .locator(getDataKey("myServer"))
3707
+ .getByTitle("Press to enable")
3708
+ .click();
3709
+
3710
+ await page.getByLabel("ALLOWED_DIR").fill("/prostgles-mcp-test");
3711
+ await page.getByText("Enable", { exact: true }).click();
3712
+ await page.waitForTimeout(1e3);
3713
+ await page.getByTestId("Popup.close").last().click();
3714
+ await page.getByTestId("Popup.close").last().click();
3715
+ await page.getByTestId("Alerts").click(TWENTY_SECONDS_OR_MORE);
3716
+ await expect(page.getByTestId("Alerts")).toContainText(
3717
+ "MCP server disabled due to error",
3718
+ );
3719
+ await page.getByText("Go to issue").click();
3720
+ await page
3721
+ .locator(getDataKey("myServer"))
3722
+ .getByTestId("SmartCard.viewEditRow")
3723
+ .click();
3724
+ await page.getByTestId("SmartForm.delete").click();
3725
+ await page.getByTestId("SmartForm.delete.confirm").click();
3726
+ });
3727
+
3728
+ /** Flaky on github */
3729
+ test("Web template build works", async ({ page: p }) => {
3730
+ const page = p as PageWIds;
3731
+ await login(page, USERS.test_user, "localhost:3004/login");
3732
+ await page.getByRole("link", { name: "cloud" }).click();
3733
+ await page.getByTestId("dashboard.goToConnConfig").click();
3734
+ await page.getByTestId("config.webApp").click();
3735
+ const createFromTemplateBtn = page.getByTestId(
3736
+ "WebAppConfig.createFromTemplate",
3737
+ );
3738
+ await createFromTemplateBtn.click();
3739
+ await page.waitForTimeout(1e3);
3740
+ await page
3741
+ .getByTestId("Btn.ClickConfirmation.Confirm")
3742
+ .click(TWENTY_SECONDS_OR_MORE);
3743
+ await expect(createFromTemplateBtn).toBeEnabled(TWENTY_SECONDS_OR_MORE);
3744
+ // Page will reload
3745
+ await page.waitForTimeout(500);
3746
+ await clickAndWait(page.getByTestId("WebAppConfig.build"));
3747
+ await clickAndWait(page.getByTestId("WebAppConfig.test"));
3748
+ await page.getByTestId("FullscreenWrapper.toggleFullscreen").click();
3749
+ await page.locator(getDataKey("Components")).click();
3750
+ await page.locator(getDataKey("SampleComponent")).click();
3751
+ await page.locator(getDataKey("Files")).click();
3752
+ await page.locator(getDataLabel("client")).click();
3753
+ await page
3754
+ .locator(getDataLabel("client") + " " + getDataLabel("package.json"))
3755
+ .getByTestId("FileTreeNode.header")
3756
+ .click();
3757
+ await page.waitForTimeout(1e3);
3758
+ // await page.getByTestId("FileTree").locator("input").fill("pack");
3759
+ // await page.keyboard.press("Enter");
3760
+ await expect(page.getByTestId("MonacoEditor")).toContainText(
3761
+ "vite-project",
3762
+ );
3763
+ });
3764
+
3765
+ test("show error when on webdev prompt and webapp not templated", async ({
3766
+ page: p,
3767
+ }) => {
3768
+ const page = p as PageWIds;
3769
+ await login(page, USERS.test_user, "localhost:3004/login");
3770
+ await page.getByRole("link", { name: "sample_database" }).click();
3771
+ await page.getByTestId("AskLLM").click();
3772
+ await page.getByTestId("AskLLM.popup").waitFor({ state: "visible" });
3773
+ await setPromptByText(page, "Web app development", false);
3774
+ const alertLocator = page.getByText(
3775
+ "WebDev MCP Server requires a templated web app",
3776
+ );
3777
+ await expect(alertLocator).toBeVisible();
3778
+
3779
+ /** Closing it works */
3780
+ await page.getByTestId("Popup.close").last().click();
3781
+ await expect(alertLocator).not.toBeAttached();
3782
+ });
3783
+
3784
+ test("Web template works", async ({ page: p }) => {
3785
+ const page = p as PageWIds;
3786
+ await goTo(page, "localhost:3005");
3787
+ await expect(page.locator("body")).toContainText("Not logged in");
3788
+ await expect(page.locator("body")).toContainText("Available tables:");
3789
+ });
3790
+
3791
+ test("Web app dev mode works", async ({ page: p }) => {
3792
+ const page = p as PageWIds;
3793
+ const cwd = resolve(join(__dirname, "..", "demo", "client"));
3794
+ console.log("Starting dev server in cwd:", cwd);
3795
+ const devProc = spawn("npm", ["run", "dev"], {
3796
+ cwd,
3797
+ shell: true,
3798
+ detached: true,
3799
+ stdio: ["ignore", "pipe", "pipe"],
3800
+ });
3801
+ try {
3802
+ await new Promise((resolve, reject) => {
3803
+ devProc.stdout?.on("data", (data) => {
3804
+ const str = data.toString();
3805
+ console.log("devProc stdout:", str);
3806
+ if (str.includes("5173")) {
3807
+ resolve(1);
3808
+ }
3809
+ });
3810
+ setTimeout(() => reject(new Error("Dev server timeout")), 30_000);
3811
+ });
3812
+ await goTo(page, "localhost:5173");
3813
+ await expect(page.locator("body")).toContainText("Not logged in");
3814
+ await expect(page.locator("body")).toContainText("Available tables:");
3815
+ } finally {
3816
+ console.log("Killing dev proc tree:", devProc.pid);
3817
+ process.kill(-devProc.pid!, "SIGTERM"); // still leaves a zombie node process?!
3818
+ }
3819
+ });
3820
+ });