diff --git a/cli/frontend/build/404.html b/cli/frontend/build/404.html index 03d7024a..3993212a 100644 --- a/cli/frontend/build/404.html +++ b/cli/frontend/build/404.html @@ -1 +1 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/cli/frontend/build/[...slug].html b/cli/frontend/build/[...slug].html index 5a5eb9b2..6922cdcc 100644 --- a/cli/frontend/build/[...slug].html +++ b/cli/frontend/build/[...slug].html @@ -1 +1 @@ -Databend
SQL Query
Execute a query to see results
\ No newline at end of file +Databend
Execute a query to see results
\ No newline at end of file diff --git a/cli/frontend/build/_next/static/css/0b9c66583f0a06c5.css b/cli/frontend/build/_next/static/css/0b9c66583f0a06c5.css new file mode 100644 index 00000000..973afb09 --- /dev/null +++ b/cli/frontend/build/_next/static/css/0b9c66583f0a06c5.css @@ -0,0 +1,3 @@ +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/* +! tailwindcss v3.4.18 | MIT License | https://tailwindcss.com +*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-1\/2{left:50%}.left-3{left:.75rem}.right-0{right:0}.top-0{top:0}.top-\[68px\]{top:68px}.z-10{z-index:10}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-5{margin-top:1.25rem}.box-border{box-sizing:border-box}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.hidden{display:none}.h-1{height:.25rem}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-8{height:2rem}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-72{max-height:18rem}.min-h-0{min-height:0}.min-h-\[calc\(100vh-180px\)\]{min-height:calc(100vh - 180px)}.min-h-screen{min-height:100vh}.w-0\.5{width:.125rem}.w-1{width:.25rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-40{width:10rem}.w-44{width:11rem}.w-8{width:2rem}.w-\[100px\]{width:100px}.w-full{width:100%}.min-w-0{min-width:0}.min-w-full{min-width:100%}.max-w-full{max-width:100%}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\.5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\.5{--tw-translate-y:-0.375rem}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.translate-y-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.translate-y-1\.5{--tw-translate-y:0.375rem}.transform,.translate-y-1\.5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.resize{resize:both}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-indigo-200{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.border-indigo-300{--tw-border-opacity:1;border-color:rgb(165 180 252/var(--tw-border-opacity,1))}.border-indigo-400{--tw-border-opacity:1;border-color:rgb(129 140 248/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165/var(--tw-border-opacity,1))}.border-transparent{border-color:transparent}.border-yellow-300{--tw-border-opacity:1;border-color:rgb(253 224 71/var(--tw-border-opacity,1))}.border-t-transparent{border-top-color:transparent}.bg-\[\#f4f6fb\]{--tw-bg-opacity:1;background-color:rgb(244 246 251/var(--tw-bg-opacity,1))}.bg-\[\#f9fbff\]{--tw-bg-opacity:1;background-color:rgb(249 251 255/var(--tw-bg-opacity,1))}.bg-\[\#ffe895\]{--tw-bg-opacity:1;background-color:rgb(255 232 149/var(--tw-bg-opacity,1))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-50\/80{background-color:rgba(239,246,255,.8)}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.bg-indigo-50\/70{background-color:rgba(238,242,255,.7)}.bg-indigo-500\/80{background-color:rgba(99,102,241,.8)}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/95{background-color:hsla(0,0%,100%,.95)}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21/var(--tw-bg-opacity,1))}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-3{padding-bottom:.75rem}.pl-8{padding-left:2rem}.pr-3{padding-right:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.tracking-wide{letter-spacing:.025em}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-gray-900\/70{color:rgba(17,24,39,.7)}.text-indigo-500{--tw-text-opacity:1;color:rgb(99 102 241/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-indigo-700{--tw-text-opacity:1;color:rgb(67 56 202/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-\[0_0_0_2px_rgba\(99\2c 102\2c 241\2c 0\.35\)\]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_0_2px_rgba\(99\2c 102\2c 241\2c 0\.35\)\]{--tw-shadow:0 0 0 2px rgba(99,102,241,.35);--tw-shadow-colored:0 0 0 2px var(--tw-shadow-color)}.shadow-\[0_15px_35px_-20px_rgba\(79\2c 70\2c 229\2c 0\.45\)\]{--tw-shadow:0 15px 35px -20px rgba(79,70,229,.45);--tw-shadow-colored:0 15px 35px -20px var(--tw-shadow-color)}.shadow-\[0_15px_35px_-20px_rgba\(79\2c 70\2c 229\2c 0\.45\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-blue-300{--tw-ring-opacity:1;--tw-ring-color:rgb(147 197 253/var(--tw-ring-opacity,1))}.ring-indigo-300{--tw-ring-opacity:1;--tw-ring-color:rgb(165 180 252/var(--tw-ring-opacity,1))}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.drop-shadow,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-transform{transition-duration:.15s}#__next,body,html{height:100%}.hover\:border-gray-200:hover{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.hover\:border-gray-400:hover{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity,1))}.hover\:border-indigo-300:hover{--tw-border-opacity:1;border-color:rgb(165 180 252/var(--tw-border-opacity,1))}.hover\:bg-gray-400:hover{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity,1))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:bg-indigo-50:hover{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity,1))}.hover\:bg-red-50:hover{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.hover\:text-indigo-600:hover{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:border-indigo-400:focus{--tw-border-opacity:1;border-color:rgb(129 140 248/var(--tw-border-opacity,1))}.focus\:bg-white:focus{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.group:hover .group-hover\:-translate-y-1{--tw-translate-y:-0.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:border-indigo-300{--tw-border-opacity:1;border-color:rgb(165 180 252/var(--tw-border-opacity,1))}.group:hover .group-hover\:bg-indigo-300{--tw-bg-opacity:1;background-color:rgb(165 180 252/var(--tw-bg-opacity,1))}.group:hover .group-hover\:bg-indigo-400{--tw-bg-opacity:1;background-color:rgb(129 140 248/var(--tw-bg-opacity,1))}.group:hover .group-hover\:text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width:640px){.sm\:block{display:block}.sm\:inline{display:inline}.sm\:p-3{padding:.75rem}}@media (min-width:768px){.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}}.expensive-nodes-card{margin-top:20px;background-color:#fff;box-shadow:0 3px 6px #010e291f;width:308px;box-sizing:border-box;border-radius:8px;padding:24px;border:1px solid rgba(1,14,41,.08)}.expensive-nodes-card-header{margin-bottom:8px}.expensive-nodes-card-header h2{margin:0;font-size:14px;color:#2c3e50}.expensive-nodes-card-header span{font-weight:400;color:#bdc3c7}.expensive-nodes-node{font-size:12px;display:flex;justify-content:space-between;align-items:center;padding:8px 6px;border-bottom:1px solid #ecf0f1}.expensive-nodes-node.selected{border:2px solid #0175f6!important;border-radius:8px}.expensive-nodes-node-name{font-size:12px;color:#0c162b99;font-weight:600}.block{display:block}.expensive-nodes-node-percentage{font-size:12px;color:rgba(12,22,43,.8);font-weight:700}.expensive-nodes-progress{display:flex;align-items:center;margin-bottom:16px}.expensive-nodes-progress .ant-progress-line{flex:1}.expensive-nodes-percentage{font-size:14px;color:#2c3e50;font-weight:700;margin-left:8px}.expensive-nodes-node-attributes{display:block}.expensive-nodes-node-title{color:#0c162bcc;font-weight:600;font-size:12px;padding:8px 6px}.custom-statistic{display:flex;align-items:center;margin-bottom:8px}.custom-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:8px}.statistic-title{font-size:14px;color:#595959} \ No newline at end of file diff --git a/cli/frontend/build/_next/static/css/9d505a4476207006.css b/cli/frontend/build/_next/static/css/9d505a4476207006.css deleted file mode 100644 index f57eb9a7..00000000 --- a/cli/frontend/build/_next/static/css/9d505a4476207006.css +++ /dev/null @@ -1,3 +0,0 @@ -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/* -! tailwindcss v3.4.18 | MIT License | https://tailwindcss.com -*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.absolute{position:absolute}.relative{position:relative}.left-0{left:0}.top-0{top:0}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.ml-3{margin-left:.75rem}.mt-1{margin-top:.25rem}.mt-5{margin-top:1.25rem}.box-border{box-sizing:border-box}.inline{display:inline}.flex{display:flex}.table{display:table}.h-1{height:.25rem}.h-4{height:1rem}.h-\[calc\(100vh-48px\)\]{height:calc(100vh - 48px)}.h-full{height:100%}.h-screen{height:100vh}.w-1{width:.25rem}.w-16{width:4rem}.w-32{width:8rem}.w-4{width:1rem}.w-\[100px\]{width:100px}.w-full{width:100%}.max-w-full{max-width:100%}.flex-1{flex:1 1 0%}.border-collapse{border-collapse:collapse}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-2{gap:.5rem}.gap-4{gap:1rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165/var(--tw-border-opacity,1))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-t-transparent{border-top-color:transparent}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21/var(--tw-bg-opacity,1))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline{outline-style:solid}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.drop-shadow,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\:bg-gray-400:hover{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity,1))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:bg-indigo-700:hover{--tw-bg-opacity:1;background-color:rgb(67 56 202/var(--tw-bg-opacity,1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-60:disabled{opacity:.6}.expensive-nodes-card{margin-top:20px;background-color:#fff;box-shadow:0 3px 6px #010e291f;width:308px;box-sizing:border-box;border-radius:8px;padding:24px;border:1px solid rgba(1,14,41,.08)}.expensive-nodes-card-header{margin-bottom:8px}.expensive-nodes-card-header h2{margin:0;font-size:14px;color:#2c3e50}.expensive-nodes-card-header span{font-weight:400;color:#bdc3c7}.expensive-nodes-node{font-size:12px;display:flex;justify-content:space-between;align-items:center;padding:8px 6px;border-bottom:1px solid #ecf0f1}.expensive-nodes-node.selected{border:2px solid #0175f6!important;border-radius:8px}.expensive-nodes-node-name{font-size:12px;color:#0c162b99;font-weight:600}.block{display:block}.expensive-nodes-node-percentage{font-size:12px;color:rgba(12,22,43,.8);font-weight:700}.expensive-nodes-progress{display:flex;align-items:center;margin-bottom:16px}.expensive-nodes-progress .ant-progress-line{flex:1}.expensive-nodes-percentage{font-size:14px;color:#2c3e50;font-weight:700;margin-left:8px}.expensive-nodes-node-attributes{display:block}.expensive-nodes-node-title{color:#0c162bcc;font-weight:600;font-size:12px;padding:8px 6px}.custom-statistic{display:flex;align-items:center;margin-bottom:8px}.custom-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:8px}.statistic-title{font-size:14px;color:#595959} \ No newline at end of file diff --git a/cli/frontend/build/_next/static/js/677.js b/cli/frontend/build/_next/static/js/677.js index d15c4528..de8ef7e3 100644 --- a/cli/frontend/build/_next/static/js/677.js +++ b/cli/frontend/build/_next/static/js/677.js @@ -1 +1 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[677],{7677:function(e,r,t){t.r(r);var a=t(2676),l=t(5271),n=t(6058),s=t(9675),i=t(2327),o=t(987),c=t(9619),d=t(9822),u=t(5122),h=t(8097);let p=t.n(h)()(()=>Promise.all([t.e(553),t.e(736),t.e(336)]).then(t.bind(t,5336)),{loadableGenerated:{webpack:()=>[5336]},ssr:!1});r.default=()=>{let e=(0,n.useRouter)(),r=e.query.slug&&Array.isArray(e.query.slug)?e.query.slug.join("/"):e.query.slug,[t,h]=(0,l.useState)("SELECT number % 7 as a, number % 11 as b, number % 13 as c, count(distinct number) FROM numbers(100000000) group by a, b, c;"),[f,m]=(0,l.useState)("graph"),[g,y]=(0,l.useState)(""),[b,x]=(0,l.useState)(null),[v,w]=(0,l.useState)(!1),[N,j]=(0,l.useState)(""),k=(0,l.useCallback)((e,r)=>{if(!e||0===e.length)return{perfData:"",graphData:null};let t=e[0];if(!t.data||0===t.data.length)return{perfData:"",graphData:null};let a="";if(t.data.forEach(e=>{e&&e.length>0&&(a+=e[0]+"\n")}),1!==r)return{perfData:a.trim(),graphData:null};try{let e=JSON.parse(a.trim());return{perfData:JSON.stringify(e,null,2),graphData:e}}catch(e){return console.error("JSON parsing error:",e),{perfData:a.trim(),graphData:null}}},[]),S=(0,l.useCallback)(async e=>{try{w(!0),j("");let r=await fetch("/api/query/".concat(e));if(r.ok){let e=await r.json();if(h(e.sql),1===e.kind?m("graph"):m("perf"),e.results&&e.results.length>0){let{perfData:r,graphData:t}=k(e.results,e.kind||2);y(r),x(t)}else y(""),x(null)}else j('Run ID "'.concat(e,'" not found')),y("")}catch(r){console.error("Failed to load shared perf query:",r),j('Failed to load run ID "'.concat(e,'"')),y("")}finally{w(!1)}},[k]),E=(0,l.useCallback)(async()=>{if(!t.trim()){alert("Please enter a SQL query");return}w(!0),j("");try{let r="graph"===f?1:2,a=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:t,kind:r})});if(!a.ok)throw Error("HTTP error! status: ".concat(a.status));let l=await a.json(),{perfData:n,graphData:s}=k(l.results,r);y(n),x(s),l.queryId&&e.push("/perf/".concat(l.queryId),void 0,{shallow:!0})}catch(e){console.error("Perf query execution failed:",e),alert("Perf query execution failed: "+e.message)}finally{w(!1)}},[t,e,k,f]);return(0,l.useEffect)(()=>{e.isReady&&r&&"string"==typeof r?S(r):h("SELECT * FROM system.tables LIMIT 10;")},[e.isReady,r,S]),(0,l.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&"Enter"===e.key&&(e.preventDefault(),E())};return window.addEventListener("keydown",e),()=>{window.removeEventListener("keydown",e)}},[E]),(0,l.useEffect)(()=>(window.resizeIframe=function(e){try{if(e&&e.contentWindow&&e.contentWindow.document){let r=e.contentWindow.document.body.scrollHeight;e.style.height=r+"px"}}catch(e){console.warn("Could not resize iframe:",e)}},()=>{delete window.resizeIframe}),[]),(0,a.jsxs)("div",{className:"h-full bg-gray-100",children:[(0,a.jsx)("div",{className:"bg-yellow-400 px-4 py-2 flex items-center justify-between",children:(0,a.jsxs)("div",{className:"flex items-center gap-4",children:[(0,a.jsx)("span",{className:"font-bold",children:"Performance Analysis"}),(0,a.jsxs)("div",{className:"flex items-center gap-2",children:[(0,a.jsxs)("select",{value:f,onChange:e=>m(e.target.value),className:"border border-gray-300 rounded px-2 py-1 text-sm",children:[(0,a.jsx)("option",{value:"perf",children:"Perf"}),(0,a.jsx)("option",{value:"graph",children:"Graph"})]}),(0,a.jsx)("button",{onClick:E,disabled:v,className:"bg-indigo-600 hover:bg-indigo-700 disabled:opacity-60 disabled:cursor-not-allowed text-white px-4 py-1.5 rounded-md flex items-center gap-2 text-sm",children:v?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}),"ANALYZING..."]}):(0,a.jsx)(a.Fragment,{children:"โ–ถ ANALYZE PERFORMANCE"})})]})]})}),(0,a.jsx)("div",{className:"h-[calc(100vh-48px)] border border-gray-300",children:(0,a.jsxs)(d.eh,{direction:"vertical",className:"h-full",children:[(0,a.jsx)(d.s_,{defaultSize:15,minSize:5,maxSize:40,className:"h-full",children:(0,a.jsx)("div",{className:"h-full border-b border-gray-300 relative",children:(0,a.jsx)(s.ZP,{value:t,placeholder:"Enter your SQL query here... (Press Cmd+Enter to analyze performance)",theme:u.tR,height:"100%",extensions:[u.MH,o.tk.lineWrapping,(0,c.ys)({icons:!1}),(0,i.i6)()],basicSetup:{lineNumbers:!0,foldGutter:!1,indentOnInput:!1,autocompletion:!0,highlightActiveLine:!1},onChange:e=>h(e),editable:!v,style:{height:"100%",fontSize:"14px"}})})}),(0,a.jsx)(d.OT,{className:"h-1 bg-gray-300 hover:bg-gray-400 cursor-row-resize"}),(0,a.jsx)(d.s_,{defaultSize:80,minSize:60,className:"h-full",children:(0,a.jsx)("div",{className:"h-full bg-white relative",children:(0,a.jsx)("div",{className:"p-2 h-full",children:N?(0,a.jsx)("div",{className:"flex items-center justify-center h-full",children:(0,a.jsxs)("div",{className:"bg-red-50 border border-red-300 rounded-lg p-4 text-red-700",children:[(0,a.jsx)("div",{className:"font-medium text-red-800 mb-1",children:"Error"}),(0,a.jsx)("div",{className:"text-sm",children:N})]})}):g?"graph"===f&&b?(0,a.jsx)("div",{className:"h-full overflow-auto",children:(0,a.jsx)(p,{perfData:b})}):(0,a.jsx)("div",{className:"h-full overflow-auto p-4 bg-white",dangerouslySetInnerHTML:{__html:g}}):(0,a.jsx)("div",{className:"flex items-center justify-center h-full text-gray-500",children:"Execute a query to see performance analysis"})})})})]})})]})}},5122:function(e,r,t){t.d(r,{MH:function(){return o},tR:function(){return i}});var a=t(1861),l=t(3233),n=t(987);let s={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},i=function(e){let{theme:r="light",settings:t={},styles:n=[]}={};return(0,l.j)({theme:r,settings:{...s,...t},styles:[{tag:[a.pJ.comment,a.pJ.quote],color:"#707F8D"},{tag:[a.pJ.typeName,a.pJ.typeOperator],color:"#aa0d91"},{tag:[a.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[a.pJ.string,a.pJ.meta],color:"#D23423"},{tag:[a.pJ.name],color:"#032f62"},{tag:[a.pJ.typeName],color:"#522BB2"},{tag:[a.pJ.variableName],color:"#23575C"},{tag:[a.pJ.definition(a.pJ.variableName)],color:"#327A9E"},{tag:[a.pJ.regexp,a.pJ.link],color:"#0e0eff"},...n]})}(),o=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}}]); \ No newline at end of file +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[677],{7677:function(e,r,t){t.r(r);var a=t(2676),l=t(5271),n=t(6058),s=t(9675),i=t(2327),o=t(987),c=t(9619),d=t(9822),u=t(5122),h=t(8097);let f=t.n(h)()(()=>Promise.all([t.e(553),t.e(736),t.e(336)]).then(t.bind(t,5336)),{loadableGenerated:{webpack:()=>[5336]},ssr:!1}),p="select number % 3 a, number % 4 b, number % 5 c from numbers(100000000) group by all limit 3;";r.default=()=>{let e=(0,n.useRouter)(),r=e.query.slug&&Array.isArray(e.query.slug)?e.query.slug.join("/"):e.query.slug,[t,h]=(0,l.useState)(p),[m,g]=(0,l.useState)("graph"),[x,b]=(0,l.useState)(""),[y,j]=(0,l.useState)(null),[v,N]=(0,l.useState)(!1),[w,k]=(0,l.useState)(""),D=(0,l.useCallback)((e,r)=>{if(!e||0===e.length)return{perfData:"",graphData:null};let t=e[0];if(!t.data||0===t.data.length)return{perfData:"",graphData:null};let a="";if(t.data.forEach(e=>{e&&e.length>0&&(a+=e[0]+"\n")}),1!==r)return{perfData:a.trim(),graphData:null};try{let e=JSON.parse(a.trim());return{perfData:JSON.stringify(e,null,2),graphData:e}}catch(e){return console.error("JSON parsing error:",e),{perfData:a.trim(),graphData:null}}},[]),S=(0,l.useCallback)(async e=>{try{N(!0),k("");let r=await fetch("/api/query/".concat(e));if(r.ok){let e=await r.json();if(h(e.sql),1===e.kind?g("graph"):g("perf"),e.results&&e.results.length>0){let{perfData:r,graphData:t}=D(e.results,e.kind||2);b(r),j(t)}else b(""),j(null)}else k('Run ID "'.concat(e,'" not found')),b(""),j(null),h(p),g("graph")}catch(r){console.error("Failed to load shared perf query:",r),k('Failed to load run ID "'.concat(e,'"')),b(""),j(null),h(p),g("graph")}finally{N(!1)}},[D]),F=(0,l.useCallback)(async()=>{if(!t.trim()){alert("Please enter a SQL query");return}N(!0),k("");try{let r="graph"===m?1:2,a=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:t,kind:r})});if(!a.ok)throw Error("HTTP error! status: ".concat(a.status));let l=await a.json(),{perfData:n,graphData:s}=D(l.results,r);b(n),j(s),l.queryId&&e.push("/perf/".concat(l.queryId),void 0,{shallow:!0})}catch(e){console.error("Perf query execution failed:",e),alert("Perf query execution failed: "+e.message)}finally{N(!1)}},[t,e,D,m]);(0,l.useEffect)(()=>{e.isReady&&r&&"string"==typeof r&&"0"!==r?S(r):h(p)},[e.isReady,r,S]);let J=(0,l.useMemo)(()=>o.$f.of([{key:"Mod-Enter",run:()=>(F(),!0),preventDefault:!0},{key:"Mod-NumpadEnter",run:()=>(F(),!0),preventDefault:!0}]),[F]);return(0,l.useEffect)(()=>(window.resizeIframe=function(e){try{if(e&&e.contentWindow&&e.contentWindow.document){let r=e.contentWindow.document.body.scrollHeight;e.style.height=r+"px"}}catch(e){console.warn("Could not resize iframe:",e)}},()=>{delete window.resizeIframe}),[]),(0,a.jsxs)("div",{className:"flex flex-1 min-h-0 flex-col bg-[#f9fbff]",children:[(0,a.jsxs)("div",{className:"border-b border-gray-200 bg-white px-4 py-3 flex flex-wrap items-center justify-between gap-3",children:[(0,a.jsx)("div",{className:"text-sm font-semibold text-gray-900",children:"Performance Analysis"}),(0,a.jsxs)("div",{className:"flex items-center gap-2",children:[(0,a.jsxs)("select",{value:m,onChange:e=>g(e.target.value),className:"rounded-full border border-gray-200 px-3 py-1 text-sm text-gray-700",children:[(0,a.jsx)("option",{value:"perf",children:"Perf"}),(0,a.jsx)("option",{value:"graph",children:"Graph"})]}),(0,a.jsx)("button",{onClick:F,disabled:v,className:"inline-flex items-center gap-2 rounded-full border px-4 py-1.5 text-sm font-semibold ".concat(v?"cursor-not-allowed border-gray-200 text-gray-400":"border-indigo-200 text-indigo-600 hover:bg-indigo-50"),children:v?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:"w-3.5 h-3.5 border-2 border-indigo-400 border-t-transparent rounded-full animate-spin"}),"Analyzing..."]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:"text-base",children:"โ–ถ"}),"Analyze"]})})]})]}),(0,a.jsx)("div",{className:"flex-1 min-h-0 border border-gray-200 bg-white",children:(0,a.jsxs)(d.eh,{direction:"vertical",className:"h-full min-h-0",style:{height:"100%"},children:[(0,a.jsx)(d.s_,{defaultSize:25,minSize:10,maxSize:60,className:"h-full min-h-0",children:(0,a.jsx)("div",{className:"h-full min-h-0 border-b border-gray-300 relative",children:(0,a.jsx)(s.ZP,{value:t,placeholder:"Enter your SQL query here... (Press Cmd+Enter to analyze performance)",theme:u.tR,height:"100%",extensions:[u.MH,o.tk.lineWrapping,(0,o.Eu)(),(0,c.ys)({icons:!1}),(0,i.i6)(),J],basicSetup:!1,onChange:e=>h(e),editable:!v,style:{height:"100%",fontSize:"14px"}})})}),(0,a.jsx)(d.OT,{className:"h-1 bg-gray-300 hover:bg-gray-400 cursor-row-resize"}),(0,a.jsx)(d.s_,{defaultSize:75,minSize:40,className:"h-full min-h-0",children:(0,a.jsx)("div",{className:"h-full min-h-0 bg-white relative",children:(0,a.jsx)("div",{className:"p-2 h-full min-h-0",children:w?(0,a.jsx)("div",{className:"flex items-center justify-center h-full",children:(0,a.jsxs)("div",{className:"bg-red-50 border border-red-300 rounded-lg p-4 text-red-700",children:[(0,a.jsx)("div",{className:"font-medium text-red-800 mb-1",children:"Error"}),(0,a.jsx)("div",{className:"text-sm",children:w})]})}):x?"graph"===m&&y?(0,a.jsx)("div",{className:"h-full min-h-0 overflow-auto",children:(0,a.jsx)(f,{perfData:y})}):(0,a.jsx)("div",{className:"h-full min-h-0 overflow-auto p-4 bg-white",dangerouslySetInnerHTML:{__html:x}}):(0,a.jsx)("div",{className:"flex items-center justify-center h-full text-gray-500",children:"Execute a query to see performance analysis"})})})})]})})]})}},5122:function(e,r,t){t.d(r,{MH:function(){return o},tR:function(){return i}});var a=t(1861),l=t(3233),n=t(987);let s={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},i=function(e){let{theme:r="light",settings:t={},styles:n=[]}={};return(0,l.j)({theme:r,settings:{...s,...t},styles:[{tag:[a.pJ.comment,a.pJ.quote],color:"#707F8D"},{tag:[a.pJ.typeName,a.pJ.typeOperator],color:"#aa0d91"},{tag:[a.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[a.pJ.string,a.pJ.meta],color:"#D23423"},{tag:[a.pJ.name],color:"#032f62"},{tag:[a.pJ.typeName],color:"#522BB2"},{tag:[a.pJ.variableName],color:"#23575C"},{tag:[a.pJ.definition(a.pJ.variableName)],color:"#327A9E"},{tag:[a.pJ.regexp,a.pJ.link],color:"#0e0eff"},...n]})}(),o=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}}]); \ No newline at end of file diff --git a/cli/frontend/build/_next/static/js/77.js b/cli/frontend/build/_next/static/js/77.js new file mode 100644 index 00000000..1076556a --- /dev/null +++ b/cli/frontend/build/_next/static/js/77.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[77],{6077:function(e,t,r){r.r(t),r.d(t,{default:function(){return N}});var l=r(2676),o=r(5271),n=r(9822),s=r(9675),a=r(2327),i=r(987),d=r(9619),c=r(5122);function u(e){if(!e)return"";let t=e instanceof Date?e:new Date(e);if(isNaN(t.getTime()))return"";let r=Date.now()-t.getTime();return r<6e4?"just now":r<36e5?"".concat(Math.floor(r/6e4),"m ago"):r<864e5?"".concat(Math.floor(r/36e5),"h ago"):r<6048e5?"".concat(Math.floor(r/864e5),"d ago"):t.toLocaleDateString()}let x=e=>(0,l.jsx)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:(0,l.jsx)("path",{d:"M7 5v10l7-5-7-5z",fill:"currentColor",stroke:"none"})}),g=e=>(0,l.jsx)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:(0,l.jsx)("path",{d:"M6 8l4 4 4-4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"})}),p=e=>(0,l.jsx)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:(0,l.jsx)("path",{d:"M6 12l4-4 4 4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"})}),h=e=>(0,l.jsxs)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:[(0,l.jsx)("rect",{x:"4",y:"4",width:"5",height:"12",rx:"1.5"}),(0,l.jsx)("rect",{x:"11",y:"4",width:"5",height:"12",rx:"1.5"})]}),b=e=>(0,l.jsxs)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:[(0,l.jsx)("path",{d:"M7 6 4 10l3 4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"}),(0,l.jsx)("path",{d:"m13 6 3 4-3 4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"})]}),m=e=>(0,l.jsxs)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:[(0,l.jsx)("circle",{cx:"7",cy:"6",r:"1"}),(0,l.jsx)("circle",{cx:"13",cy:"6",r:"1"}),(0,l.jsx)("circle",{cx:"7",cy:"10",r:"1"}),(0,l.jsx)("circle",{cx:"13",cy:"10",r:"1"}),(0,l.jsx)("circle",{cx:"7",cy:"14",r:"1"}),(0,l.jsx)("circle",{cx:"13",cy:"14",r:"1"})]}),f=e=>(0,l.jsxs)("svg",{viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",...e,children:[(0,l.jsx)("path",{d:"M8 4H4v4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"}),(0,l.jsx)("path",{d:"M12 4h4v4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"}),(0,l.jsx)("path",{d:"M8 16H4v-4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"}),(0,l.jsx)("path",{d:"M12 16h4v-4",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"})]}),v=e=>(0,l.jsxs)("svg",{viewBox:"0 0 20 20",fill:"currentColor",stroke:"none",...e,children:[(0,l.jsx)("circle",{cx:"5",cy:"10",r:"1.5"}),(0,l.jsx)("circle",{cx:"10",cy:"10",r:"1.5"}),(0,l.jsx)("circle",{cx:"15",cy:"10",r:"1.5"})]});var y=e=>{var t;let{cell:r,index:n,isActive:y,canDelete:j,onSqlChange:w,onExecute:k,onDelete:N,onSelect:C,onToggleCollapse:D,onToggleEditor:E,onToggleResult:S,onToggleFullscreen:A,onMoveUp:L,onMoveDown:M,isFullscreen:R=!1,dragState:F,onDragStart:P,onDragEnd:q,onDragOver:B,onDrop:J,onRunFromHere:O=()=>{},onRunToHere:T=()=>{}}=e,z=(0,o.useRef)(null),[_,I]=(0,o.useState)(!1),W=(0,o.useRef)(null),[H,Q]=(0,o.useState)(!1),U=(0,o.useRef)(null);(0,o.useEffect)(()=>{if(!_)return;let e=e=>{W.current&&!W.current.contains(e.target)&&I(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[_]),(0,o.useEffect)(()=>{if(!H)return;let e=e=>{U.current&&!U.current.contains(e.target)&&Q(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[H]);let Y=!r.hideEditor&&!r.collapsed,X=!r.hideResult&&!r.collapsed,Z=(0,o.useMemo)(()=>r.loading?"Running query":r.lastExecutedAt?"Ran ".concat(u(r.lastExecutedAt)):"Ready to run",[r.loading,r.lastExecutedAt]),$=["flex","gap-3","rounded-2xl","border","bg-white/95","backdrop-blur-[2px]","transition-all",F.isDragOver?"ring-1 ring-indigo-300 border-indigo-300":"border-gray-100",R?"shadow-[0_0_0_2px_rgba(99,102,241,0.35)] border-indigo-300":y?"shadow-[0_15px_35px_-20px_rgba(79,70,229,0.45)]":"shadow-sm hover:shadow-md hover:border-gray-200",r.loading?"ring-1 ring-blue-300 border-blue-200 bg-blue-50/80":""].join(" "),G="absolute left-0 right-0 h-1 bg-indigo-500/80 rounded-full transition-opacity pointer-events-none opacity-0",K=F.isDragOver?"after"===F.dragOverPosition?"translate-y-1.5":"-translate-y-1.5":"translate-y-0",V=F.isDragOver&&"before"===F.dragOverPosition,ee=F.isDragOver&&"after"===F.dragOverPosition,et="auto",er=!R,el=(0,o.useMemo)(()=>i.$f.of([{key:"Mod-Enter",run:()=>(k(),!0),preventDefault:!0},{key:"Mod-NumpadEnter",run:()=>(k(),!0),preventDefault:!0},{key:"Alt-Enter",run:()=>(null==O||O(),!0),preventDefault:!0},{key:"Shift-Enter",run:()=>(null==T||T(),!0),preventDefault:!0}]),[k,O,T]),eo=e=>{if(!z.current)return!1;let t=z.current.getBoundingClientRect();return e.clientY-t.top>t.height/2};return(0,l.jsxs)("div",{className:"relative",children:[V&&(0,l.jsx)("div",{className:"".concat(G," top-0 opacity-100")}),(0,l.jsxs)("div",{ref:z,className:"".concat($," ").concat(R?"h-full min-h-[calc(100vh-180px)]":""," ").concat(F.isDragging?"opacity-50 cursor-grabbing":""," transform transition-transform duration-150 ").concat(K),onClick:C,draggable:!R,onDragStart:e=>{if(e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",r.id),z.current){let t=z.current.getBoundingClientRect();e.dataTransfer.setDragImage(z.current,e.clientX-t.left,e.clientY-t.top)}P()},onDragEnd:e=>{e.preventDefault(),q()},onDragOver:e=>{e.preventDefault(),B(eo(e))},onDrop:e=>{e.preventDefault(),J(eo(e))},children:[er&&(0,l.jsxs)("div",{className:"flex flex-col items-center gap-2 border-r border-gray-100 px-2 py-3",children:[(0,l.jsx)("div",{className:"cursor-grab rounded-full border bg-white p-2 text-gray-400 hover:text-gray-600 ".concat(F.isDragging?"border-indigo-300 text-indigo-500 cursor-grabbing":"border-gray-200"),children:(0,l.jsx)(m,{className:"h-4 w-4"})}),(0,l.jsxs)("div",{className:"flex flex-col gap-1 text-gray-400",children:[(0,l.jsx)("button",{type:"button",onClick:e=>{e.stopPropagation(),D()},className:"rounded-md border px-1.5 py-1 text-xs ".concat(r.collapsed?"border-indigo-300 text-indigo-500":"border-gray-200 hover:text-gray-600"),title:r.collapsed?"Expand cell":"Collapse cell",children:r.collapsed?(0,l.jsx)(g,{className:"h-3 w-3"}):(0,l.jsx)(p,{className:"h-3 w-3"})}),!r.collapsed&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)("button",{type:"button",onClick:e=>{e.stopPropagation(),E()},className:"rounded-md border px-1.5 py-1 text-xs ".concat(r.hideEditor?"border-indigo-300 text-indigo-500":"border-gray-200 hover:text-gray-600"),title:r.hideEditor?"Show SQL editor":"Collapse SQL editor",children:(0,l.jsx)(b,{className:"h-3.5 w-3.5"})}),(0,l.jsx)("button",{type:"button",onClick:e=>{e.stopPropagation(),S()},className:"rounded-md border px-1.5 py-1 text-xs ".concat(r.hideResult?"border-indigo-300 text-indigo-500":"border-gray-200 hover:text-gray-600"),title:r.hideResult?"Show results":"Collapse results",children:(0,l.jsx)(h,{className:"h-3.5 w-3.5"})})]})]})]}),(0,l.jsxs)("div",{className:"flex-1 ".concat(er?"p-3":"p-1 sm:p-3"," ").concat(er?"":"md:px-6"),draggable:!1,children:[(0,l.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,l.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-500",children:[(0,l.jsxs)("div",{className:"relative",ref:U,onMouseEnter:()=>{!r.loading&&r.sql.trim()&&Q(!0)},onMouseLeave:()=>Q(!1),children:[(0,l.jsx)("button",{type:"button",onClick:e=>{e.stopPropagation(),!r.loading&&r.sql.trim()&&(k(),Q(!1))},disabled:r.loading||!r.sql.trim(),className:"flex h-8 w-8 items-center justify-center rounded-full border text-sm font-semibold transition ".concat(r.loading||!r.sql.trim()?"border-gray-200 text-gray-400 cursor-not-allowed":H?"border-indigo-400 text-indigo-600 bg-indigo-50":"border-gray-300 text-gray-600 hover:border-indigo-300 hover:text-indigo-600"),title:"Run cell",children:(0,l.jsx)(x,{className:"h-4 w-4"})}),H&&!r.loading&&r.sql.trim()&&(0,l.jsxs)("div",{className:"absolute left-0 mt-2 w-44 rounded-xl border border-gray-200 bg-white shadow-lg z-10",children:[(0,l.jsxs)("button",{className:"flex w-full items-center justify-between px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:e=>{e.stopPropagation(),k(),Q(!1)},children:["Run cell",(0,l.jsx)("span",{className:"text-xs text-gray-400",children:"โŒ˜โŽ"})]}),(0,l.jsxs)("button",{className:"flex w-full items-center justify-between px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:e=>{e.stopPropagation(),O(),Q(!1)},children:["Run from here",(0,l.jsx)("span",{className:"text-xs text-gray-400",children:"โŒฅโŽ"})]}),(0,l.jsxs)("button",{className:"flex w-full items-center justify-between px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:e=>{e.stopPropagation(),T(),Q(!1)},children:["Run to here",(0,l.jsx)("span",{className:"text-xs text-gray-400",children:"โ‡งโŽ"})]})]})]}),(0,l.jsx)("span",{className:"inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-semibold ".concat(r.loading?"bg-blue-100 text-blue-700":"bg-gray-100 text-gray-600"),children:Z})]}),(0,l.jsxs)("div",{className:"flex items-center gap-2",children:[(0,l.jsx)("button",{type:"button",onClick:e=>{e.stopPropagation(),A()},className:"rounded-full border p-1.5 text-gray-500 hover:text-gray-700 ".concat(R?"border-indigo-300 text-indigo-500":"border-gray-200 hover:border-gray-300"),title:R?"Exit fullscreen":"Fullscreen cell",children:(0,l.jsx)(f,{className:"h-4 w-4"})}),!R&&(0,l.jsxs)("div",{className:"relative",ref:W,children:[(0,l.jsx)("button",{type:"button",onClick:e=>{e.stopPropagation(),I(e=>!e)},className:"rounded-full border border-gray-200 p-1.5 text-gray-400 hover:border-gray-300 hover:text-gray-600",title:"Cell options",children:(0,l.jsx)(v,{className:"h-4 w-4"})}),_&&(0,l.jsxs)("div",{className:"absolute right-0 mt-2 w-40 rounded-xl border border-gray-200 bg-white shadow-lg z-10",children:[(0,l.jsxs)("button",{className:"flex w-full items-center justify-between px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:e=>{e.stopPropagation(),L(),I(!1)},children:["Move cell up",(0,l.jsx)("span",{className:"text-xs text-gray-400",children:"โŒ˜โ†‘"})]}),(0,l.jsxs)("button",{className:"flex w-full items-center justify-between px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:e=>{e.stopPropagation(),M(),I(!1)},children:["Move cell down",(0,l.jsx)("span",{className:"text-xs text-gray-400",children:"โŒ˜โ†“"})]}),j&&(0,l.jsx)("button",{className:"flex w-full items-center justify-between px-3 py-2 text-sm text-red-600 hover:bg-red-50",onClick:e=>{e.stopPropagation(),N(),I(!1)},children:"Delete"})]})]})]})]}),!r.collapsed&&(0,l.jsxs)("div",{className:"mt-2 space-y-3 ".concat(R?"flex-1 flex flex-col overflow-hidden":""),onClick:C,children:[Y?(0,l.jsx)("div",{className:"rounded-xl bg-white",children:(0,l.jsx)(s.ZP,{value:r.sql,theme:c.tR,height:et,extensions:[c.MH,i.tk.lineWrapping,(0,i.Eu)(),(0,d.ys)({icons:!1}),(0,a.i6)(),el],basicSetup:!1,onChange:w,editable:!r.loading,onFocus:C,style:{fontSize:"14px",height:et,minHeight:"44px"}})}):(0,l.jsxs)("div",{className:"w-full rounded-xl border border-dashed border-gray-200 px-3 py-2 text-left text-sm text-gray-600 bg-white cursor-pointer hover:border-indigo-300 hover:text-indigo-600",onClick:e=>{e.stopPropagation(),E()},children:[(0,l.jsx)("div",{className:"font-mono whitespace-pre-wrap overflow-hidden",style:{maxHeight:"48px"},children:r.sql||"SQL editor collapsed"}),(0,l.jsx)("div",{className:"text-xs text-indigo-500 font-semibold mt-1",children:"Show editor"})]}),r.error&&X&&(0,l.jsx)("div",{className:"rounded-xl border border-red-200 bg-red-50 p-3 text-sm text-red-700",children:r.error}),!r.error&&X&&r.result&&(0,l.jsxs)("div",{className:"".concat(R?"flex-1 flex flex-col":""),children:[(0,l.jsxs)("div",{className:"text-xs font-semibold uppercase tracking-wide text-gray-400",children:[r.result.rowCount," row",1===r.result.rowCount?"":"s"," returned ",r.result.duration?"in ".concat(r.result.duration):""]}),(0,l.jsx)("div",{className:"".concat(R?"flex-1 overflow-auto rounded-xl border border-gray-100 bg-white mt-2":"space-y-3"),children:(t=r.result).data&&0!==t.data.length?(0,l.jsx)("div",{className:"rounded-lg border border-gray-200 overflow-hidden",children:(0,l.jsx)("div",{className:"overflow-auto max-h-72",children:(0,l.jsxs)("table",{className:"min-w-full text-sm",children:[(0,l.jsx)("thead",{className:"bg-gray-50",children:(0,l.jsx)("tr",{children:t.columns.map((e,r)=>(0,l.jsxs)("th",{className:"px-4 py-3 text-left font-semibold text-gray-700",children:[(0,l.jsx)("div",{children:e}),t.types&&t.types[r]&&(0,l.jsx)("div",{className:"text-xs text-gray-400",children:t.types[r]})]},e+r))})}),(0,l.jsx)("tbody",{children:t.data.map((e,t)=>(0,l.jsx)("tr",{className:t%2==0?"bg-white":"bg-gray-50",children:e.map((e,t)=>(0,l.jsx)("td",{className:"px-4 py-2 text-gray-800 font-mono text-xs",children:e},t))},t))})]})})}):(0,l.jsx)("div",{className:"rounded-lg border border-gray-200 bg-gray-50 p-3 text-center text-sm text-gray-500",children:"No data returned"})})]}),!r.error&&!X&&!r.collapsed]})]})]}),ee&&(0,l.jsx)("div",{className:"".concat(G," bottom-0 opacity-100")})]})};let j="bendsql-notebooks",w={getNotebooks(){try{let e=localStorage.getItem(j);if(e){let t=JSON.parse(e);return{notebooks:t.notebooks.map(e=>({...e,createdAt:new Date(e.createdAt),updatedAt:new Date(e.updatedAt),cells:e.cells.map(e=>{var t,r,l;return{...e,collapsed:null!==(t=e.collapsed)&&void 0!==t&&t,hideEditor:null!==(r=e.hideEditor)&&void 0!==r&&r,hideResult:null!==(l=e.hideResult)&&void 0!==l&&l,lastExecutedAt:e.lastExecutedAt?new Date(e.lastExecutedAt):void 0}})})),currentNotebookId:t.currentNotebookId}}}catch(e){console.error("Failed to load notebooks from storage:",e)}return{notebooks:[]}},saveNotebooks(e){try{localStorage.setItem(j,JSON.stringify(e))}catch(e){console.error("Failed to save notebooks to storage:",e)}},createNotebook(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"Untitled Notebook",t=new Date;return{id:k(),name:e,cells:[{id:k(),sql:"",loading:!1,collapsed:!1,hideEditor:!1,hideResult:!1}],createdAt:t,updatedAt:t}},createCell:()=>({id:k(),sql:"",loading:!1,collapsed:!1,hideEditor:!1,hideResult:!1})};function k(){return Date.now().toString(36)+Math.random().toString(36).substr(2)}var N=()=>{let[e,t]=(0,o.useState)([]),[r,s]=(0,o.useState)(null),[a,i]=(0,o.useState)(null),[d,c]=(0,o.useState)(""),[x,g]=(0,o.useState)(null),[p,h]=(0,o.useState)({id:null,placeAfter:!1}),[b,m]=(0,o.useState)(null),[f,j]=(0,o.useState)(!1),[k,N]=(0,o.useState)(null),C=(0,o.useRef)(null),D=(0,o.useRef)(null),[E,S]=(0,o.useState)(!1),A=(0,o.useRef)(null);(0,o.useEffect)(()=>{A.current=r},[r]),(0,o.useEffect)(()=>{let e=w.getNotebooks();t(e.notebooks);let r=e.notebooks[0];if(e.currentNotebookId){let t=e.notebooks.find(t=>t.id===e.currentNotebookId);t&&(r=t)}if(r){var l,o;s(r),i(null!==(o=null===(l=r.cells[0])||void 0===l?void 0:l.id)&&void 0!==o?o:null)}},[]),(0,o.useEffect)(()=>{e.length>0&&w.saveNotebooks({notebooks:e,currentNotebookId:null==r?void 0:r.id})},[e,r]),(0,o.useEffect)(()=>{if(!r){i(null);return}if(!r.cells.some(e=>e.id===a)){var e,t;i(null!==(t=null===(e=r.cells[0])||void 0===e?void 0:e.id)&&void 0!==t?t:null)}},[r,a]),(0,o.useEffect)(()=>{if(!f)return;let e=e=>{D.current&&!D.current.contains(e.target)&&j(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[f]),(0,o.useEffect)(()=>{if(!k)return;let e=e=>{e.target.closest("[data-notebook-menu]")||N(null)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[k]);let L=(0,o.useMemo)(()=>{if(!d.trim())return e;let t=d.toLowerCase();return e.filter(e=>e.name.toLowerCase().includes(t))},[e,d]),M=(0,o.useCallback)(()=>{var e,r;let l=w.createNotebook();t(e=>[...e,l]),s(l),i(null!==(r=null===(e=l.cells[0])||void 0===e?void 0:e.id)&&void 0!==r?r:null)},[]),R=(0,o.useCallback)(t=>{var r,l;let o=e.find(e=>e.id===t);o&&(s(o),i(null!==(l=null===(r=o.cells[0])||void 0===r?void 0:r.id)&&void 0!==l?l:null))},[e]),F=(0,o.useCallback)((e,l)=>{t(t=>t.map(t=>t.id===e?{...t,name:l,updatedAt:new Date}:t)),(null==r?void 0:r.id)===e&&s(e=>e?{...e,name:l,updatedAt:new Date}:null)},[r]),P=(0,o.useCallback)(e=>{if(!r)return;let l=w.createCell(),o=[...r.cells],n=Math.max(0,Math.min(e,o.length));o.splice(n,0,l);let a={...r,cells:o,updatedAt:new Date};i(l.id),s(a),t(e=>e.map(e=>e.id===a.id?a:e))},[r]),q=(0,o.useCallback)(()=>{var e;null===(e=C.current)||void 0===e||e.focus()},[]),B=(0,o.useCallback)(()=>{s(null),i(null),m(null)},[]),J=(0,o.useCallback)(()=>{if(!r)return;let e=w.createCell(),l={...r,cells:[e],updatedAt:new Date};s(l),t(e=>e.map(e=>e.id===l.id?l:e)),i(e.id),m(null)},[r]),O=(0,o.useCallback)(e=>{t(t=>{if(-1===t.findIndex(t=>t.id===e))return t;let l=t.filter(t=>t.id!==e);if((null==r?void 0:r.id)===e){var o,n;let e=l.length>0?l[0]:null;s(e),i(null!==(n=null==e?void 0:null===(o=e.cells[0])||void 0===o?void 0:o.id)&&void 0!==n?n:null),m(null)}return l}),N(null)},[r]),T=(0,o.useCallback)(()=>{m(null)},[]),z=(0,o.useCallback)((e,l)=>{if(!r)return;let o={...r,cells:r.cells.map(t=>t.id===e?{...t,sql:l}:t),updatedAt:new Date};s(o),t(e=>e.map(e=>e.id===o.id?o:e))},[r]),_=(0,o.useCallback)((e,l)=>{if(!r)return;let o={...r,cells:r.cells.map(t=>t.id===e?{...t,[l]:!t[l]}:t),updatedAt:new Date};s(o),t(e=>e.map(e=>e.id===o.id?o:e))},[r]),I=(0,o.useCallback)(function(e,l){let o=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(!r||e===l)return!1;let n=[...r.cells],a=n.findIndex(t=>t.id===e),d=n.findIndex(e=>e.id===l);if(-1===a||-1===d)return!1;let[c]=n.splice(a,1);n.splice(o?d+1:d,0,c);let u={...r,cells:n,updatedAt:new Date};return s(u),t(e=>e.map(e=>e.id===u.id?u:e)),i(c.id),!0},[r]),W=(0,o.useCallback)((e,t)=>{if(!r)return;let l=r.cells,o=l.findIndex(t=>t.id===e);if(-1===o)return;let n="up"===t?o-1:o+1;n<0||n>=l.length||I(e,l[n].id,"down"===t)},[r,I]),H=(0,o.useCallback)(e=>{g(e),h({id:null,placeAfter:!1})},[]),Q=(0,o.useCallback)(()=>{g(null),h({id:null,placeAfter:!1})},[]),U=(0,o.useCallback)(function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];x&&x!==e&&I(x,e,t)&&h({id:e,placeAfter:t})},[x,I]),Y=(0,o.useCallback)(function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];x&&x!==e&&I(x,e,t),g(null),h({id:null,placeAfter:!1})},[x,I]),X=(0,o.useCallback)(async e=>{let r=A.current;if(!r)return{success:!1};let l=r.cells.find(t=>t.id===e);if(!l||!l.sql.trim())return{success:!1};i(e);let o={...r,cells:r.cells.map(t=>t.id===e?{...t,loading:!0,error:void 0,result:void 0}:t)};s(o),A.current=o;try{let r=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:l.sql,kind:0})});if(!r.ok){let e="HTTP error! status: ".concat(r.status);try{let t=await r.json();t.error&&(e=t.error)}catch(e){}throw Error(e)}let n=(await r.json()).results||[],a=n.length>0?n[n.length-1]:void 0,i={...o,cells:o.cells.map(t=>t.id===e?{...t,loading:!1,result:a,error:void 0,lastExecutedAt:new Date}:t),updatedAt:new Date};return s(i),A.current=i,t(e=>e.map(e=>e.id===i.id?i:e)),{success:!0}}catch(n){console.error("Cell execution failed:",n);let r=n.message.replace(/\\n/g,"\n"),l={...o,cells:o.cells.map(t=>t.id===e?{...t,loading:!1,error:"Query execution failed: "+r,result:void 0}:t),updatedAt:new Date};return s(l),A.current=l,t(e=>e.map(e=>e.id===l.id?l:e)),{success:!1,error:r}}},[]),Z=(0,o.useCallback)(async e=>{let t=A.current;if(t)for(let r of t.cells.slice(e).map(e=>e.id)){let e=await X(r);if(!(null==e?void 0:e.success))break}},[X]),$=(0,o.useCallback)(async e=>{let t=A.current;if(t)for(let r of t.cells.slice(0,Math.min(e+1,t.cells.length)).map(e=>e.id)){let e=await X(r);if(!(null==e?void 0:e.success))break}},[X]);(0,o.useEffect)(()=>{if(!b)return;let e=e=>{"Escape"===e.key&&(e.preventDefault(),T())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[b,T]);let G=(0,o.useCallback)(e=>{if(!r||r.cells.length<=1)return;let l=r.cells.findIndex(t=>t.id===e),o=r.cells[l+1]||r.cells[l-1],n={...r,cells:r.cells.filter(t=>t.id!==e),updatedAt:new Date};i(t=>{var r;return t===e?null!==(r=null==o?void 0:o.id)&&void 0!==r?r:null:t}),s(n),t(e=>e.map(e=>e.id===n.id?n:e)),m(t=>t===e?null:t)},[r]),K=(e,t)=>{if(b)return null;let r="between"===e?"Add cell between":"above"===e?"Add cell above":"Add cell below";return(0,l.jsxs)("button",{type:"button",onClick:()=>P(t),className:"group relative flex w-full items-center justify-center py-1 focus:outline-none",title:r,children:[(0,l.jsx)("span",{className:"pointer-events-none h-px w-full bg-gray-200 transition-colors group-hover:bg-indigo-300"}),(0,l.jsxs)("span",{className:"pointer-events-none absolute left-1/2 -translate-x-1/2 -translate-y-1/2 whitespace-nowrap rounded-full border border-gray-200 bg-white px-3 py-1 text-xs font-semibold text-gray-600 opacity-0 shadow group-hover:-translate-y-1 group-hover:opacity-100 group-hover:border-indigo-300 group-hover:text-indigo-600",children:["+ ",r]})]},"add-control-".concat(t))};return(0,l.jsxs)("div",{className:"relative flex h-full flex-1 flex-col bg-[#f4f6fb]",children:[(0,l.jsxs)(n.eh,{direction:"horizontal",className:"flex-1 overflow-hidden",children:[(0,l.jsx)(n.s_,{defaultSize:15,minSize:15,maxSize:30,className:"h-full",children:(0,l.jsxs)("div",{className:"flex h-full flex-col border-r border-gray-200 bg-white",children:[(0,l.jsxs)("div",{className:"p-3 border-b border-gray-100",children:[(0,l.jsx)("label",{className:"text-xs font-semibold uppercase tracking-wide text-gray-400 mb-2 block",children:"Search"}),(0,l.jsxs)("div",{className:"relative",children:[(0,l.jsx)("span",{className:"absolute inset-y-0 left-3 flex items-center text-gray-400",children:(0,l.jsxs)("svg",{className:"h-4 w-4",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",children:[(0,l.jsx)("path",{d:"m13.5 13.5 3 3",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round"}),(0,l.jsx)("circle",{cx:"9",cy:"9",r:"5.5",strokeWidth:"1.6"})]})}),(0,l.jsx)("input",{value:d,onChange:e=>c(e.target.value),placeholder:"Find notebook",className:"w-full rounded-lg border border-gray-200 bg-gray-50 pl-8 pr-3 py-2 text-sm text-gray-700 focus:border-indigo-400 focus:bg-white focus:outline-none"})]})]}),(0,l.jsxs)("div",{className:"flex-1 overflow-y-auto",children:[(0,l.jsxs)("div",{className:"flex items-center justify-between px-3 py-2 text-xs font-semibold uppercase tracking-wide text-gray-500",children:[(0,l.jsxs)("button",{type:"button",className:"inline-flex items-center gap-2 rounded-full border border-transparent px-2 py-1 text-xs font-semibold text-gray-500 hover:text-gray-700",onClick:()=>S(e=>!e),children:[(0,l.jsx)("span",{children:E?"โ–ถ":"โ–ผ"}),(0,l.jsx)("span",{children:"Notebooks"})]}),(0,l.jsx)("button",{type:"button",onClick:M,className:"rounded-full border border-gray-200 px-2 py-1 text-sm font-semibold text-gray-600 hover:border-indigo-300 hover:text-indigo-600",title:"Add notebook",children:"+"})]}),!E&&(0,l.jsxs)("div",{className:"px-2 pb-3 space-y-1",children:[0===L.length&&(0,l.jsx)("div",{className:"text-center text-sm text-gray-500 px-2 py-4",children:"No notebooks found"}),L.map(e=>{let t=(null==r?void 0:r.id)===e.id,o=k===e.id;return(0,l.jsx)("div",{className:"space-y-1","data-notebook-menu":o?"true":void 0,children:(0,l.jsxs)("button",{onClick:()=>R(e.id),className:"w-full text-left px-3 py-2 rounded-lg border transition-all ".concat(t?"border-indigo-300 bg-indigo-50/70 text-indigo-700":"border-transparent hover:border-gray-200 hover:bg-gray-50"),children:[(0,l.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,l.jsx)("span",{className:"font-semibold text-sm truncate",children:e.name||"Untitled Notebook"}),(0,l.jsxs)("div",{className:"flex items-center gap-2 text-[10px] text-gray-400",children:[(0,l.jsx)("span",{className:"uppercase",children:u(e.updatedAt)||"new"}),(0,l.jsxs)("div",{className:"relative","data-notebook-menu-button":!0,children:[(0,l.jsx)("button",{type:"button",onClick:t=>{t.stopPropagation(),N(t=>t===e.id?null:e.id)},className:"rounded-full border p-1 transition ".concat(o?"border-indigo-300 text-indigo-600":"border-gray-200 text-gray-500 hover:border-gray-300"),title:"Notebook options",children:(0,l.jsx)(v,{className:"h-3.5 w-3.5"})}),o&&(0,l.jsx)("div",{className:"absolute right-0 mt-2 w-40 rounded-xl border border-gray-200 bg-white shadow-lg z-10",children:(0,l.jsx)("button",{type:"button",onClick:()=>{O(e.id),N(null)},className:"flex w-full items-center gap-2 px-3 py-2 text-sm text-red-600 hover:bg-red-50",children:"Delete notebook"})})]})]})]}),(0,l.jsxs)("div",{className:"text-xs text-gray-500 mt-1",children:[e.cells.length," cell",1===e.cells.length?"":"s"]})]})},e.id)})]})]})]})}),(0,l.jsx)(n.OT,{className:"group flex w-3 cursor-col-resize items-center justify-center",children:(0,l.jsx)("span",{className:"h-10 w-0.5 rounded-full bg-gray-200 group-hover:bg-indigo-400"})}),(0,l.jsx)(n.s_,{defaultSize:60,minSize:40,className:"h-full",children:(0,l.jsx)("div",{className:"flex h-full flex-col overflow-hidden",children:r?(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)("header",{className:"border-b border-gray-200 bg-white px-4 py-3 flex items-center justify-between gap-3",children:[(0,l.jsxs)("div",{className:"min-w-0",children:[(0,l.jsx)("input",{ref:C,type:"text",value:r.name,onChange:e=>F(r.id,e.target.value),className:"w-full border-none bg-transparent text-xl font-semibold text-gray-900 focus:outline-none",placeholder:"Notebook name"}),(0,l.jsxs)("p",{className:"text-xs text-gray-500 mt-1",children:["Updated ",u(r.updatedAt)||"just now"," \xb7 ",r.cells.length," cell",1===r.cells.length?"":"s"]})]}),(0,l.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-500",children:[(0,l.jsx)("span",{className:"hidden sm:inline",children:"โŒ˜โŽ to run cell"}),(0,l.jsxs)("div",{className:"relative",ref:D,children:[(0,l.jsx)("button",{type:"button",onClick:()=>j(e=>!e),className:"rounded-full border p-1.5 transition ".concat(f?"border-indigo-300 text-indigo-600":"border-gray-200 text-gray-500 hover:border-gray-300"),title:"Notebook options",children:(0,l.jsx)(v,{className:"h-4 w-4"})}),f&&(0,l.jsxs)("div",{className:"absolute right-0 mt-2 w-44 rounded-xl border border-gray-200 bg-white shadow-lg z-10",children:[(0,l.jsx)("button",{className:"flex w-full items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>{q(),j(!1)},children:"Rename"}),(0,l.jsx)("button",{className:"flex w-full items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>{B(),j(!1)},children:"Close"}),(0,l.jsx)("button",{className:"flex w-full items-center gap-2 px-3 py-2 text-sm text-red-600 hover:bg-red-50",onClick:()=>{J(),j(!1)},children:"Delete all cells"})]})]})]})]}),(0,l.jsxs)("div",{className:"flex-1 overflow-y-auto px-4 py-4 ".concat(b?"space-y-0":"space-y-3"),children:[!b&&K("above",0),r.cells.map((e,t)=>b&&e.id!==b?null:(0,l.jsxs)(o.Fragment,{children:[(0,l.jsx)(y,{cell:e,index:t,onSqlChange:t=>z(e.id,t),onExecute:()=>X(e.id),onDelete:()=>G(e.id),canDelete:r.cells.length>1,isActive:e.id===a||b===e.id,onSelect:()=>i(e.id),onToggleCollapse:()=>_(e.id,"collapsed"),onToggleEditor:()=>_(e.id,"hideEditor"),onToggleResult:()=>_(e.id,"hideResult"),onToggleFullscreen:()=>m(t=>t===e.id?null:e.id),isFullscreen:b===e.id,onMoveUp:()=>W(e.id,"up"),onMoveDown:()=>W(e.id,"down"),dragState:{isDragging:x===e.id,isDragOver:p.id===e.id,dragOverPosition:p.id===e.id?p.placeAfter?"after":"before":void 0},onDragStart:()=>H(e.id),onDragEnd:Q,onDragOver:t=>U(e.id,t),onDrop:t=>Y(e.id,t),onRunFromHere:()=>{Z(t)},onRunToHere:()=>{$(t)}}),!b&&K(t===r.cells.length-1?"below":"between",t+1)]},e.id)),!b&&K("below",r.cells.length)]})]}):(0,l.jsx)("div",{className:"flex-1 flex items-center justify-center",children:(0,l.jsxs)("div",{className:"text-center max-w-xs",children:[(0,l.jsx)("p",{className:"text-lg font-semibold text-gray-800 mb-2",children:"No notebooks yet"}),(0,l.jsx)("p",{className:"text-sm text-gray-500 mb-4",children:"Create your first notebook to start experimenting with queries."}),(0,l.jsx)("button",{onClick:M,className:"rounded-xl bg-indigo-600 px-5 py-2 text-sm font-medium text-white hover:bg-indigo-500",children:"Create Notebook"})]})})})})]}),b&&(0,l.jsx)("div",{className:"absolute inset-x-0 top-[68px] z-10 flex justify-end px-6",children:(0,l.jsx)("button",{onClick:T,className:"rounded-full border border-gray-300 bg-white px-3 py-1 text-xs font-semibold text-gray-600 shadow-sm hover:border-gray-400",children:"Exit fullscreen โŽ‹"})})]})}},5122:function(e,t,r){r.d(t,{MH:function(){return i},tR:function(){return a}});var l=r(1861),o=r(3233),n=r(987);let s={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},a=function(e){let{theme:t="light",settings:r={},styles:n=[]}={};return(0,o.j)({theme:t,settings:{...s,...r},styles:[{tag:[l.pJ.comment,l.pJ.quote],color:"#707F8D"},{tag:[l.pJ.typeName,l.pJ.typeOperator],color:"#aa0d91"},{tag:[l.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[l.pJ.string,l.pJ.meta],color:"#D23423"},{tag:[l.pJ.name],color:"#032f62"},{tag:[l.pJ.typeName],color:"#522BB2"},{tag:[l.pJ.variableName],color:"#23575C"},{tag:[l.pJ.definition(l.pJ.variableName)],color:"#327A9E"},{tag:[l.pJ.regexp,l.pJ.link],color:"#0e0eff"},...n]})}(),i=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}}]); \ No newline at end of file diff --git a/cli/frontend/build/_next/static/js/pages/[...slug].js b/cli/frontend/build/_next/static/js/pages/[...slug].js index 9117d55c..9bcafccd 100644 --- a/cli/frontend/build/_next/static/js/pages/[...slug].js +++ b/cli/frontend/build/_next/static/js/pages/[...slug].js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[330],{923:function(e,r,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/[...slug]",function(){return t(2093)}])},2093:function(e,r,t){"use strict";t.r(r);var a=t(2676);t(5271);var s=t(2229),n=t.n(s),l=t(5550);r.default=()=>(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n(),{children:(0,a.jsx)("title",{children:"Databend"})}),(0,a.jsx)(l.Z,{})]})},5550:function(e,r,t){"use strict";var a=t(2676),s=t(5271),n=t(6058),l=t(9675),o=t(2327),i=t(987),d=t(9619),c=t(9822),u=t(5122);r.Z=()=>{let e=(0,n.useRouter)(),r=e.query.slug&&Array.isArray(e.query.slug)?e.query.slug.join("/"):e.query.slug,t=e.query.queryId,h=r||t,[m,g]=(0,s.useState)(""),[p,x]=(0,s.useState)([]),[y,f]=(0,s.useState)(!1),[b,N]=(0,s.useState)("");(0,s.useEffect)(()=>{e.isReady&&h&&"string"==typeof h?j(h):g("CREATE OR REPLACE TABLE students (uid Int16, name String, age Int16);\n\nINSERT INTO students VALUES (1231, 'John', 33);\nINSERT INTO students VALUES (6666, 'Ksenia', 48);\nINSERT INTO students VALUES (8888, 'Alice', 50);\n\nSELECT * FROM students;")},[e.isReady,h]);let j=async e=>{try{f(!0),N("");let r=await fetch("/api/query/".concat(e));if(r.ok){let e=await r.json();g(e.sql),x(e.results||[])}else N('Run ID "'.concat(e,'" not found')),x([])}catch(r){console.error("Failed to load shared query:",r),N('Failed to load run ID "'.concat(e,'"')),x([])}finally{f(!1)}},w=(0,s.useCallback)(async()=>{if(!m.trim()){N("Please enter a SQL query"),x([]);return}f(!0),N("");try{let r=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:m,kind:0})});if(!r.ok){let e="HTTP error! status: ".concat(r.status);try{let t=await r.json();t.error&&(e=t.error)}catch(e){}throw Error(e)}let t=await r.json();x(t.results||[]),t.queryId&&e.push("/".concat(t.queryId),void 0,{shallow:!0})}catch(e){console.error("Query execution failed:",e),N("Query execution failed: "+e.message.replace(/\\n/g,"\n")),x([])}finally{f(!1)}},[m,e]);(0,s.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&"Enter"===e.key&&(e.preventDefault(),w())};return window.addEventListener("keydown",e),()=>{window.removeEventListener("keydown",e)}},[w]);let v=(e,r)=>e.data&&Array.isArray(e.data)&&0!==e.data.length?(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsxs)("table",{className:"w-full border-collapse",children:[(0,a.jsx)("thead",{children:(0,a.jsx)("tr",{className:"bg-gray-100",children:e.columns.map((r,t)=>(0,a.jsxs)("th",{className:"border border-gray-300 px-4 py-3 text-left font-semibold text-gray-900 bg-gray-50",children:[r,e.types&&e.types[t]&&(0,a.jsx)("div",{className:"text-xs font-normal text-left text-gray-500 mt-1",children:e.types[t]})]},t))})}),(0,a.jsx)("tbody",{children:e.data.map((e,r)=>(0,a.jsx)("tr",{className:r%2==0?"bg-white":"bg-gray-50",children:e.map((e,r)=>(0,a.jsx)("td",{className:"border border-gray-300 px-4 py-2 text-gray-900 font-mono text-sm",children:e||""},r))},r))})]})})]},r):(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"p-4 text-center text-gray-500",children:"No data returned"})]},r);return(0,a.jsxs)("div",{className:"h-full bg-gray-100",children:[(0,a.jsx)("div",{className:"bg-yellow-400 px-4 py-2 flex items-center justify-between",children:(0,a.jsxs)("div",{className:"flex items-center gap-4",children:[(0,a.jsx)("span",{className:"font-bold",children:"SQL Query"}),(0,a.jsx)("button",{onClick:w,disabled:y,className:"bg-indigo-600 hover:bg-indigo-700 disabled:opacity-60 disabled:cursor-not-allowed text-white px-4 py-1.5 rounded-md flex items-center gap-2 text-sm",children:y?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}),"RUNNING..."]}):(0,a.jsx)(a.Fragment,{children:"โ–ถ RUN QUERY"})})]})}),(0,a.jsx)("div",{className:"h-[calc(100vh-48px)] border border-gray-300",children:(0,a.jsxs)(c.eh,{direction:"horizontal",className:"h-full",children:[(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full",children:(0,a.jsx)("div",{className:"h-full border-r border-gray-300 relative",children:(0,a.jsx)(l.ZP,{value:m,placeholder:"Enter your SQL queries here... (Press Cmd+Enter to run)",theme:u.tR,height:"100%",extensions:[u.MH,i.tk.lineWrapping,(0,d.ys)({icons:!1}),(0,o.i6)()],basicSetup:{lineNumbers:!0,foldGutter:!1,indentOnInput:!1,autocompletion:!0,highlightActiveLine:!1},onChange:e=>g(e),editable:!y,style:{height:"100%",fontSize:"14px"}})})}),(0,a.jsx)(c.OT,{className:"w-1 bg-gray-300 hover:bg-gray-400 cursor-col-resize"}),(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full",children:(0,a.jsx)("div",{className:"h-full overflow-auto bg-white relative",children:(0,a.jsx)("div",{className:"p-2 h-full",children:b?(0,a.jsx)("div",{className:"flex items-center justify-center h-full",children:(0,a.jsxs)("div",{className:"bg-red-50 border border-red-300 rounded-lg p-4 text-red-700 max-w-full",children:[(0,a.jsx)("div",{className:"font-medium text-red-800 mb-1",children:"Error"}),(0,a.jsx)("pre",{className:"text-sm whitespace-pre-wrap break-words font-mono",children:b})]})}):p.length>0?(0,a.jsx)("div",{className:"space-y-4",children:p.map((e,r)=>v(e,r))}):(0,a.jsx)("div",{className:"flex items-center justify-center h-full text-gray-500",children:"Execute a query to see results"})})})})]})})]})}},5122:function(e,r,t){"use strict";t.d(r,{MH:function(){return i},tR:function(){return o}});var a=t(1861),s=t(3233),n=t(987);let l={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},o=function(e){let{theme:r="light",settings:t={},styles:n=[]}={};return(0,s.j)({theme:r,settings:{...l,...t},styles:[{tag:[a.pJ.comment,a.pJ.quote],color:"#707F8D"},{tag:[a.pJ.typeName,a.pJ.typeOperator],color:"#aa0d91"},{tag:[a.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[a.pJ.string,a.pJ.meta],color:"#D23423"},{tag:[a.pJ.name],color:"#032f62"},{tag:[a.pJ.typeName],color:"#522BB2"},{tag:[a.pJ.variableName],color:"#23575C"},{tag:[a.pJ.definition(a.pJ.variableName)],color:"#327A9E"},{tag:[a.pJ.regexp,a.pJ.link],color:"#0e0eff"},...n]})}(),i=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}},function(e){e.O(0,[430,736,888,774,179],function(){return e(e.s=923)}),_N_E=e.O()}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[330],{923:function(e,r,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/[...slug]",function(){return t(2093)}])},2093:function(e,r,t){"use strict";t.r(r);var a=t(2676);t(5271);var s=t(2229),n=t.n(s),o=t(5550);r.default=()=>(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n(),{children:(0,a.jsx)("title",{children:"Databend"})}),(0,a.jsx)(o.Z,{})]})},5550:function(e,r,t){"use strict";var a=t(2676),s=t(5271),n=t(6058),o=t(9675),l=t(2327),i=t(987),d=t(9619),c=t(9822),u=t(5122);r.Z=()=>{let e=(0,n.useRouter)(),r=e.query.slug&&Array.isArray(e.query.slug)?e.query.slug.join("/"):e.query.slug,t=e.query.queryId,h=r||t,[m,g]=(0,s.useState)(""),[x,f]=(0,s.useState)([]),[p,y]=(0,s.useState)(!1),[b,j]=(0,s.useState)("");(0,s.useEffect)(()=>{e.isReady&&h&&"string"==typeof h?N(h):g("CREATE OR REPLACE TABLE students (uid Int16, name String, age Int16);\n\nINSERT INTO students VALUES (1231, 'John', 33);\nINSERT INTO students VALUES (6666, 'Ksenia', 48);\nINSERT INTO students VALUES (8888, 'Alice', 50);\n\nSELECT * FROM students;")},[e.isReady,h]);let N=async e=>{try{y(!0),j("");let r=await fetch("/api/query/".concat(e));if(r.ok){let e=await r.json();g(e.sql),f(e.results||[])}else j('Run ID "'.concat(e,'" not found')),f([])}catch(r){console.error("Failed to load shared query:",r),j('Failed to load run ID "'.concat(e,'"')),f([])}finally{y(!1)}},w=(0,s.useCallback)(async()=>{if(!m.trim()){j("Please enter a SQL query"),f([]);return}y(!0),j("");try{let r=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:m,kind:0})});if(!r.ok){let e="HTTP error! status: ".concat(r.status);try{let t=await r.json();t.error&&(e=t.error)}catch(e){}throw Error(e)}let t=await r.json();f(t.results||[]),t.queryId&&e.push("/".concat(t.queryId),void 0,{shallow:!0})}catch(e){console.error("Query execution failed:",e),j("Query execution failed: "+e.message.replace(/\\n/g,"\n")),f([])}finally{y(!1)}},[m,e]),v=(0,s.useMemo)(()=>i.$f.of([{key:"Mod-Enter",run:()=>(w(),!0),preventDefault:!0},{key:"Ctrl-Enter",run:()=>(w(),!0),preventDefault:!0}]),[w]),E=(e,r)=>e.data&&Array.isArray(e.data)&&0!==e.data.length?(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsxs)("table",{className:"w-full border-collapse",children:[(0,a.jsx)("thead",{children:(0,a.jsx)("tr",{className:"bg-gray-100",children:e.columns.map((r,t)=>(0,a.jsxs)("th",{className:"border border-gray-300 px-4 py-3 text-left font-semibold text-gray-900 bg-gray-50",children:[r,e.types&&e.types[t]&&(0,a.jsx)("div",{className:"text-xs font-normal text-left text-gray-500 mt-1",children:e.types[t]})]},t))})}),(0,a.jsx)("tbody",{children:e.data.map((e,r)=>(0,a.jsx)("tr",{className:r%2==0?"bg-white":"bg-gray-50",children:e.map((e,r)=>(0,a.jsx)("td",{className:"border border-gray-300 px-4 py-2 text-gray-900 font-mono text-sm",children:e||""},r))},r))})]})})]},r):(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"p-4 text-center text-gray-500",children:"No data returned"})]},r);return(0,a.jsxs)("div",{className:"flex flex-1 min-h-0 flex-col bg-[#f9fbff]",children:[(0,a.jsxs)("div",{className:"border-b border-gray-200 bg-white px-4 py-3 flex items-center gap-3 text-sm text-gray-600",children:[(0,a.jsx)("button",{onClick:w,disabled:p,className:"inline-flex items-center gap-2 rounded-full border px-4 py-1.5 text-sm font-semibold ".concat(p?"cursor-not-allowed border-gray-200 text-gray-400":"border-indigo-200 text-indigo-600 hover:bg-indigo-50"),children:p?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:"w-3.5 h-3.5 border-2 border-indigo-400 border-t-transparent rounded-full animate-spin"}),"Running..."]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:"text-base",children:"โ–ถ"}),"Run query"]})}),(0,a.jsx)("span",{className:"hidden sm:block",children:"Press โŒ˜โŽ to run"})]}),(0,a.jsx)("div",{className:"flex-1 min-h-0 border border-gray-200 bg-white",children:(0,a.jsxs)(c.eh,{direction:"horizontal",className:"h-full min-h-0",style:{height:"100%"},children:[(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full min-h-0",children:(0,a.jsx)("div",{className:"h-full min-h-0 border-r border-gray-300 relative",children:(0,a.jsx)(o.ZP,{value:m,placeholder:"Enter your SQL queries here... (Press Cmd+Enter to run)",theme:u.tR,height:"100%",extensions:[u.MH,i.tk.lineWrapping,(0,i.Eu)(),(0,d.ys)({icons:!1}),(0,l.i6)(),v],basicSetup:!1,onChange:e=>g(e),editable:!p,style:{height:"100%",fontSize:"14px"}})})}),(0,a.jsx)(c.OT,{className:"w-1 bg-gray-300 hover:bg-gray-400 cursor-col-resize"}),(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full min-h-0",children:(0,a.jsx)("div",{className:"h-full min-h-0 overflow-auto bg-white relative",children:(0,a.jsx)("div",{className:"p-2 h-full min-h-0",children:b?(0,a.jsx)("div",{className:"flex items-center justify-center h-full",children:(0,a.jsxs)("div",{className:"bg-red-50 border border-red-300 rounded-lg p-4 text-red-700 max-w-full",children:[(0,a.jsx)("div",{className:"font-medium text-red-800 mb-1",children:"Error"}),(0,a.jsx)("pre",{className:"text-sm whitespace-pre-wrap break-words font-mono",children:b})]})}):x.length>0?(0,a.jsx)("div",{className:"space-y-4",children:x.map((e,r)=>E(e,r))}):(0,a.jsx)("div",{className:"flex items-center justify-center h-full text-gray-500",children:"Execute a query to see results"})})})})]})})]})}},5122:function(e,r,t){"use strict";t.d(r,{MH:function(){return i},tR:function(){return l}});var a=t(1861),s=t(3233),n=t(987);let o={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},l=function(e){let{theme:r="light",settings:t={},styles:n=[]}={};return(0,s.j)({theme:r,settings:{...o,...t},styles:[{tag:[a.pJ.comment,a.pJ.quote],color:"#707F8D"},{tag:[a.pJ.typeName,a.pJ.typeOperator],color:"#aa0d91"},{tag:[a.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[a.pJ.string,a.pJ.meta],color:"#D23423"},{tag:[a.pJ.name],color:"#032f62"},{tag:[a.pJ.typeName],color:"#522BB2"},{tag:[a.pJ.variableName],color:"#23575C"},{tag:[a.pJ.definition(a.pJ.variableName)],color:"#327A9E"},{tag:[a.pJ.regexp,a.pJ.link],color:"#0e0eff"},...n]})}(),i=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}},function(e){e.O(0,[430,736,888,774,179],function(){return e(e.s=923)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/cli/frontend/build/_next/static/js/pages/_app.js b/cli/frontend/build/_next/static/js/pages/_app.js index 88af3113..424789b4 100644 --- a/cli/frontend/build/_next/static/js/pages/_app.js +++ b/cli/frontend/build/_next/static/js/pages/_app.js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[888],{6442:function(e,n,r){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_app",function(){return r(6322)}])},6322:function(e,n,r){"use strict";r.r(n),r.d(n,{default:function(){return o}});var t=r(2676),a=r(5271),s=r(6058),l=r(7292),i=r.n(l),c=e=>{let{children:n}=e,r=(0,s.useRouter)(),[l,c]=(0,a.useState)(!1),o=e=>"/"===e?"/"===r.pathname:r.pathname.startsWith(e);return(0,t.jsxs)("div",{className:"flex h-screen bg-gray-200",children:[(0,t.jsxs)("div",{className:"bg-white border-r border-gray-200 transition-all duration-300 ".concat(l?"w-16":"w-32"),children:[(0,t.jsx)("div",{className:"p-4 border-b",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[!l&&(0,t.jsx)("h1",{className:"text-lg font-bold text-gray-800",children:"BendSQL"}),(0,t.jsx)("button",{onClick:()=>c(!l),className:"p-1 rounded hover:bg-gray-100 transition-colors",title:l?"Expand sidebar":"Collapse sidebar",children:l?"โ†’":"โ†"})]})}),(0,t.jsx)("nav",{className:"p-2",children:[{name:"Query",path:"/",icon:"\uD83D\uDCCA"},{name:"Perf",path:"/perf/0",icon:"โšก"}].map(e=>(0,t.jsxs)(i(),{href:e.path,className:"flex items-center p-3 rounded-lg mb-1 transition-colors ".concat(o(e.path)?"bg-blue-50 text-blue-600 border border-blue-200":"text-gray-600 hover:bg-gray-50"),children:[(0,t.jsx)("span",{className:"text-lg",children:e.icon}),!l&&(0,t.jsx)("span",{className:"ml-3 font-medium",children:e.name})]},e.path))})]}),(0,t.jsx)("div",{className:"flex-1 flex flex-col overflow-hidden",children:n})]})};r(6710),r(2260);var o=function(e){let{Component:n,pageProps:r}=e;return(0,t.jsx)(c,{children:(0,t.jsx)(n,{...r})})}},2260:function(){},6710:function(){}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[736,774,179],function(){return n(6442),n(3841)}),_N_E=e.O()}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[888],{6442:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_app",function(){return t(6322)}])},6322:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var s=t(2676);t(5271);var l=t(6058),a=t(7292),r=t.n(a),i=e=>{let{children:n}=e,t=(0,l.useRouter)(),a=e=>{let n=t.asPath.split("?")[0]||"/";return"/"===e?"/"===n:n.startsWith(e)};return(0,s.jsxs)("div",{className:"flex h-screen min-h-screen flex-col bg-[#ffe895]",children:[(0,s.jsx)("header",{className:"border-b border-yellow-300 bg-yellow-400",children:(0,s.jsx)("div",{className:"flex w-full items-center justify-between gap-4 px-6 py-3",children:(0,s.jsxs)("div",{className:"flex items-center gap-4",children:[(0,s.jsx)("span",{className:"text-lg font-bold text-gray-900",children:"BendSQL"}),(0,s.jsx)("nav",{className:"flex items-center gap-2",children:[{name:"Query",path:"/",icon:"\uD83D\uDCCA"},{name:"Notebooks",path:"/notebooks",icon:"\uD83D\uDCD3"},{name:"Perf",path:"/perf/0",icon:"โšก"}].map(e=>(0,s.jsxs)(r(),{href:e.path,className:"inline-flex items-center gap-2 rounded-full px-4 py-1.5 text-sm font-semibold transition ".concat(a(e.path)?"bg-white text-gray-900 shadow":"text-gray-900/70 hover:text-gray-900"),children:[(0,s.jsx)("span",{children:e.icon}),(0,s.jsx)("span",{children:e.name})]},e.path))})]})})}),(0,s.jsx)("main",{className:"flex-1 overflow-hidden bg-[#f9fbff] flex flex-col min-h-0 h-full",children:(0,s.jsx)("div",{className:"flex-1 min-h-0 flex flex-col h-full",children:n})})]})};t(6710),t(2260);var c=function(e){let{Component:n,pageProps:t}=e;return(0,s.jsx)(i,{children:(0,s.jsx)(n,{...t})})}},2260:function(){},6710:function(){}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[736,774,179],function(){return n(6442),n(3841)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/cli/frontend/build/_next/static/js/pages/index.js b/cli/frontend/build/_next/static/js/pages/index.js index 67680d49..5baa46a0 100644 --- a/cli/frontend/build/_next/static/js/pages/index.js +++ b/cli/frontend/build/_next/static/js/pages/index.js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[405],{9331:function(e,r,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return t(6315)}])},6315:function(e,r,t){"use strict";t.r(r);var a=t(2676);t(5271);var s=t(2229),n=t.n(s),l=t(5550);r.default=()=>(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n(),{children:(0,a.jsx)("title",{children:"Databend"})}),(0,a.jsx)(l.Z,{})]})},5550:function(e,r,t){"use strict";var a=t(2676),s=t(5271),n=t(6058),l=t(9675),o=t(2327),i=t(987),d=t(9619),c=t(9822),u=t(5122);r.Z=()=>{let e=(0,n.useRouter)(),r=e.query.slug&&Array.isArray(e.query.slug)?e.query.slug.join("/"):e.query.slug,t=e.query.queryId,h=r||t,[m,g]=(0,s.useState)(""),[p,x]=(0,s.useState)([]),[y,f]=(0,s.useState)(!1),[b,N]=(0,s.useState)("");(0,s.useEffect)(()=>{e.isReady&&h&&"string"==typeof h?j(h):g("CREATE OR REPLACE TABLE students (uid Int16, name String, age Int16);\n\nINSERT INTO students VALUES (1231, 'John', 33);\nINSERT INTO students VALUES (6666, 'Ksenia', 48);\nINSERT INTO students VALUES (8888, 'Alice', 50);\n\nSELECT * FROM students;")},[e.isReady,h]);let j=async e=>{try{f(!0),N("");let r=await fetch("/api/query/".concat(e));if(r.ok){let e=await r.json();g(e.sql),x(e.results||[])}else N('Run ID "'.concat(e,'" not found')),x([])}catch(r){console.error("Failed to load shared query:",r),N('Failed to load run ID "'.concat(e,'"')),x([])}finally{f(!1)}},w=(0,s.useCallback)(async()=>{if(!m.trim()){N("Please enter a SQL query"),x([]);return}f(!0),N("");try{let r=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:m,kind:0})});if(!r.ok){let e="HTTP error! status: ".concat(r.status);try{let t=await r.json();t.error&&(e=t.error)}catch(e){}throw Error(e)}let t=await r.json();x(t.results||[]),t.queryId&&e.push("/".concat(t.queryId),void 0,{shallow:!0})}catch(e){console.error("Query execution failed:",e),N("Query execution failed: "+e.message.replace(/\\n/g,"\n")),x([])}finally{f(!1)}},[m,e]);(0,s.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&"Enter"===e.key&&(e.preventDefault(),w())};return window.addEventListener("keydown",e),()=>{window.removeEventListener("keydown",e)}},[w]);let v=(e,r)=>e.data&&Array.isArray(e.data)&&0!==e.data.length?(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsxs)("table",{className:"w-full border-collapse",children:[(0,a.jsx)("thead",{children:(0,a.jsx)("tr",{className:"bg-gray-100",children:e.columns.map((r,t)=>(0,a.jsxs)("th",{className:"border border-gray-300 px-4 py-3 text-left font-semibold text-gray-900 bg-gray-50",children:[r,e.types&&e.types[t]&&(0,a.jsx)("div",{className:"text-xs font-normal text-left text-gray-500 mt-1",children:e.types[t]})]},t))})}),(0,a.jsx)("tbody",{children:e.data.map((e,r)=>(0,a.jsx)("tr",{className:r%2==0?"bg-white":"bg-gray-50",children:e.map((e,r)=>(0,a.jsx)("td",{className:"border border-gray-300 px-4 py-2 text-gray-900 font-mono text-sm",children:e||""},r))},r))})]})})]},r):(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"p-4 text-center text-gray-500",children:"No data returned"})]},r);return(0,a.jsxs)("div",{className:"h-full bg-gray-100",children:[(0,a.jsx)("div",{className:"bg-yellow-400 px-4 py-2 flex items-center justify-between",children:(0,a.jsxs)("div",{className:"flex items-center gap-4",children:[(0,a.jsx)("span",{className:"font-bold",children:"SQL Query"}),(0,a.jsx)("button",{onClick:w,disabled:y,className:"bg-indigo-600 hover:bg-indigo-700 disabled:opacity-60 disabled:cursor-not-allowed text-white px-4 py-1.5 rounded-md flex items-center gap-2 text-sm",children:y?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}),"RUNNING..."]}):(0,a.jsx)(a.Fragment,{children:"โ–ถ RUN QUERY"})})]})}),(0,a.jsx)("div",{className:"h-[calc(100vh-48px)] border border-gray-300",children:(0,a.jsxs)(c.eh,{direction:"horizontal",className:"h-full",children:[(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full",children:(0,a.jsx)("div",{className:"h-full border-r border-gray-300 relative",children:(0,a.jsx)(l.ZP,{value:m,placeholder:"Enter your SQL queries here... (Press Cmd+Enter to run)",theme:u.tR,height:"100%",extensions:[u.MH,i.tk.lineWrapping,(0,d.ys)({icons:!1}),(0,o.i6)()],basicSetup:{lineNumbers:!0,foldGutter:!1,indentOnInput:!1,autocompletion:!0,highlightActiveLine:!1},onChange:e=>g(e),editable:!y,style:{height:"100%",fontSize:"14px"}})})}),(0,a.jsx)(c.OT,{className:"w-1 bg-gray-300 hover:bg-gray-400 cursor-col-resize"}),(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full",children:(0,a.jsx)("div",{className:"h-full overflow-auto bg-white relative",children:(0,a.jsx)("div",{className:"p-2 h-full",children:b?(0,a.jsx)("div",{className:"flex items-center justify-center h-full",children:(0,a.jsxs)("div",{className:"bg-red-50 border border-red-300 rounded-lg p-4 text-red-700 max-w-full",children:[(0,a.jsx)("div",{className:"font-medium text-red-800 mb-1",children:"Error"}),(0,a.jsx)("pre",{className:"text-sm whitespace-pre-wrap break-words font-mono",children:b})]})}):p.length>0?(0,a.jsx)("div",{className:"space-y-4",children:p.map((e,r)=>v(e,r))}):(0,a.jsx)("div",{className:"flex items-center justify-center h-full text-gray-500",children:"Execute a query to see results"})})})})]})})]})}},5122:function(e,r,t){"use strict";t.d(r,{MH:function(){return i},tR:function(){return o}});var a=t(1861),s=t(3233),n=t(987);let l={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},o=function(e){let{theme:r="light",settings:t={},styles:n=[]}={};return(0,s.j)({theme:r,settings:{...l,...t},styles:[{tag:[a.pJ.comment,a.pJ.quote],color:"#707F8D"},{tag:[a.pJ.typeName,a.pJ.typeOperator],color:"#aa0d91"},{tag:[a.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[a.pJ.string,a.pJ.meta],color:"#D23423"},{tag:[a.pJ.name],color:"#032f62"},{tag:[a.pJ.typeName],color:"#522BB2"},{tag:[a.pJ.variableName],color:"#23575C"},{tag:[a.pJ.definition(a.pJ.variableName)],color:"#327A9E"},{tag:[a.pJ.regexp,a.pJ.link],color:"#0e0eff"},...n]})}(),i=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}},function(e){e.O(0,[430,736,888,774,179],function(){return e(e.s=9331)}),_N_E=e.O()}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[405],{9331:function(e,r,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return t(6315)}])},6315:function(e,r,t){"use strict";t.r(r);var a=t(2676);t(5271);var s=t(2229),n=t.n(s),o=t(5550);r.default=()=>(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n(),{children:(0,a.jsx)("title",{children:"Databend"})}),(0,a.jsx)(o.Z,{})]})},5550:function(e,r,t){"use strict";var a=t(2676),s=t(5271),n=t(6058),o=t(9675),l=t(2327),i=t(987),d=t(9619),c=t(9822),u=t(5122);r.Z=()=>{let e=(0,n.useRouter)(),r=e.query.slug&&Array.isArray(e.query.slug)?e.query.slug.join("/"):e.query.slug,t=e.query.queryId,h=r||t,[m,g]=(0,s.useState)(""),[x,f]=(0,s.useState)([]),[p,y]=(0,s.useState)(!1),[b,j]=(0,s.useState)("");(0,s.useEffect)(()=>{e.isReady&&h&&"string"==typeof h?N(h):g("CREATE OR REPLACE TABLE students (uid Int16, name String, age Int16);\n\nINSERT INTO students VALUES (1231, 'John', 33);\nINSERT INTO students VALUES (6666, 'Ksenia', 48);\nINSERT INTO students VALUES (8888, 'Alice', 50);\n\nSELECT * FROM students;")},[e.isReady,h]);let N=async e=>{try{y(!0),j("");let r=await fetch("/api/query/".concat(e));if(r.ok){let e=await r.json();g(e.sql),f(e.results||[])}else j('Run ID "'.concat(e,'" not found')),f([])}catch(r){console.error("Failed to load shared query:",r),j('Failed to load run ID "'.concat(e,'"')),f([])}finally{y(!1)}},w=(0,s.useCallback)(async()=>{if(!m.trim()){j("Please enter a SQL query"),f([]);return}y(!0),j("");try{let r=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sql:m,kind:0})});if(!r.ok){let e="HTTP error! status: ".concat(r.status);try{let t=await r.json();t.error&&(e=t.error)}catch(e){}throw Error(e)}let t=await r.json();f(t.results||[]),t.queryId&&e.push("/".concat(t.queryId),void 0,{shallow:!0})}catch(e){console.error("Query execution failed:",e),j("Query execution failed: "+e.message.replace(/\\n/g,"\n")),f([])}finally{y(!1)}},[m,e]),v=(0,s.useMemo)(()=>i.$f.of([{key:"Mod-Enter",run:()=>(w(),!0),preventDefault:!0},{key:"Ctrl-Enter",run:()=>(w(),!0),preventDefault:!0}]),[w]),E=(e,r)=>e.data&&Array.isArray(e.data)&&0!==e.data.length?(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsxs)("table",{className:"w-full border-collapse",children:[(0,a.jsx)("thead",{children:(0,a.jsx)("tr",{className:"bg-gray-100",children:e.columns.map((r,t)=>(0,a.jsxs)("th",{className:"border border-gray-300 px-4 py-3 text-left font-semibold text-gray-900 bg-gray-50",children:[r,e.types&&e.types[t]&&(0,a.jsx)("div",{className:"text-xs font-normal text-left text-gray-500 mt-1",children:e.types[t]})]},t))})}),(0,a.jsx)("tbody",{children:e.data.map((e,r)=>(0,a.jsx)("tr",{className:r%2==0?"bg-white":"bg-gray-50",children:e.map((e,r)=>(0,a.jsx)("td",{className:"border border-gray-300 px-4 py-2 text-gray-900 font-mono text-sm",children:e||""},r))},r))})]})})]},r):(0,a.jsxs)("div",{className:"bg-white border border-gray-300 rounded-lg mb-4 overflow-hidden shadow-sm",children:[(0,a.jsxs)("div",{className:"bg-gray-50 border-b border-gray-300 px-4 py-3 font-medium text-gray-700",children:["Query ",r+1," (",e.rowCount," rows, ",e.duration,")"]}),(0,a.jsx)("div",{className:"p-4 text-center text-gray-500",children:"No data returned"})]},r);return(0,a.jsxs)("div",{className:"flex flex-1 min-h-0 flex-col bg-[#f9fbff]",children:[(0,a.jsxs)("div",{className:"border-b border-gray-200 bg-white px-4 py-3 flex items-center gap-3 text-sm text-gray-600",children:[(0,a.jsx)("button",{onClick:w,disabled:p,className:"inline-flex items-center gap-2 rounded-full border px-4 py-1.5 text-sm font-semibold ".concat(p?"cursor-not-allowed border-gray-200 text-gray-400":"border-indigo-200 text-indigo-600 hover:bg-indigo-50"),children:p?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:"w-3.5 h-3.5 border-2 border-indigo-400 border-t-transparent rounded-full animate-spin"}),"Running..."]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:"text-base",children:"โ–ถ"}),"Run query"]})}),(0,a.jsx)("span",{className:"hidden sm:block",children:"Press โŒ˜โŽ to run"})]}),(0,a.jsx)("div",{className:"flex-1 min-h-0 border border-gray-200 bg-white",children:(0,a.jsxs)(c.eh,{direction:"horizontal",className:"h-full min-h-0",style:{height:"100%"},children:[(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full min-h-0",children:(0,a.jsx)("div",{className:"h-full min-h-0 border-r border-gray-300 relative",children:(0,a.jsx)(o.ZP,{value:m,placeholder:"Enter your SQL queries here... (Press Cmd+Enter to run)",theme:u.tR,height:"100%",extensions:[u.MH,i.tk.lineWrapping,(0,i.Eu)(),(0,d.ys)({icons:!1}),(0,l.i6)(),v],basicSetup:!1,onChange:e=>g(e),editable:!p,style:{height:"100%",fontSize:"14px"}})})}),(0,a.jsx)(c.OT,{className:"w-1 bg-gray-300 hover:bg-gray-400 cursor-col-resize"}),(0,a.jsx)(c.s_,{defaultSize:50,minSize:20,className:"h-full min-h-0",children:(0,a.jsx)("div",{className:"h-full min-h-0 overflow-auto bg-white relative",children:(0,a.jsx)("div",{className:"p-2 h-full min-h-0",children:b?(0,a.jsx)("div",{className:"flex items-center justify-center h-full",children:(0,a.jsxs)("div",{className:"bg-red-50 border border-red-300 rounded-lg p-4 text-red-700 max-w-full",children:[(0,a.jsx)("div",{className:"font-medium text-red-800 mb-1",children:"Error"}),(0,a.jsx)("pre",{className:"text-sm whitespace-pre-wrap break-words font-mono",children:b})]})}):x.length>0?(0,a.jsx)("div",{className:"space-y-4",children:x.map((e,r)=>E(e,r))}):(0,a.jsx)("div",{className:"flex items-center justify-center h-full text-gray-500",children:"Execute a query to see results"})})})})]})})]})}},5122:function(e,r,t){"use strict";t.d(r,{MH:function(){return i},tR:function(){return l}});var a=t(1861),s=t(3233),n=t(987);let o={background:"#fff",foreground:"#3D3D3D",selection:"#BBDFFF",selectionMatch:"#BBDFFF",gutterBackground:"#fff",gutterForeground:"#AFAFAF",lineHighlight:"#EDF4FF"},l=function(e){let{theme:r="light",settings:t={},styles:n=[]}={};return(0,s.j)({theme:r,settings:{...o,...t},styles:[{tag:[a.pJ.comment,a.pJ.quote],color:"#707F8D"},{tag:[a.pJ.typeName,a.pJ.typeOperator],color:"#aa0d91"},{tag:[a.pJ.keyword],color:"#aa0d91",fontWeight:"bold"},{tag:[a.pJ.string,a.pJ.meta],color:"#D23423"},{tag:[a.pJ.name],color:"#032f62"},{tag:[a.pJ.typeName],color:"#522BB2"},{tag:[a.pJ.variableName],color:"#23575C"},{tag:[a.pJ.definition(a.pJ.variableName)],color:"#327A9E"},{tag:[a.pJ.regexp,a.pJ.link],color:"#0e0eff"},...n]})}(),i=n.tk.theme({"&":{fontSize:"12pt",border:"1px solid #556cd6","border-radius":"3px",padding:"3px"},"&.cm-editor.cm-focused":{outline:"none","border-width":"2px","border-color":"#fcd004"},".cm-tooltip-autocomplete":{border:"1px solid #556cd6","border-radius":"3px",margin:"3px",padding:"3px",background:"white",color:"black"},".cm-completionMatchedText":{"text-decoration":"none"},".cm-tooltip-autocomplete ul li[aria-selected]":{background:"white",color:"black","font-weight":"bold"}})}},function(e){e.O(0,[430,736,888,774,179],function(){return e(e.s=9331)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/cli/frontend/build/_next/static/js/pages/notebooks.js b/cli/frontend/build/_next/static/js/pages/notebooks.js new file mode 100644 index 00000000..acb422d1 --- /dev/null +++ b/cli/frontend/build/_next/static/js/pages/notebooks.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[514],{633:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/notebooks",function(){return t(902)}])},902:function(e,n,t){"use strict";t.r(n);var s=t(2676);t(5271);var o=t(2229),r=t.n(o),i=t(8097);let a=t.n(i)()(()=>Promise.all([t.e(430),t.e(736),t.e(77)]).then(t.bind(t,6077)),{loadableGenerated:{webpack:()=>[6077]},ssr:!1});n.default=()=>(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(r(),{children:(0,s.jsx)("title",{children:"Databend - Notebooks"})}),(0,s.jsx)(a,{})]})}},function(e){e.O(0,[736,888,774,179],function(){return e(e.s=633)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/cli/frontend/build/_next/static/stable-build-id/_buildManifest.js b/cli/frontend/build/_next/static/stable-build-id/_buildManifest.js index 0d7f5796..f78f7125 100644 --- a/cli/frontend/build/_next/static/stable-build-id/_buildManifest.js +++ b/cli/frontend/build/_next/static/stable-build-id/_buildManifest.js @@ -1 +1 @@ -self.__BUILD_MANIFEST=function(s){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,"static/js/pages/index.js"],"/_error":["static/js/pages/_error.js"],"/perf/[...slug]":["static/js/pages/perf/[...slug].js"],"/[...slug]":[s,"static/js/pages/[...slug].js"],sortedPages:["/","/_app","/_error","/perf/[...slug]","/[...slug]"]}}("static/js/0ba37d83.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file +self.__BUILD_MANIFEST=function(s){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,"static/js/pages/index.js"],"/_error":["static/js/pages/_error.js"],"/notebooks":["static/js/pages/notebooks.js"],"/perf/[...slug]":["static/js/pages/perf/[...slug].js"],"/[...slug]":[s,"static/js/pages/[...slug].js"],sortedPages:["/","/_app","/_error","/notebooks","/perf/[...slug]","/[...slug]"]}}("static/js/0ba37d83.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file diff --git a/cli/frontend/build/index.html b/cli/frontend/build/index.html index 91c53dcd..3523c4e2 100644 --- a/cli/frontend/build/index.html +++ b/cli/frontend/build/index.html @@ -1 +1 @@ -Databend
SQL Query
Execute a query to see results
\ No newline at end of file +Databend
Execute a query to see results
\ No newline at end of file diff --git a/cli/frontend/build/notebooks.html b/cli/frontend/build/notebooks.html new file mode 100644 index 00000000..0d5f82ea --- /dev/null +++ b/cli/frontend/build/notebooks.html @@ -0,0 +1 @@ +Databend - Notebooks
\ No newline at end of file diff --git a/cli/frontend/build/perf/[...slug].html b/cli/frontend/build/perf/[...slug].html index b3a7a41a..97237f3d 100644 --- a/cli/frontend/build/perf/[...slug].html +++ b/cli/frontend/build/perf/[...slug].html @@ -1 +1 @@ -Databend - Performance Analysis
\ No newline at end of file +Databend - Performance Analysis
\ No newline at end of file diff --git a/cli/src/web.rs b/cli/src/web.rs index f8b6e262..dfd38f2e 100644 --- a/cli/src/web.rs +++ b/cli/src/web.rs @@ -122,6 +122,9 @@ async fn embed_file(path: web::Path) -> HttpResponse { // Handle Next.js static export structure for /perf/ routes // trailingSlash: false generates perf/[...slug].html "perf/[...slug].html".to_string() + } else if requested_path == "notebooks" || requested_path.starts_with("notebooks/") { + // Static notebooks page + "notebooks.html".to_string() } else if requested_path .chars() .all(|c| c.is_alphanumeric() || c == '_' || c == '-') @@ -294,6 +297,7 @@ async fn execute_query(req: web::Json) -> impl Responder { let mut last_query_id = None; for statement in &statements { let start_time = std::time::Instant::now(); + let mut stats_running_time: Option = None; match conn.query_iter_ext(statement).await { Ok(mut rows) => { @@ -325,9 +329,8 @@ async fn execute_query(req: web::Json) -> impl Responder { data.push(row_values); row_count += 1; } - RowWithStats::Stats(_stats) => { - // Skip stats for now, we could use them for additional info - continue; + RowWithStats::Stats(stats) => { + stats_running_time = Some(stats.running_time_ms); } } } @@ -339,7 +342,15 @@ async fn execute_query(req: web::Json) -> impl Responder { } } - let duration = format!("{}ms", start_time.elapsed().as_millis()); + let duration = if let Some(ms) = stats_running_time { + if ms.fract() == 0.0 { + format!("{:.0}ms", ms) + } else { + format!("{:.2}ms", ms) + } + } else { + format!("{}ms", start_time.elapsed().as_millis()) + }; last_query_id = conn.last_query_id(); results.push(QueryResult { columns, diff --git a/frontend/pages/notebooks.tsx b/frontend/pages/notebooks.tsx new file mode 100644 index 00000000..761ebcb7 --- /dev/null +++ b/frontend/pages/notebooks.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import Head from 'next/head'; +import dynamic from 'next/dynamic'; + +const Notebooks = dynamic(() => import('../src/Notebooks'), { + ssr: false +}); + +const NotebooksPage: React.FC = () => { + return ( + <> + + Databend - Notebooks + + + + ); +}; + +export default NotebooksPage; \ No newline at end of file diff --git a/frontend/src/Layout.tsx b/frontend/src/Layout.tsx index b3937f65..0a2f503a 100644 --- a/frontend/src/Layout.tsx +++ b/frontend/src/Layout.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { useRouter } from 'next/router'; import Link from 'next/link'; @@ -8,69 +8,53 @@ interface LayoutProps { const Layout: React.FC = ({ children }) => { const router = useRouter(); - const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const navItems = [ { name: 'Query', path: '/', icon: '๐Ÿ“Š' }, + { name: 'Notebooks', path: '/notebooks', icon: '๐Ÿ““' }, { name: 'Perf', path: '/perf/0', icon: 'โšก' }, ]; const isActive = (path: string) => { + const currentPath = router.asPath.split('?')[0] || '/'; if (path === '/') { - return router.pathname === '/'; + return currentPath === '/'; } - return router.pathname.startsWith(path); + return currentPath.startsWith(path); }; return ( -
- {/* Sidebar */} -
-
-
- {!sidebarCollapsed && ( -

BendSQL

- )} - +
+
+
+
+ BendSQL +
- - -
- - {/* Main Content */} -
- {children} -
+ +
+
+ {children} +
+
); }; -export default Layout; \ No newline at end of file +export default Layout; diff --git a/frontend/src/Notebooks.tsx b/frontend/src/Notebooks.tsx new file mode 100644 index 00000000..c8537173 --- /dev/null +++ b/frontend/src/Notebooks.tsx @@ -0,0 +1,784 @@ +import React, { + useState, + useEffect, + useCallback, + useMemo, + useRef, +} from 'react'; +import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels'; +import NotebookCellComponent from './components/NotebookCell'; +import { EllipsisIcon } from './components/icons'; +import { Notebook, NotebookCell } from './types/notebook'; +import { notebookStorage } from './utills/notebookStorage'; +import { formatRelativeTime } from './utills/time'; + +const Notebooks: React.FC = () => { + const [notebooks, setNotebooks] = useState([]); + const [currentNotebook, setCurrentNotebook] = useState(null); + const [activeCellId, setActiveCellId] = useState(null); + const [notebookSearch, setNotebookSearch] = useState(''); + const [draggingCellId, setDraggingCellId] = useState(null); + const [dragOverState, setDragOverState] = useState<{ id: string | null; placeAfter: boolean }>({ + id: null, + placeAfter: false, + }); + const [fullscreenCellId, setFullscreenCellId] = useState(null); + const [notebookMenuOpen, setNotebookMenuOpen] = useState(false); + const [openNotebookMenuId, setOpenNotebookMenuId] = useState(null); + const notebookNameRef = useRef(null); + const notebookMenuRef = useRef(null); + const [notebookListCollapsed, setNotebookListCollapsed] = useState(false); + const currentNotebookRef = useRef(null); + + useEffect(() => { + currentNotebookRef.current = currentNotebook; + }, [currentNotebook]); + + // Load stored notebooks on mount + useEffect(() => { + const storage = notebookStorage.getNotebooks(); + setNotebooks(storage.notebooks); + + let initial = storage.notebooks[0]; + if (storage.currentNotebookId) { + const found = storage.notebooks.find(nb => nb.id === storage.currentNotebookId); + if (found) { + initial = found; + } + } + + if (initial) { + setCurrentNotebook(initial); + setActiveCellId(initial.cells[0]?.id ?? null); + } + }, []); + + // Persist notebooks whenever they change + useEffect(() => { + if (notebooks.length > 0) { + notebookStorage.saveNotebooks({ + notebooks, + currentNotebookId: currentNotebook?.id, + }); + } + }, [notebooks, currentNotebook]); + + // Ensure the active cell always exists inside the current notebook + useEffect(() => { + if (!currentNotebook) { + setActiveCellId(null); + return; + } + + const hasActive = currentNotebook.cells.some(cell => cell.id === activeCellId); + if (!hasActive) { + setActiveCellId(currentNotebook.cells[0]?.id ?? null); + } + }, [currentNotebook, activeCellId]); + + useEffect(() => { + if (!notebookMenuOpen) { + return; + } + const handleClick = (event: MouseEvent) => { + if (notebookMenuRef.current && !notebookMenuRef.current.contains(event.target as Node)) { + setNotebookMenuOpen(false); + } + }; + document.addEventListener('mousedown', handleClick); + return () => document.removeEventListener('mousedown', handleClick); + }, [notebookMenuOpen]); + + useEffect(() => { + if (!openNotebookMenuId) { + return; + } + const handleClick = (event: MouseEvent) => { + const target = event.target as HTMLElement; + if (!target.closest('[data-notebook-menu]')) { + setOpenNotebookMenuId(null); + } + }; + document.addEventListener('mousedown', handleClick); + return () => document.removeEventListener('mousedown', handleClick); + }, [openNotebookMenuId]); + + const filteredNotebooks = useMemo(() => { + if (!notebookSearch.trim()) { + return notebooks; + } + + const term = notebookSearch.toLowerCase(); + return notebooks.filter(nb => nb.name.toLowerCase().includes(term)); + }, [notebooks, notebookSearch]); + + const createNewNotebook = useCallback(() => { + const newNotebook = notebookStorage.createNotebook(); + setNotebooks(prev => [...prev, newNotebook]); + setCurrentNotebook(newNotebook); + setActiveCellId(newNotebook.cells[0]?.id ?? null); + }, []); + + const selectNotebook = useCallback((notebookId: string) => { + const notebook = notebooks.find(nb => nb.id === notebookId); + if (!notebook) { + return; + } + setCurrentNotebook(notebook); + setActiveCellId(notebook.cells[0]?.id ?? null); + }, [notebooks]); + + const updateNotebookName = useCallback((notebookId: string, name: string) => { + setNotebooks(prev => + prev.map(nb => + nb.id === notebookId + ? { ...nb, name, updatedAt: new Date() } + : nb + ) + ); + if (currentNotebook?.id === notebookId) { + setCurrentNotebook(prev => prev ? { ...prev, name, updatedAt: new Date() } : null); + } + }, [currentNotebook]); + + const addCellAt = useCallback((insertIndex: number) => { + if (!currentNotebook) { + return; + } + + const newCell = notebookStorage.createCell(); + const cells = [...currentNotebook.cells]; + const clampedIndex = Math.max(0, Math.min(insertIndex, cells.length)); + cells.splice(clampedIndex, 0, newCell); + + const updatedNotebook = { + ...currentNotebook, + cells, + updatedAt: new Date(), + }; + + setActiveCellId(newCell.id); + setCurrentNotebook(updatedNotebook); + setNotebooks(prev => prev.map(nb => nb.id === updatedNotebook.id ? updatedNotebook : nb)); + }, [currentNotebook]); + + const focusNotebookName = useCallback(() => { + notebookNameRef.current?.focus(); + }, []); + + const closeNotebook = useCallback(() => { + setCurrentNotebook(null); + setActiveCellId(null); + setFullscreenCellId(null); + }, []); + + const deleteAllCells = useCallback(() => { + if (!currentNotebook) { + return; + } + + const freshCell = notebookStorage.createCell(); + const updatedNotebook = { + ...currentNotebook, + cells: [freshCell], + updatedAt: new Date(), + }; + + setCurrentNotebook(updatedNotebook); + setNotebooks(prev => prev.map(nb => nb.id === updatedNotebook.id ? updatedNotebook : nb)); + setActiveCellId(freshCell.id); + setFullscreenCellId(null); + }, [currentNotebook]); + + const deleteNotebook = useCallback((notebookId: string) => { + setNotebooks(prev => { + const index = prev.findIndex(nb => nb.id === notebookId); + if (index === -1) { + return prev; + } + + const updated = prev.filter(nb => nb.id !== notebookId); + + if (currentNotebook?.id === notebookId) { + // ๅฆ‚ๆžœๅˆ ้™ค็š„ๆ˜ฏๅฝ“ๅ‰ notebook๏ผŒ้€‰ๆ‹ฉๆ–ฐ็š„ๅฝ“ๅ‰ notebook + const fallback = updated.length > 0 ? updated[0] : null; + setCurrentNotebook(fallback); + setActiveCellId(fallback?.cells[0]?.id ?? null); + setFullscreenCellId(null); + } + + return updated; + }); + + setOpenNotebookMenuId(null); + }, [currentNotebook]); + + const closeFullscreen = useCallback(() => { + setFullscreenCellId(null); + }, []); + + const updateCellSql = useCallback((cellId: string, sql: string) => { + if (!currentNotebook) { + return; + } + + const updatedNotebook = { + ...currentNotebook, + cells: currentNotebook.cells.map(cell => + cell.id === cellId ? { ...cell, sql } : cell + ), + updatedAt: new Date(), + }; + + setCurrentNotebook(updatedNotebook); + setNotebooks(prev => prev.map(nb => nb.id === updatedNotebook.id ? updatedNotebook : nb)); + }, [currentNotebook]); + + const toggleCellSection = useCallback((cellId: string, field: keyof Pick) => { + if (!currentNotebook) { + return; + } + + const updatedNotebook = { + ...currentNotebook, + cells: currentNotebook.cells.map(cell => + cell.id === cellId + ? { ...cell, [field]: !cell[field] } + : cell + ), + updatedAt: new Date(), + }; + + setCurrentNotebook(updatedNotebook); + setNotebooks(prev => prev.map(nb => nb.id === updatedNotebook.id ? updatedNotebook : nb)); + }, [currentNotebook]); + + const reorderCells = useCallback((sourceId: string, targetId: string, placeAfter = false) => { + if (!currentNotebook || sourceId === targetId) { + return false; + } + + const cells = [...currentNotebook.cells]; + const sourceIndex = cells.findIndex(cell => cell.id === sourceId); + const targetIndex = cells.findIndex(cell => cell.id === targetId); + if (sourceIndex === -1 || targetIndex === -1) { + return false; + } + + const [moved] = cells.splice(sourceIndex, 1); + const insertIndex = placeAfter ? targetIndex + 1 : targetIndex; + cells.splice(insertIndex, 0, moved); + + const updatedNotebook = { + ...currentNotebook, + cells, + updatedAt: new Date(), + }; + + setCurrentNotebook(updatedNotebook); + setNotebooks(prev => prev.map(nb => nb.id === updatedNotebook.id ? updatedNotebook : nb)); + setActiveCellId(moved.id); + return true; + }, [currentNotebook]); + + const moveCellPosition = useCallback((cellId: string, direction: 'up' | 'down') => { + if (!currentNotebook) { + return; + } + const cells = currentNotebook.cells; + const currentIndex = cells.findIndex(cell => cell.id === cellId); + if (currentIndex === -1) { + return; + } + const targetIndex = direction === 'up' ? currentIndex - 1 : currentIndex + 1; + if (targetIndex < 0 || targetIndex >= cells.length) { + return; + } + const targetId = cells[targetIndex].id; + reorderCells(cellId, targetId, direction === 'down'); + }, [currentNotebook, reorderCells]); + + const handleDragStart = useCallback((cellId: string) => { + setDraggingCellId(cellId); + setDragOverState({ id: null, placeAfter: false }); + }, []); + + const handleDragEnd = useCallback(() => { + setDraggingCellId(null); + setDragOverState({ id: null, placeAfter: false }); + }, []); + + const handleDragOverCell = useCallback((cellId: string, placeAfter = false) => { + if (!draggingCellId || draggingCellId === cellId) { + return; + } + if (reorderCells(draggingCellId, cellId, placeAfter)) { + setDragOverState({ id: cellId, placeAfter }); + } + }, [draggingCellId, reorderCells]); + + const handleDropOnCell = useCallback((cellId: string, placeAfter = false) => { + if (draggingCellId && draggingCellId !== cellId) { + reorderCells(draggingCellId, cellId, placeAfter); + } + setDraggingCellId(null); + setDragOverState({ id: null, placeAfter: false }); + }, [draggingCellId, reorderCells]); + + const executeCell = useCallback(async (cellId: string) => { + const notebook = currentNotebookRef.current; + if (!notebook) { + return { success: false as const }; + } + + const cell = notebook.cells.find(c => c.id === cellId); + if (!cell || !cell.sql.trim()) { + return { success: false as const }; + } + + setActiveCellId(cellId); + + const updatedNotebook = { + ...notebook, + cells: notebook.cells.map(c => + c.id === cellId ? { ...c, loading: true, error: undefined, result: undefined } : c + ), + }; + setCurrentNotebook(updatedNotebook); + currentNotebookRef.current = updatedNotebook; + + try { + const response = await fetch('/api/query', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ sql: cell.sql, kind: 0 }), + }); + + if (!response.ok) { + let errorMessage = `HTTP error! status: ${response.status}`; + try { + const errorData = await response.json(); + if (errorData.error) { + errorMessage = errorData.error; + } + } catch (e) { + // response was not JSON โ€“ ignore + } + throw new Error(errorMessage); + } + + const data = await response.json(); + const results = data.results || []; + const lastResult = results.length > 0 ? results[results.length - 1] : undefined; + + const finalNotebook = { + ...updatedNotebook, + cells: updatedNotebook.cells.map(c => + c.id === cellId + ? { + ...c, + loading: false, + result: lastResult, + error: undefined, + lastExecutedAt: new Date(), + } + : c + ), + updatedAt: new Date(), + }; + + setCurrentNotebook(finalNotebook); + currentNotebookRef.current = finalNotebook; + setNotebooks(prev => prev.map(nb => nb.id === finalNotebook.id ? finalNotebook : nb)); + + return { success: true as const }; + } catch (error) { + console.error('Cell execution failed:', error); + const errorMessage = (error as Error).message.replace(/\\n/g, '\n'); + + const finalNotebook = { + ...updatedNotebook, + cells: updatedNotebook.cells.map(c => + c.id === cellId + ? { + ...c, + loading: false, + error: 'Query execution failed: ' + errorMessage, + result: undefined, + } + : c + ), + updatedAt: new Date(), + }; + + setCurrentNotebook(finalNotebook); + currentNotebookRef.current = finalNotebook; + setNotebooks(prev => prev.map(nb => nb.id === finalNotebook.id ? finalNotebook : nb)); + + return { success: false as const, error: errorMessage }; + } + }, []); + + const runCellsFrom = useCallback(async (startIndex: number) => { + const notebook = currentNotebookRef.current; + if (!notebook) { + return; + } + const ids = notebook.cells.slice(startIndex).map(cell => cell.id); + for (const id of ids) { + const result = await executeCell(id); + if (!result?.success) { + break; + } + } + }, [executeCell]); + + const runCellsTo = useCallback(async (endIndex: number) => { + const notebook = currentNotebookRef.current; + if (!notebook) { + return; + } + const ids = notebook.cells.slice(0, Math.min(endIndex + 1, notebook.cells.length)).map(cell => cell.id); + for (const id of ids) { + const result = await executeCell(id); + if (!result?.success) { + break; + } + } + }, [executeCell]); + + useEffect(() => { + if (!fullscreenCellId) { + return; + } + const handleEscape = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + event.preventDefault(); + closeFullscreen(); + } + }; + window.addEventListener('keydown', handleEscape); + return () => window.removeEventListener('keydown', handleEscape); + }, [fullscreenCellId, closeFullscreen]); + + const deleteCell = useCallback((cellId: string) => { + if (!currentNotebook || currentNotebook.cells.length <= 1) { + return; + } + + const cellIndex = currentNotebook.cells.findIndex(cell => cell.id === cellId); + const fallbackCell = currentNotebook.cells[cellIndex + 1] || currentNotebook.cells[cellIndex - 1]; + + const updatedNotebook = { + ...currentNotebook, + cells: currentNotebook.cells.filter(cell => cell.id !== cellId), + updatedAt: new Date(), + }; + + setActiveCellId(prev => (prev === cellId ? fallbackCell?.id ?? null : prev)); + setCurrentNotebook(updatedNotebook); + setNotebooks(prev => prev.map(nb => nb.id === updatedNotebook.id ? updatedNotebook : nb)); + setFullscreenCellId(prev => (prev === cellId ? null : prev)); + }, [currentNotebook]); + + const renderAddControl = (label: 'above' | 'between' | 'below', insertIndex: number) => { + if (fullscreenCellId) { + return null; + } + const labelText = label === 'between' ? 'Add cell between' : label === 'above' ? 'Add cell above' : 'Add cell below'; + return ( + + ); + }; + + const renderSidebar = () => ( +
+
+ +
+ + + + + + + setNotebookSearch(e.target.value)} + placeholder="Find notebook" + className="w-full rounded-lg border border-gray-200 bg-gray-50 pl-8 pr-3 py-2 text-sm text-gray-700 focus:border-indigo-400 focus:bg-white focus:outline-none" + /> +
+
+ +
+
+ + +
+ + {!notebookListCollapsed && ( +
+ {filteredNotebooks.length === 0 && ( +
+ No notebooks found +
+ )} + {filteredNotebooks.map(nb => { + const isActive = currentNotebook?.id === nb.id; + const isMenuOpen = openNotebookMenuId === nb.id; + return ( +
+ + {isMenuOpen && ( +
+ +
+ )} +
+
+
+
+ {nb.cells.length} cell{nb.cells.length === 1 ? '' : 's'} +
+ +
+ ); + })} +
+ )} +
+
+ ); + + return ( +
+ + + {renderSidebar()} + + + + + +
+ {currentNotebook ? ( + <> +
+
+ updateNotebookName(currentNotebook.id, e.target.value)} + className="w-full border-none bg-transparent text-xl font-semibold text-gray-900 focus:outline-none" + placeholder="Notebook name" + /> +

+ Updated {formatRelativeTime(currentNotebook.updatedAt) || 'just now'} ยท {currentNotebook.cells.length} cell{currentNotebook.cells.length === 1 ? '' : 's'} +

+
+
+ โŒ˜โŽ to run cell +
+ + {notebookMenuOpen && ( +
+ + + +
+ )} +
+
+
+ +
+ {!fullscreenCellId && renderAddControl('above', 0)} + {currentNotebook.cells.map((cell, index) => { + if (fullscreenCellId && cell.id !== fullscreenCellId) { + return null; + } + return ( + + updateCellSql(cell.id, sql)} + onExecute={() => executeCell(cell.id)} + onDelete={() => deleteCell(cell.id)} + canDelete={currentNotebook.cells.length > 1} + isActive={cell.id === activeCellId || fullscreenCellId === cell.id} + onSelect={() => setActiveCellId(cell.id)} + onToggleCollapse={() => toggleCellSection(cell.id, 'collapsed')} + onToggleEditor={() => toggleCellSection(cell.id, 'hideEditor')} + onToggleResult={() => toggleCellSection(cell.id, 'hideResult')} + onToggleFullscreen={() => + setFullscreenCellId(prev => (prev === cell.id ? null : cell.id)) + } + isFullscreen={fullscreenCellId === cell.id} + onMoveUp={() => moveCellPosition(cell.id, 'up')} + onMoveDown={() => moveCellPosition(cell.id, 'down')} + dragState={{ + isDragging: draggingCellId === cell.id, + isDragOver: dragOverState.id === cell.id, + dragOverPosition: + dragOverState.id === cell.id + ? dragOverState.placeAfter + ? 'after' + : 'before' + : undefined, + }} + onDragStart={() => handleDragStart(cell.id)} + onDragEnd={handleDragEnd} + onDragOver={(placeAfter) => handleDragOverCell(cell.id, placeAfter)} + onDrop={(placeAfter) => handleDropOnCell(cell.id, placeAfter)} + onRunFromHere={() => { void runCellsFrom(index); }} + onRunToHere={() => { void runCellsTo(index); }} + /> + {!fullscreenCellId && renderAddControl( + index === currentNotebook.cells.length - 1 ? 'below' : 'between', + index + 1 + )} + + ); + })} + {!fullscreenCellId && renderAddControl('below', currentNotebook.cells.length)} +
+ + ) : ( +
+
+

No notebooks yet

+

+ Create your first notebook to start experimenting with queries. +

+ +
+
+ )} +
+
+
+ + {fullscreenCellId && ( +
+ +
+ )} +
+ ); +}; + +export default Notebooks; diff --git a/frontend/src/PerfQuery.tsx b/frontend/src/PerfQuery.tsx index 530c45c7..f6ff532f 100644 --- a/frontend/src/PerfQuery.tsx +++ b/frontend/src/PerfQuery.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { useRouter } from 'next/router'; import CodeMirror from '@uiw/react-codemirror'; import { sql } from '@codemirror/lang-sql'; -import { EditorView } from '@codemirror/view'; +import { EditorView, keymap, lineNumbers } from '@codemirror/view'; import { autocompletion } from '@codemirror/autocomplete'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { xcodeLight, xcodeLightPatch } from './components/CodeMirrorTheme'; @@ -30,14 +30,23 @@ interface QueryResponse { queryId?: string; } +const DEFAULT_PERF_SQL = `select number % 3 a, number % 4 b, number % 5 c from numbers(100000000) group by all limit 3;`; + const PerfQuery: React.FC = () => { + const isExecutionShortcut = (event: KeyboardEvent) => { + if (!(event.metaKey || event.ctrlKey)) { + return false; + } + return event.key === 'Enter' || event.key === 'NumpadEnter' || event.key === 'Return'; + }; + const router = useRouter(); // Get query ID from path parameters (for catch-all routes like [slug]) const pathQueryId = router.query.slug && Array.isArray(router.query.slug) ? router.query.slug.join('/') : router.query.slug; const queryId = pathQueryId; - const [query, setQuery] = useState(`SELECT number % 7 as a, number % 11 as b, number % 13 as c, count(distinct number) FROM numbers(100000000) group by a, b, c;`); + const [query, setQuery] = useState(DEFAULT_PERF_SQL); const [analysisType, setAnalysisType] = useState<'graph' | 'perf'>('graph'); const [perfData, setPerfData] = useState(''); @@ -113,14 +122,20 @@ const PerfQuery: React.FC = () => { setGraphData(null); } } else { - // Query not found, but still render the page + // Query not found, restore defaults so editor isn't empty setError(`Run ID "${queryId}" not found`); setPerfData(''); + setGraphData(null); + setQuery(DEFAULT_PERF_SQL); + setAnalysisType('graph'); } } catch (error) { console.error('Failed to load shared perf query:', error); setError(`Failed to load run ID "${queryId}"`); setPerfData(''); + setGraphData(null); + setQuery(DEFAULT_PERF_SQL); + setAnalysisType('graph'); } finally { setLoading(false); } @@ -172,29 +187,32 @@ const PerfQuery: React.FC = () => { // Load query from URL on component mount useEffect(() => { - if (router.isReady && queryId && typeof queryId === 'string') { + if (router.isReady && queryId && typeof queryId === 'string' && queryId !== '0') { loadSharedPerfQuery(queryId); } else { - setQuery(`SELECT * FROM system.tables LIMIT 10;`); + setQuery(DEFAULT_PERF_SQL); } }, [router.isReady, queryId, loadSharedPerfQuery]); // Add global keyboard event listener for Cmd+Enter - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { - e.preventDefault(); + const runKeymap = useMemo(() => keymap.of([ + { + key: 'Mod-Enter', + run: () => { executePerfQuery(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - - // Cleanup event listener on component unmount - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, [executePerfQuery]); + return true; + }, + preventDefault: true, + }, + { + key: 'Mod-NumpadEnter', + run: () => { + executePerfQuery(); + return true; + }, + preventDefault: true, + }, + ]), [executePerfQuery]); // Add resizeIframe function for HTML content useEffect(() => { @@ -227,7 +245,7 @@ const PerfQuery: React.FC = () => { if (analysisType === 'graph' && graphData) { return ( -
+
); @@ -235,7 +253,7 @@ const PerfQuery: React.FC = () => { // For perf mode, render the HTML content return (
); @@ -243,46 +261,50 @@ const PerfQuery: React.FC = () => { }; return ( -
- {/* Header */} -
-
- Performance Analysis -
- - -
+
+
+
Performance Analysis
+
+ +
- - {/* Content - Resizable Vertical Panels */} -
- +
+ {/* Top Panel - SQL Editor (small initial height) */} - -
+ +
{ extensions={[ xcodeLightPatch, EditorView.lineWrapping, + lineNumbers(), autocompletion({ icons: false, }), sql(), + runKeymap, ]} - basicSetup={{ - lineNumbers: true, - foldGutter: false, - indentOnInput: false, - autocompletion: true, - highlightActiveLine: false, - }} + basicSetup={false} onChange={(value) => setQuery(value)} editable={!loading} style={{ @@ -316,9 +334,9 @@ const PerfQuery: React.FC = () => { {/* Bottom Panel - Performance Results */} - -
-
+ +
+
{error ? (
@@ -338,4 +356,4 @@ const PerfQuery: React.FC = () => { ); }; -export default PerfQuery; \ No newline at end of file +export default PerfQuery; diff --git a/frontend/src/SQLQuery.tsx b/frontend/src/SQLQuery.tsx index 8769045c..df4f25ce 100644 --- a/frontend/src/SQLQuery.tsx +++ b/frontend/src/SQLQuery.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { useRouter } from 'next/router'; import CodeMirror from '@uiw/react-codemirror'; import { sql } from '@codemirror/lang-sql'; -import { EditorView } from '@codemirror/view'; +import { EditorView, keymap, lineNumbers } from '@codemirror/view'; import { autocompletion } from '@codemirror/autocomplete'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { xcodeLight, xcodeLightPatch } from './components/CodeMirrorTheme'; @@ -16,6 +16,13 @@ interface QueryResult { } const SQLQuery: React.FC = () => { + const isExecutionShortcut = (event: KeyboardEvent) => { + if (!(event.metaKey || event.ctrlKey)) { + return false; + } + return event.key === 'Enter' || event.key === 'NumpadEnter' || event.key === 'Return'; + }; + const router = useRouter(); // Get query ID from path parameters (for catch-all routes like [slug]) const pathQueryId = router.query.slug && Array.isArray(router.query.slug) @@ -122,21 +129,24 @@ SELECT * FROM students;`); }, [query, router]); // Add global keyboard event listener for Cmd+Enter - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { - e.preventDefault(); + const runKeymap = useMemo(() => keymap.of([ + { + key: 'Mod-Enter', + run: () => { executeQuery(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - - // Cleanup event listener on component unmount - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, [executeQuery]); + return true; + }, + preventDefault: true, + }, + { + key: 'Ctrl-Enter', + run: () => { + executeQuery(); + return true; + }, + preventDefault: true, + }, + ]), [executeQuery]); const renderTable = (result: QueryResult, index: number) => { // Handle empty data @@ -204,36 +214,40 @@ SELECT * FROM students;`); }; return ( -
- {/* Header */} -
-
- SQL Query - -
+
+
+ + Press โŒ˜โŽ to run
- - {/* Content - Resizable Panels */} -
- +
+ {/* Left Panel - SQL Editor */} - -
+ +
setQuery(value)} editable={!loading} style={{ @@ -267,9 +277,9 @@ SELECT * FROM students;`); {/* Right Panel - Results */} - -
-
+ +
+
{error ? (
@@ -295,4 +305,4 @@ SELECT * FROM students;`); ); }; -export default SQLQuery; \ No newline at end of file +export default SQLQuery; diff --git a/frontend/src/components/NotebookCell.tsx b/frontend/src/components/NotebookCell.tsx new file mode 100644 index 00000000..16a08143 --- /dev/null +++ b/frontend/src/components/NotebookCell.tsx @@ -0,0 +1,564 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import CodeMirror from '@uiw/react-codemirror'; +import { sql } from '@codemirror/lang-sql'; +import { EditorView, keymap, lineNumbers } from '@codemirror/view'; +import { autocompletion } from '@codemirror/autocomplete'; +import { xcodeLight, xcodeLightPatch } from './CodeMirrorTheme'; +import { NotebookCell, QueryResult } from '../types/notebook'; +import { formatRelativeTime } from '../utills/time'; +import { + PlayIcon, + ChevronDownIcon, + ChevronUpIcon, + ColumnsIcon, + CodeIcon, + GripIcon, + ExpandIcon, + EllipsisIcon, +} from './icons'; + +interface NotebookCellProps { + cell: NotebookCell; + index: number; + isActive: boolean; + canDelete: boolean; + onSqlChange: (sql: string) => void; + onExecute: () => void; + onDelete: () => void; + onSelect: () => void; + onToggleCollapse: () => void; + onToggleEditor: () => void; + onToggleResult: () => void; + onToggleFullscreen: () => void; + onMoveUp: () => void; + onMoveDown: () => void; + isFullscreen?: boolean; + dragState: { + isDragging: boolean; + isDragOver: boolean; + dragOverPosition?: 'before' | 'after'; + }; + onDragStart: () => void; + onDragEnd: () => void; + onDragOver: (placeAfter?: boolean) => void; + onDrop: (placeAfter?: boolean) => void; + onRunFromHere?: () => void; + onRunToHere?: () => void; +} + +const NotebookCellComponent: React.FC = ({ + cell, + index, + isActive, + canDelete, + onSqlChange, + onExecute, + onDelete, + onSelect, + onToggleCollapse, + onToggleEditor, + onToggleResult, + onToggleFullscreen, + onMoveUp, + onMoveDown, + isFullscreen = false, + dragState, + onDragStart, + onDragEnd, + onDragOver, + onDrop, + onRunFromHere = () => {}, + onRunToHere = () => {}, +}) => { + const cardRef = useRef(null); + const isExecutionShortcut = (event: KeyboardEvent) => { + if (!(event.metaKey || event.ctrlKey)) { + return false; + } + return event.key === 'Enter' || event.key === 'NumpadEnter' || event.key === 'Return'; + }; + const [menuOpen, setMenuOpen] = useState(false); + const menuRef = useRef(null); + const [runMenuOpen, setRunMenuOpen] = useState(false); + const runMenuRef = useRef(null); + + useEffect(() => { + if (!menuOpen) return; + const handleClick = (event: MouseEvent) => { + if (menuRef.current && !menuRef.current.contains(event.target as Node)) { + setMenuOpen(false); + } + }; + document.addEventListener('mousedown', handleClick); + return () => document.removeEventListener('mousedown', handleClick); + }, [menuOpen]); + + useEffect(() => { + if (!runMenuOpen) return; + const handleClick = (event: MouseEvent) => { + if (runMenuRef.current && !runMenuRef.current.contains(event.target as Node)) { + setRunMenuOpen(false); + } + }; + document.addEventListener('mousedown', handleClick); + return () => document.removeEventListener('mousedown', handleClick); + }, [runMenuOpen]); + + const showEditor = !cell.hideEditor && !cell.collapsed; + const showResult = !cell.hideResult && !cell.collapsed; + + const statusLabel = useMemo(() => { + if (cell.loading) return 'Running query'; + if (cell.lastExecutedAt) { + return `Ran ${formatRelativeTime(cell.lastExecutedAt)}`; + } + return 'Ready to run'; + }, [cell.loading, cell.lastExecutedAt]); + + const renderTable = (result: QueryResult) => { + if (!result.data || result.data.length === 0) { + return ( +
+ No data returned +
+ ); + } + + return ( +
+
+ + + + {result.columns.map((column, columnIndex) => ( + + ))} + + + + {result.data.map((row, rowIndex) => ( + + {row.map((value, cellIndex) => ( + + ))} + + ))} + +
+
{column}
+ {result.types && result.types[columnIndex] && ( +
{result.types[columnIndex]}
+ )} +
+ {value} +
+
+
+ ); + }; + + + const baseCardClasses = [ + 'flex', + 'gap-3', + 'rounded-2xl', + 'border', + 'bg-white/95', + 'backdrop-blur-[2px]', + 'transition-all', + dragState.isDragOver ? 'ring-1 ring-indigo-300 border-indigo-300' : 'border-gray-100', + isFullscreen + ? 'shadow-[0_0_0_2px_rgba(99,102,241,0.35)] border-indigo-300' + : isActive + ? 'shadow-[0_15px_35px_-20px_rgba(79,70,229,0.45)]' + : 'shadow-sm hover:shadow-md hover:border-gray-200', + cell.loading ? 'ring-1 ring-blue-300 border-blue-200 bg-blue-50/80' : '', + ].join(' '); + + // ๆ”พ็ฝฎๆŒ‡็คบๅ™จๆ ทๅผ + const dropIndicatorClass = [ + 'absolute', + 'left-0', + 'right-0', + 'h-1', + 'bg-indigo-500/80', + 'rounded-full', + 'transition-opacity', + 'pointer-events-none', + 'opacity-0', + ].join(' '); + + const dragTransformClass = dragState.isDragOver + ? dragState.dragOverPosition === 'after' + ? 'translate-y-1.5' + : '-translate-y-1.5' + : 'translate-y-0'; + const showTopIndicator = dragState.isDragOver && dragState.dragOverPosition === 'before'; + const showBottomIndicator = dragState.isDragOver && dragState.dragOverPosition === 'after'; + + const editorHeight = isFullscreen ? 'auto' : 'auto'; + const editorMinHeight = isFullscreen ? '44px' : '44px'; + const showSideControls = !isFullscreen; + const showMenu = !isFullscreen; + + const runKeymap = useMemo(() => keymap.of([ + { + key: 'Mod-Enter', + run: () => { + onExecute(); + return true; + }, + preventDefault: true, + }, + { + key: 'Mod-NumpadEnter', + run: () => { + onExecute(); + return true; + }, + preventDefault: true, + }, + { + key: 'Alt-Enter', + run: () => { + onRunFromHere?.(); + return true; + }, + preventDefault: true, + }, + { + key: 'Shift-Enter', + run: () => { + onRunToHere?.(); + return true; + }, + preventDefault: true, + }, + ]), [onExecute, onRunFromHere, onRunToHere]); + + const getPlaceAfter = (event: React.DragEvent) => { + if (!cardRef.current) { + return false; + } + const rect = cardRef.current.getBoundingClientRect(); + return event.clientY - rect.top > rect.height / 2; + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + onDragOver(getPlaceAfter(event)); + }; + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + onDrop(getPlaceAfter(event)); + }; + + const handleDragStartWrapper = (event: React.DragEvent) => { + event.dataTransfer.effectAllowed = 'move'; + event.dataTransfer.setData('text/plain', cell.id); + if (cardRef.current) { + const rect = cardRef.current.getBoundingClientRect(); + event.dataTransfer.setDragImage( + cardRef.current, + event.clientX - rect.left, + event.clientY - rect.top, + ); + } + onDragStart(); + }; + + const handleDragEndWrapper = (event: React.DragEvent) => { + event.preventDefault(); + onDragEnd(); + }; + + return ( +
+ {showTopIndicator && ( +
+ )} + +
+ {showSideControls && ( +
+
+ +
+
+ + {!cell.collapsed && ( + <> + + + + )} +
+
+ )} + +
+
+
+
{ + if (!cell.loading && cell.sql.trim()) { + setRunMenuOpen(true); + } + }} + onMouseLeave={() => setRunMenuOpen(false)} + > + + {runMenuOpen && !cell.loading && cell.sql.trim() && ( +
+ + + +
+ )} +
+ + {statusLabel} + +
+ +
+ + {showMenu && ( +
+ + {menuOpen && ( +
+ + + {canDelete && ( + + )} +
+ )} +
+ )} +
+
+ + {!cell.collapsed && ( +
+ {showEditor ? ( +
+ +
+ ) : ( +
{ + e.stopPropagation(); + onToggleEditor(); + }} + > +
+ {cell.sql || 'SQL editor collapsed'} +
+
Show editor
+
+ )} + + {cell.error && showResult && ( +
+ {cell.error} +
+ )} + + {!cell.error && showResult && cell.result && ( +
+
+ {cell.result.rowCount} row{cell.result.rowCount === 1 ? '' : 's'} returned {cell.result.duration ? `in ${cell.result.duration}` : ''} +
+
+ {renderTable(cell.result)} +
+
+ )} + + {!cell.error && !showResult && !cell.collapsed} +
+ )} +
+
+ + {/* ไธ‹ๆ–นๆ”พ็ฝฎๆŒ‡็คบๅ™จ */} + {showBottomIndicator && ( +
+ )} +
+ ); +}; + +export default NotebookCellComponent; diff --git a/frontend/src/components/icons.tsx b/frontend/src/components/icons.tsx new file mode 100644 index 00000000..5504a117 --- /dev/null +++ b/frontend/src/components/icons.tsx @@ -0,0 +1,61 @@ +import React from 'react'; + +export const PlayIcon: React.FC> = (props) => ( + + + +); + +export const ChevronDownIcon: React.FC> = (props) => ( + + + +); + +export const ChevronUpIcon: React.FC> = (props) => ( + + + +); + +export const ColumnsIcon: React.FC> = (props) => ( + + + + +); + +export const CodeIcon: React.FC> = (props) => ( + + + + +); + +export const GripIcon: React.FC> = (props) => ( + + + + + + + + +); + +export const ExpandIcon: React.FC> = (props) => ( + + + + + + +); + +export const EllipsisIcon: React.FC> = (props) => ( + + + + + +); diff --git a/frontend/src/index.css b/frontend/src/index.css index a90f0749..47ad4c46 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -2,3 +2,8 @@ @tailwind components; @tailwind utilities; +html, +body, +#__next { + height: 100%; +} diff --git a/frontend/src/types/notebook.ts b/frontend/src/types/notebook.ts new file mode 100644 index 00000000..1de4956c --- /dev/null +++ b/frontend/src/types/notebook.ts @@ -0,0 +1,32 @@ +export interface QueryResult { + columns: string[]; + types: string[]; + data: string[][]; + rowCount: number; + duration: string; +} + +export interface NotebookCell { + id: string; + sql: string; + result?: QueryResult; + error?: string; + loading: boolean; + lastExecutedAt?: Date; + collapsed?: boolean; + hideEditor?: boolean; + hideResult?: boolean; +} + +export interface Notebook { + id: string; + name: string; + cells: NotebookCell[]; + createdAt: Date; + updatedAt: Date; +} + +export interface NotebookStorage { + notebooks: Notebook[]; + currentNotebookId?: string; +} diff --git a/frontend/src/utills/index.ts b/frontend/src/utills/index.ts index b807d96e..632b49b9 100644 --- a/frontend/src/utills/index.ts +++ b/frontend/src/utills/index.ts @@ -1,4 +1,5 @@ export * from "./graph"; +export * from "./time"; /** * Formats a given percentage value. @@ -25,4 +26,4 @@ export function transformErrors(errors) { const type = Object.keys(error)[0]; return { _errorType: type, ...error[type] }; }); -} \ No newline at end of file +} diff --git a/frontend/src/utills/notebookStorage.ts b/frontend/src/utills/notebookStorage.ts new file mode 100644 index 00000000..1c941d00 --- /dev/null +++ b/frontend/src/utills/notebookStorage.ts @@ -0,0 +1,80 @@ +import { Notebook, NotebookCell, NotebookStorage } from '../types/notebook'; + +const STORAGE_KEY = 'bendsql-notebooks'; + +export const notebookStorage = { + // Get all notebooks from localStorage + getNotebooks(): NotebookStorage { + try { + const stored = localStorage.getItem(STORAGE_KEY); + if (stored) { + const data = JSON.parse(stored); + // Convert date strings back to Date objects + return { + notebooks: data.notebooks.map((nb: any) => ({ + ...nb, + createdAt: new Date(nb.createdAt), + updatedAt: new Date(nb.updatedAt), + cells: nb.cells.map((cell: any) => ({ + ...cell, + collapsed: cell.collapsed ?? false, + hideEditor: cell.hideEditor ?? false, + hideResult: cell.hideResult ?? false, + lastExecutedAt: cell.lastExecutedAt ? new Date(cell.lastExecutedAt) : undefined, + })), + })), + currentNotebookId: data.currentNotebookId, + }; + } + } catch (error) { + console.error('Failed to load notebooks from storage:', error); + } + + // Return default empty state + return { notebooks: [] }; + }, + + // Save notebooks to localStorage + saveNotebooks(storage: NotebookStorage): void { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(storage)); + } catch (error) { + console.error('Failed to save notebooks to storage:', error); + } + }, + + // Create a new notebook + createNotebook(name: string = 'Untitled Notebook'): Notebook { + const now = new Date(); + return { + id: generateId(), + name, + cells: [{ + id: generateId(), + sql: '', + loading: false, + collapsed: false, + hideEditor: false, + hideResult: false, + }], + createdAt: now, + updatedAt: now, + }; + }, + + // Create a new cell + createCell(): NotebookCell { + return { + id: generateId(), + sql: '', + loading: false, + collapsed: false, + hideEditor: false, + hideResult: false, + }; + }, +}; + +function generateId(): string { + return Date.now().toString(36) + Math.random().toString(36).substr(2); +} diff --git a/frontend/src/utills/time.ts b/frontend/src/utills/time.ts new file mode 100644 index 00000000..767aa6e5 --- /dev/null +++ b/frontend/src/utills/time.ts @@ -0,0 +1,34 @@ +export function formatRelativeTime(input?: Date | string | number): string { + if (!input) { + return ''; + } + + const date = input instanceof Date ? input : new Date(input); + if (isNaN(date.getTime())) { + return ''; + } + + const diff = Date.now() - date.getTime(); + const minute = 60 * 1000; + const hour = 60 * minute; + const day = 24 * hour; + const week = 7 * day; + + if (diff < minute) { + return 'just now'; + } + if (diff < hour) { + const minutes = Math.floor(diff / minute); + return `${minutes}m ago`; + } + if (diff < day) { + const hours = Math.floor(diff / hour); + return `${hours}h ago`; + } + if (diff < week) { + const days = Math.floor(diff / day); + return `${days}d ago`; + } + + return date.toLocaleDateString(); +}