d1s 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/.next/.next/BUILD_ID +1 -0
- package/dist/.next/.next/app-build-manifest.json +109 -0
- package/dist/.next/.next/app-path-routes-manifest.json +1 -0
- package/dist/.next/.next/build-manifest.json +33 -0
- package/dist/.next/.next/cache/.rscinfo +1 -0
- package/dist/.next/.next/cache/.tsbuildinfo +1 -0
- package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/dist/.next/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/dist/.next/.next/diagnostics/build-diagnostics.json +6 -0
- package/dist/.next/.next/diagnostics/framework.json +1 -0
- package/dist/.next/.next/export-marker.json +1 -0
- package/dist/.next/.next/images-manifest.json +1 -0
- package/dist/.next/.next/next-minimal-server.js.nft.json +1 -0
- package/dist/.next/.next/next-server.js.nft.json +1 -0
- package/dist/.next/.next/package.json +1 -0
- package/dist/.next/.next/prerender-manifest.json +1 -0
- package/dist/.next/.next/react-loadable-manifest.json +1 -0
- package/dist/.next/.next/required-server-files.json +1 -0
- package/dist/.next/.next/routes-manifest.json +1 -0
- package/dist/.next/.next/server/app/_not-found/page.js +1 -0
- package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/_not-found.html +1 -0
- package/dist/.next/.next/server/app/_not-found.meta +8 -0
- package/dist/.next/.next/server/app/_not-found.rsc +16 -0
- package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -0
- package/dist/.next/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/databases/route.js +1 -0
- package/dist/.next/.next/server/app/api/databases/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route.js +12 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +14 -0
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js +14 -0
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/query/route.js +8 -0
- package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/tables/route.js +7 -0
- package/dist/.next/.next/server/app/api/tables/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/index.html +3 -0
- package/dist/.next/.next/server/app/index.meta +7 -0
- package/dist/.next/.next/server/app/index.rsc +20 -0
- package/dist/.next/.next/server/app/page.js +58 -0
- package/dist/.next/.next/server/app/page.js.nft.json +1 -0
- package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app-paths-manifest.json +15 -0
- package/dist/.next/.next/server/chunks/336.js +1 -0
- package/dist/.next/.next/server/chunks/627.js +6 -0
- package/dist/.next/.next/server/chunks/638.js +13 -0
- package/dist/.next/.next/server/chunks/801.js +55 -0
- package/dist/.next/.next/server/chunks/973.js +2 -0
- package/dist/.next/.next/server/chunks/992.js +3 -0
- package/dist/.next/.next/server/functions-config-manifest.json +1 -0
- package/dist/.next/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/dist/.next/.next/server/middleware-build-manifest.js +1 -0
- package/dist/.next/.next/server/middleware-manifest.json +6 -0
- package/dist/.next/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/.next/.next/server/next-font-manifest.js +1 -0
- package/dist/.next/.next/server/next-font-manifest.json +1 -0
- package/dist/.next/.next/server/pages/404.html +1 -0
- package/dist/.next/.next/server/pages/500.html +1 -0
- package/dist/.next/.next/server/pages/_app.js +1 -0
- package/dist/.next/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/.next/.next/server/pages/_document.js +1 -0
- package/dist/.next/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/.next/.next/server/pages/_error.js +1 -0
- package/dist/.next/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/.next/.next/server/pages-manifest.json +1 -0
- package/dist/.next/.next/server/server-reference-manifest.js +1 -0
- package/dist/.next/.next/server/server-reference-manifest.json +1 -0
- package/dist/.next/.next/server/webpack-runtime.js +1 -0
- package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_buildManifest.js +1 -0
- package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_ssgManifest.js +1 -0
- package/dist/.next/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
- package/dist/.next/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
- package/dist/.next/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
- package/dist/.next/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
- package/dist/.next/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
- package/dist/.next/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
- package/dist/.next/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
- package/dist/.next/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
- package/dist/.next/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
- package/dist/.next/.next/static/chunks/framework-d29117d969504448.js +1 -0
- package/dist/.next/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
- package/dist/.next/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
- package/dist/.next/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
- package/dist/.next/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
- package/dist/.next/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/.next/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
- package/dist/.next/.next/static/css/c51a7ef325e30c16.css +3 -0
- package/dist/.next/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/dist/.next/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/.next/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/.next/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/dist/.next/.next/trace +3 -0
- package/dist/.next/.next/types/app/api/cloudflare/route.ts +347 -0
- package/dist/.next/.next/types/app/api/databases/route.ts +347 -0
- package/dist/.next/.next/types/app/api/migrations/sync/route.ts +347 -0
- package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +347 -0
- package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
- package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +347 -0
- package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +347 -0
- package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +347 -0
- package/dist/.next/.next/types/app/api/query/route.ts +347 -0
- package/dist/.next/.next/types/app/api/tables/[name]/route.ts +347 -0
- package/dist/.next/.next/types/app/api/tables/route.ts +347 -0
- package/dist/.next/.next/types/app/page.ts +84 -0
- package/dist/.next/.next/types/cache-life.d.ts +141 -0
- package/dist/.next/.next/types/package.json +1 -0
- package/dist/.next/BUILD_ID +1 -0
- package/dist/.next/app-build-manifest.json +109 -0
- package/dist/.next/app-path-routes-manifest.json +1 -0
- package/dist/.next/build-manifest.json +33 -0
- package/dist/.next/cache/.rscinfo +1 -0
- package/dist/.next/cache/.tsbuildinfo +1 -0
- package/dist/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/.next/diagnostics/build-diagnostics.json +6 -0
- package/dist/.next/diagnostics/framework.json +1 -0
- package/dist/.next/export-marker.json +1 -0
- package/dist/.next/images-manifest.json +1 -0
- package/dist/.next/next-minimal-server.js.nft.json +1 -0
- package/dist/.next/next-server.js.nft.json +1 -0
- package/dist/.next/package.json +1 -0
- package/dist/.next/prerender-manifest.json +1 -0
- package/dist/.next/react-loadable-manifest.json +1 -0
- package/dist/.next/required-server-files.json +1 -0
- package/dist/.next/routes-manifest.json +1 -0
- package/dist/.next/server/app/_not-found/page.js +1 -0
- package/dist/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/_not-found.html +1 -0
- package/dist/.next/server/app/_not-found.meta +8 -0
- package/dist/.next/server/app/_not-found.rsc +16 -0
- package/dist/.next/server/app/api/cloudflare/route.js +1 -0
- package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/databases/route.js +1 -0
- package/dist/.next/server/app/api/databases/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/migrations/sync/route.js +12 -0
- package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/migrations/sync-files/route.js +1 -0
- package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route.js +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/pull-remote/preview/route.js +1 -0
- package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/push-remote/confirm/route.js +14 -0
- package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/push-remote/preview/route.js +14 -0
- package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/query/route.js +8 -0
- package/dist/.next/server/app/api/query/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/tables/[name]/route.js +5 -0
- package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/tables/route.js +7 -0
- package/dist/.next/server/app/api/tables/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/index.html +3 -0
- package/dist/.next/server/app/index.meta +7 -0
- package/dist/.next/server/app/index.rsc +20 -0
- package/dist/.next/server/app/page.js +58 -0
- package/dist/.next/server/app/page.js.nft.json +1 -0
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/.next/server/app-paths-manifest.json +15 -0
- package/dist/.next/server/chunks/336.js +1 -0
- package/dist/.next/server/chunks/627.js +6 -0
- package/dist/.next/server/chunks/638.js +13 -0
- package/dist/.next/server/chunks/801.js +55 -0
- package/dist/.next/server/chunks/973.js +2 -0
- package/dist/.next/server/chunks/992.js +3 -0
- package/dist/.next/server/functions-config-manifest.json +1 -0
- package/dist/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/dist/.next/server/middleware-build-manifest.js +1 -0
- package/dist/.next/server/middleware-manifest.json +6 -0
- package/dist/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/.next/server/next-font-manifest.js +1 -0
- package/dist/.next/server/next-font-manifest.json +1 -0
- package/dist/.next/server/pages/404.html +1 -0
- package/dist/.next/server/pages/500.html +1 -0
- package/dist/.next/server/pages/_app.js +1 -0
- package/dist/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/.next/server/pages/_document.js +1 -0
- package/dist/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/.next/server/pages/_error.js +1 -0
- package/dist/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/.next/server/pages-manifest.json +1 -0
- package/dist/.next/server/server-reference-manifest.js +1 -0
- package/dist/.next/server/server-reference-manifest.json +1 -0
- package/dist/.next/server/webpack-runtime.js +1 -0
- package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_buildManifest.js +1 -0
- package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_ssgManifest.js +1 -0
- package/dist/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
- package/dist/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
- package/dist/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
- package/dist/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
- package/dist/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
- package/dist/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
- package/dist/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
- package/dist/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
- package/dist/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
- package/dist/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
- package/dist/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
- package/dist/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
- package/dist/.next/static/chunks/framework-d29117d969504448.js +1 -0
- package/dist/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
- package/dist/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
- package/dist/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
- package/dist/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
- package/dist/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
- package/dist/.next/static/css/c51a7ef325e30c16.css +3 -0
- package/dist/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/dist/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/dist/.next/trace +13 -0
- package/dist/.next/types/app/api/cloudflare/route.ts +347 -0
- package/dist/.next/types/app/api/databases/route.ts +347 -0
- package/dist/.next/types/app/api/migrations/sync/route.ts +347 -0
- package/dist/.next/types/app/api/migrations/sync-files/route.ts +347 -0
- package/dist/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
- package/dist/.next/types/app/api/pull-remote/preview/route.ts +347 -0
- package/dist/.next/types/app/api/push-remote/confirm/route.ts +347 -0
- package/dist/.next/types/app/api/push-remote/preview/route.ts +347 -0
- package/dist/.next/types/app/api/query/route.ts +347 -0
- package/dist/.next/types/app/api/tables/[name]/route.ts +347 -0
- package/dist/.next/types/app/api/tables/route.ts +347 -0
- package/dist/.next/types/app/page.ts +84 -0
- package/dist/.next/types/cache-life.d.ts +141 -0
- package/dist/.next/types/package.json +1 -0
- package/dist/app/api/cloudflare/route.js +146 -0
- package/dist/app/api/databases/route.js +72 -0
- package/dist/app/api/migrations/sync/route.js +172 -0
- package/dist/app/api/migrations/sync-files/route.js +172 -0
- package/dist/app/api/pull-remote/confirm/route.js +277 -0
- package/dist/app/api/pull-remote/preview/route.js +143 -0
- package/dist/app/api/push-remote/confirm/route.js +196 -0
- package/dist/app/api/push-remote/preview/route.js +178 -0
- package/dist/app/api/query/route.js +160 -0
- package/dist/app/api/tables/[name]/route.js +173 -0
- package/dist/app/api/tables/route.js +174 -0
- package/dist/app/app/api/cloudflare/route.js +146 -0
- package/dist/app/app/api/databases/route.js +72 -0
- package/dist/app/app/api/migrations/sync/route.js +172 -0
- package/dist/app/app/api/migrations/sync-files/route.js +172 -0
- package/dist/app/app/api/pull-remote/confirm/route.js +277 -0
- package/dist/app/app/api/pull-remote/preview/route.js +143 -0
- package/dist/app/app/api/push-remote/confirm/route.js +196 -0
- package/dist/app/app/api/push-remote/preview/route.js +178 -0
- package/dist/app/app/api/query/route.js +160 -0
- package/dist/app/app/api/tables/[name]/route.js +173 -0
- package/dist/app/app/api/tables/route.js +174 -0
- package/dist/app/app/globals.css +93 -0
- package/dist/app/app/layout.jsx +35 -0
- package/dist/app/app/page.jsx +37 -0
- package/dist/app/globals.css +93 -0
- package/dist/app/layout.jsx +35 -0
- package/dist/app/page.jsx +37 -0
- package/dist/d1-studio.js +344 -0
- package/dist/lib/database-queue.js +33 -0
- package/dist/lib/error.js +20 -0
- package/dist/lib/find-wrangler-config.js +67 -0
- package/dist/lib/license.js +99 -0
- package/dist/lib/migrations.js +415 -0
- package/dist/lib/parse-sql-error.js +200 -0
- package/dist/lib/request-deduplication.js +24 -0
- package/dist/lib/schema-operations.js +103 -0
- package/dist/lib/sql-error-types.js +14 -0
- package/dist/lib/sql-operations.js +557 -0
- package/dist/lib/utils.js +6 -0
- package/next.config.mjs +18 -0
- package/package.json +97 -0
- package/postcss.config.mjs +8 -0
- package/scripts/studio.js +344 -0
- package/scripts/test.js +168 -0
- package/src/app/api/cloudflare/route.js +146 -0
- package/src/app/api/databases/route.js +72 -0
- package/src/app/api/migrations/sync/route.js +172 -0
- package/src/app/api/migrations/sync-files/route.js +172 -0
- package/src/app/api/pull-remote/confirm/route.js +277 -0
- package/src/app/api/pull-remote/preview/route.js +143 -0
- package/src/app/api/push-remote/confirm/route.js +196 -0
- package/src/app/api/push-remote/preview/route.js +178 -0
- package/src/app/api/query/route.js +160 -0
- package/src/app/api/tables/[name]/route.js +173 -0
- package/src/app/api/tables/route.js +174 -0
- package/src/app/globals.css +93 -0
- package/src/app/layout.jsx +35 -0
- package/src/app/page.jsx +37 -0
- package/src/components/cloudflare-credentials-modal.jsx +94 -0
- package/src/components/column-selector.jsx +133 -0
- package/src/components/column-sorting.jsx +65 -0
- package/src/components/delete-records-dialog.jsx +64 -0
- package/src/components/download-button.jsx +205 -0
- package/src/components/edit-error-alert.jsx +30 -0
- package/src/components/editable-cell.jsx +163 -0
- package/src/components/editable-row.jsx +169 -0
- package/src/components/environment-handler.jsx +278 -0
- package/src/components/environment-select.jsx +59 -0
- package/src/components/pull-preview-toast.jsx +188 -0
- package/src/components/push-error-alert.jsx +72 -0
- package/src/components/push-preview-toast.jsx +183 -0
- package/src/components/query-results.jsx +112 -0
- package/src/components/refresh-button.jsx +61 -0
- package/src/components/resize-columns.jsx +101 -0
- package/src/components/sidebar.jsx +236 -0
- package/src/components/sql-editor.jsx +411 -0
- package/src/components/sql-error-display.jsx +167 -0
- package/src/components/sync-migrations-button.jsx +87 -0
- package/src/components/table-error-dialog.jsx +65 -0
- package/src/components/table-toolbar.jsx +285 -0
- package/src/components/table-view.jsx +843 -0
- package/src/components/ui/alert.jsx +47 -0
- package/src/components/ui/button.jsx +48 -0
- package/src/components/ui/card.jsx +50 -0
- package/src/components/ui/checkbox.jsx +24 -0
- package/src/components/ui/collapsible.jsx +11 -0
- package/src/components/ui/dialog.jsx +96 -0
- package/src/components/ui/dropdown-menu.jsx +158 -0
- package/src/components/ui/input.jsx +19 -0
- package/src/components/ui/scroll-area.jsx +40 -0
- package/src/components/ui/select.jsx +121 -0
- package/src/components/ui/separator.jsx +25 -0
- package/src/components/ui/sheet.jsx +109 -0
- package/src/components/ui/sidebar.jsx +620 -0
- package/src/components/ui/skeleton.jsx +14 -0
- package/src/components/ui/table.jsx +86 -0
- package/src/components/ui/tabs.jsx +43 -0
- package/src/components/ui/toast.jsx +86 -0
- package/src/components/ui/toaster.jsx +35 -0
- package/src/components/ui/tooltip.jsx +28 -0
- package/src/context/database-context.js +510 -0
- package/src/hooks/use-mobile.jsx +19 -0
- package/src/hooks/use-sql-error.ts +23 -0
- package/src/hooks/use-toast.js +155 -0
- package/src/lib/database-queue.js +33 -0
- package/src/lib/error.js +20 -0
- package/src/lib/find-wrangler-config.js +67 -0
- package/src/lib/license.js +99 -0
- package/src/lib/migrations.js +415 -0
- package/src/lib/parse-sql-error.js +200 -0
- package/src/lib/request-deduplication.js +24 -0
- package/src/lib/schema-operations.js +103 -0
- package/src/lib/sql-error-types.js +14 -0
- package/src/lib/sql-operations.js +557 -0
- package/src/lib/utils.js +6 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// components/sidebar.jsx
|
|
2
|
+
'use client';
|
|
3
|
+
|
|
4
|
+
import React, { useEffect, useState } from 'react';
|
|
5
|
+
import {
|
|
6
|
+
Table2,
|
|
7
|
+
Search,
|
|
8
|
+
Loader2,
|
|
9
|
+
AlertCircle,
|
|
10
|
+
TerminalSquare,
|
|
11
|
+
} from 'lucide-react';
|
|
12
|
+
import { Input } from '@/components/ui/input';
|
|
13
|
+
import { Alert, AlertDescription } from '@/components/ui/alert';
|
|
14
|
+
import { useDatabase } from '@/context/database-context';
|
|
15
|
+
import { CloudflareCredentialsModal } from './cloudflare-credentials-modal';
|
|
16
|
+
import { useEnvironmentController } from './environment-handler';
|
|
17
|
+
import { EnvironmentSelect } from './environment-select';
|
|
18
|
+
|
|
19
|
+
export function AppSidebar({
|
|
20
|
+
className,
|
|
21
|
+
currentView,
|
|
22
|
+
onNavigate,
|
|
23
|
+
onTableSelect,
|
|
24
|
+
}) {
|
|
25
|
+
const { tables, refreshTables, isLoading: isTablesLoading, error } = useDatabase();
|
|
26
|
+
const [databases, setDatabases] = useState([]);
|
|
27
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
28
|
+
const [environment, setEnvironment] = useState('local');
|
|
29
|
+
const [showCredentialsModal, setShowCredentialsModal] = useState(false);
|
|
30
|
+
const [selectedTable, setSelectedTable] = useState(null);
|
|
31
|
+
const [isTableLoading, setIsTableLoading] = useState(false);
|
|
32
|
+
|
|
33
|
+
const {
|
|
34
|
+
isConnecting,
|
|
35
|
+
isPushing,
|
|
36
|
+
showPreview,
|
|
37
|
+
connectToCloudflare,
|
|
38
|
+
pushToRemote,
|
|
39
|
+
pullFromRemote,
|
|
40
|
+
pullToRemotePreview,
|
|
41
|
+
validateStoredCredentials,
|
|
42
|
+
PreviewUI,
|
|
43
|
+
} = useEnvironmentController();
|
|
44
|
+
|
|
45
|
+
// Filter tables based on search term
|
|
46
|
+
const filteredTables =
|
|
47
|
+
tables?.filter((table) =>
|
|
48
|
+
table.toLowerCase().includes(searchTerm.toLowerCase())
|
|
49
|
+
) || [];
|
|
50
|
+
|
|
51
|
+
const handleTableClick = async (table) => {
|
|
52
|
+
try {
|
|
53
|
+
setIsTableLoading(true);
|
|
54
|
+
setSelectedTable(table);
|
|
55
|
+
onTableSelect(table);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('Error selecting table:', error);
|
|
58
|
+
} finally {
|
|
59
|
+
setIsTableLoading(false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const handleEnvironmentChange = async (value) => {
|
|
64
|
+
console.log('Environment change triggered:', value);
|
|
65
|
+
// Immediately update the environment state so the UI reflects the correct label
|
|
66
|
+
setEnvironment(value);
|
|
67
|
+
|
|
68
|
+
if (value === 'production') {
|
|
69
|
+
try {
|
|
70
|
+
const credentials = await validateStoredCredentials();
|
|
71
|
+
if (!credentials) {
|
|
72
|
+
setShowCredentialsModal(true);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Trigger push preview or push directly (as desired)
|
|
76
|
+
await pushToRemote();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('Environment change failed:', error);
|
|
79
|
+
setEnvironment('local');
|
|
80
|
+
}
|
|
81
|
+
} else if (value === 'pull') {
|
|
82
|
+
try {
|
|
83
|
+
const credentials = await validateStoredCredentials();
|
|
84
|
+
if (!credentials) {
|
|
85
|
+
setShowCredentialsModal(true);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Instead of immediately pulling, show the pull preview toast
|
|
89
|
+
await pullToRemotePreview();
|
|
90
|
+
// Optionally, you may keep the environment value as "pull" until confirmation,
|
|
91
|
+
// then revert to "local" in the confirm pull flow.
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error('Pull from remote failed:', error);
|
|
94
|
+
setEnvironment('local');
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
setEnvironment(value);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const fetchDatabases = async () => {
|
|
103
|
+
try {
|
|
104
|
+
const response = await fetch('/api/databases');
|
|
105
|
+
const data = await response.json();
|
|
106
|
+
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
throw new Error(data.error || 'Failed to fetch databases');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
setDatabases(data.databases || []);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('Error fetching databases:', error);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
fetchDatabases();
|
|
118
|
+
refreshTables();
|
|
119
|
+
}, [refreshTables]);
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<>
|
|
123
|
+
<aside className={`${className} bg-neutral-50 p-4`}>
|
|
124
|
+
<div className="font-sans">
|
|
125
|
+
{/* Header */}
|
|
126
|
+
<div className="flex items-center gap-2 mb-6">
|
|
127
|
+
<Table2 className="h-5 w-5" />
|
|
128
|
+
<span className="font-mono font-bold text-sm">d1-studio</span>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
{/* Error Message */}
|
|
132
|
+
{error && (
|
|
133
|
+
<Alert variant="destructive" className="mb-4">
|
|
134
|
+
<AlertCircle className="h-4 w-4" />
|
|
135
|
+
<AlertDescription className="text-sm ml-2">{error}</AlertDescription>
|
|
136
|
+
</Alert>
|
|
137
|
+
)}
|
|
138
|
+
|
|
139
|
+
{/* Database Section */}
|
|
140
|
+
<div className="flex items-center justify-between mb-6">
|
|
141
|
+
<div>
|
|
142
|
+
<div className="text-xs text-muted-foreground mb-1">Database name</div>
|
|
143
|
+
<div className="font-semibold text-sm">
|
|
144
|
+
{databases[0]?.database_name || 'No database found'}
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<EnvironmentSelect
|
|
149
|
+
value={environment}
|
|
150
|
+
onValueChange={handleEnvironmentChange}
|
|
151
|
+
isLoading={isPushing}
|
|
152
|
+
disabled={isConnecting}
|
|
153
|
+
showPreview={showPreview}
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
{/* SQL Editor Section */}
|
|
158
|
+
<div className="mb-6">
|
|
159
|
+
<button
|
|
160
|
+
className={`w-full flex items-center gap-x-1 border rounded-md text-sm font-medium transition-colors px-2 py-2
|
|
161
|
+
${currentView === 'sql-editor' ? 'bg-neutral-900 text-white' : 'bg-white hover:bg-neutral-100'}`}
|
|
162
|
+
onClick={() => onNavigate('sql-editor')}
|
|
163
|
+
disabled={isTableLoading}
|
|
164
|
+
>
|
|
165
|
+
<TerminalSquare className="h-[16px] w-[16px]" />
|
|
166
|
+
SQL editor
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{/* Search Section */}
|
|
171
|
+
<div className="relative mb-6 bg-white">
|
|
172
|
+
<Search className="absolute left-2 top-2.5 h-4 w-4 text-neutral-500" />
|
|
173
|
+
<Input
|
|
174
|
+
placeholder="Search tables"
|
|
175
|
+
value={searchTerm}
|
|
176
|
+
onChange={(e) => setSearchTerm(e.target.value)}
|
|
177
|
+
className="pl-7"
|
|
178
|
+
/>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
{/* Tables Section */}
|
|
182
|
+
<div>
|
|
183
|
+
<div className="flex items-center justify-between mb-1">
|
|
184
|
+
<h3 className="text-sm font-medium text-muted-foreground">
|
|
185
|
+
Tables {tables?.length ? `(${tables.length})` : ''}
|
|
186
|
+
</h3>
|
|
187
|
+
{isTablesLoading && <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />}
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
{/* Tables List */}
|
|
191
|
+
<div className="space-y-1 font-sans">
|
|
192
|
+
{!isTablesLoading && filteredTables.length === 0 && (
|
|
193
|
+
<div className="text-sm font-medium text-muted-foreground px-2 py-2">
|
|
194
|
+
{searchTerm
|
|
195
|
+
? 'No matching tables found'
|
|
196
|
+
: error
|
|
197
|
+
? 'Error loading tables'
|
|
198
|
+
: 'No tables available'
|
|
199
|
+
}
|
|
200
|
+
</div>
|
|
201
|
+
)}
|
|
202
|
+
|
|
203
|
+
{filteredTables.map((table) => (
|
|
204
|
+
<button
|
|
205
|
+
key={table}
|
|
206
|
+
className={`w-full text-left text-sm font-medium rounded-md transition-colors px-2 py-2
|
|
207
|
+
${currentView === 'table-view' && selectedTable === table
|
|
208
|
+
? 'bg-[#F0F0F0] text-neutral-900 font-semibold'
|
|
209
|
+
: 'text-neutral-700 hover:bg-[#F2F2F2]'}
|
|
210
|
+
${isTableLoading && 'opacity-50 cursor-not-allowed'}`}
|
|
211
|
+
onClick={() => handleTableClick(table)}
|
|
212
|
+
disabled={isTableLoading}
|
|
213
|
+
>
|
|
214
|
+
{table}
|
|
215
|
+
</button>
|
|
216
|
+
))}
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
{/* Cloudflare Credentials Modal */}
|
|
222
|
+
<CloudflareCredentialsModal
|
|
223
|
+
open={showCredentialsModal}
|
|
224
|
+
onClose={() => {
|
|
225
|
+
setShowCredentialsModal(false);
|
|
226
|
+
setEnvironment('local');
|
|
227
|
+
}}
|
|
228
|
+
onSubmit={connectToCloudflare}
|
|
229
|
+
/>
|
|
230
|
+
</aside>
|
|
231
|
+
|
|
232
|
+
{/* Preview UI */}
|
|
233
|
+
{PreviewUI}
|
|
234
|
+
</>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
4
|
+
import Editor from '@monaco-editor/react';
|
|
5
|
+
import { Loader2, Command, CornerDownLeft, GripHorizontal, ChevronDown } from 'lucide-react';
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { useDatabase } from '@/context/database-context';
|
|
8
|
+
import { SQLResultsView, SQLErrorDisplay } from './query-results';
|
|
9
|
+
import {
|
|
10
|
+
DropdownMenu,
|
|
11
|
+
DropdownMenuContent,
|
|
12
|
+
DropdownMenuItem,
|
|
13
|
+
DropdownMenuTrigger,
|
|
14
|
+
} from "@/components/ui/dropdown-menu";
|
|
15
|
+
import { parseSQLError } from '@/lib/parse-sql-error';
|
|
16
|
+
|
|
17
|
+
// Helpful predefined queries
|
|
18
|
+
const HELPFUL_QUERIES = {
|
|
19
|
+
// Table listing queries
|
|
20
|
+
'Show Tables': `SELECT name
|
|
21
|
+
FROM sqlite_master
|
|
22
|
+
WHERE type='table'
|
|
23
|
+
AND name NOT LIKE 'sqlite_%';`,
|
|
24
|
+
|
|
25
|
+
// Schema queries
|
|
26
|
+
'Table Schema': `-- Table Schema
|
|
27
|
+
-- Replace table_name with your table name
|
|
28
|
+
PRAGMA table_info(table_name);`,
|
|
29
|
+
|
|
30
|
+
'Table Indexes': `-- Table Indexes
|
|
31
|
+
-- Replace table_name with your table name
|
|
32
|
+
SELECT
|
|
33
|
+
m.name as table_name,
|
|
34
|
+
i.name as index_name,
|
|
35
|
+
i.sql as index_definition
|
|
36
|
+
FROM sqlite_master m
|
|
37
|
+
JOIN sqlite_master i ON m.name = i.tbl_name
|
|
38
|
+
WHERE m.type = 'table'
|
|
39
|
+
AND i.type = 'index'
|
|
40
|
+
AND m.name = 'table_name';`,
|
|
41
|
+
|
|
42
|
+
'Foreign Keys': `-- Foreign Key Information
|
|
43
|
+
-- Replace table_name with your table name
|
|
44
|
+
PRAGMA foreign_key_list(table_name);`,
|
|
45
|
+
|
|
46
|
+
// Data queries
|
|
47
|
+
'Table Data': `-- Table Data
|
|
48
|
+
-- Replace table_name with your table name
|
|
49
|
+
SELECT * FROM table_name LIMIT 100;`,
|
|
50
|
+
|
|
51
|
+
'Row Count': `-- Row Count
|
|
52
|
+
-- Replace table_name with your table name
|
|
53
|
+
SELECT COUNT(*) as total_rows FROM table_name;`,
|
|
54
|
+
|
|
55
|
+
'Column Stats': `-- Column Statistics
|
|
56
|
+
-- Replace table_name and column_name with your values
|
|
57
|
+
SELECT
|
|
58
|
+
COUNT(*) as total_rows,
|
|
59
|
+
COUNT(column_name) as non_null_count,
|
|
60
|
+
COUNT(DISTINCT column_name) as unique_values,
|
|
61
|
+
MIN(column_name) as min_value,
|
|
62
|
+
MAX(column_name) as max_value
|
|
63
|
+
FROM table_name;`,
|
|
64
|
+
|
|
65
|
+
// Schema modification
|
|
66
|
+
'Create Table': `CREATE TABLE IF NOT EXISTS new_table (
|
|
67
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
68
|
+
name TEXT NOT NULL,
|
|
69
|
+
email TEXT UNIQUE,
|
|
70
|
+
status TEXT CHECK(status IN ('active', 'inactive')) DEFAULT 'active',
|
|
71
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
-- Create indexes
|
|
75
|
+
CREATE INDEX idx_new_table_name ON new_table(name);
|
|
76
|
+
CREATE UNIQUE INDEX idx_new_table_email ON new_table(email);`,
|
|
77
|
+
|
|
78
|
+
'Create View': `-- Create a view
|
|
79
|
+
CREATE VIEW view_name AS
|
|
80
|
+
SELECT column1, column2
|
|
81
|
+
FROM table_name
|
|
82
|
+
WHERE condition;`
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Query categories for organization
|
|
86
|
+
const QUERY_CATEGORIES = {
|
|
87
|
+
'Schema Information': ['Show Tables', 'Table Schema', 'Table Indexes', 'Foreign Keys'],
|
|
88
|
+
'Data Queries': ['Table Data', 'Row Count', 'Column Stats'],
|
|
89
|
+
'Schema Modification': ['Create Table', 'Create View']
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
function QueryTemplateMenu({ onSelectQuery }) {
|
|
93
|
+
return (
|
|
94
|
+
<DropdownMenu>
|
|
95
|
+
<DropdownMenuTrigger asChild>
|
|
96
|
+
<Button variant="outline" size="sm">
|
|
97
|
+
Query Templates
|
|
98
|
+
<ChevronDown className="ml-2 h-4 w-4" />
|
|
99
|
+
</Button>
|
|
100
|
+
</DropdownMenuTrigger>
|
|
101
|
+
<DropdownMenuContent align="start" className="w-72">
|
|
102
|
+
{Object.entries(QUERY_CATEGORIES).map(([category, queryNames]) => (
|
|
103
|
+
<React.Fragment key={category}>
|
|
104
|
+
<div className="px-2 py-1.5 text-sm font-semibold text-neutral-900 font-sans">
|
|
105
|
+
{category}
|
|
106
|
+
</div>
|
|
107
|
+
{queryNames.map((queryName) => (
|
|
108
|
+
<DropdownMenuItem
|
|
109
|
+
key={queryName}
|
|
110
|
+
onClick={() => onSelectQuery(queryName)}
|
|
111
|
+
className="font-sans text-neutral-800"
|
|
112
|
+
>
|
|
113
|
+
{queryName}
|
|
114
|
+
</DropdownMenuItem>
|
|
115
|
+
))}
|
|
116
|
+
</React.Fragment>
|
|
117
|
+
))}
|
|
118
|
+
</DropdownMenuContent>
|
|
119
|
+
</DropdownMenu>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function SQLEditor() {
|
|
124
|
+
const { executeQuery, refreshTables } = useDatabase();
|
|
125
|
+
const [queryResult, setQueryResult] = useState(null);
|
|
126
|
+
const [isExecuting, setIsExecuting] = useState(false);
|
|
127
|
+
const [editorHeight, setEditorHeight] = useState(300);
|
|
128
|
+
const [isResizing, setIsResizing] = useState(false);
|
|
129
|
+
const editorRef = useRef(null);
|
|
130
|
+
const panelRef = useRef(null);
|
|
131
|
+
|
|
132
|
+
// Update the height of the panel on editorHeight change
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (panelRef.current) {
|
|
135
|
+
panelRef.current.style.height = `${editorHeight}px`;
|
|
136
|
+
}
|
|
137
|
+
}, [editorHeight]);
|
|
138
|
+
|
|
139
|
+
// Resizing logic for editor
|
|
140
|
+
const startResizing = useCallback((mouseDownEvent) => {
|
|
141
|
+
mouseDownEvent.preventDefault();
|
|
142
|
+
|
|
143
|
+
const startHeight = editorHeight;
|
|
144
|
+
const startY = mouseDownEvent.pageY;
|
|
145
|
+
|
|
146
|
+
const onMouseMove = (mouseMoveEvent) => {
|
|
147
|
+
const currentY = mouseMoveEvent.pageY;
|
|
148
|
+
const newHeight = startHeight + (currentY - startY);
|
|
149
|
+
const minHeight = 100;
|
|
150
|
+
const maxHeight = window.innerHeight * 0.8;
|
|
151
|
+
|
|
152
|
+
setEditorHeight(Math.min(Math.max(newHeight, minHeight), maxHeight));
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const onMouseUp = () => {
|
|
156
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
157
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
161
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
162
|
+
}, [editorHeight]);
|
|
163
|
+
|
|
164
|
+
// Execute query and refresh tables
|
|
165
|
+
const executeQueryAndRefresh = async () => {
|
|
166
|
+
if (!editorRef.current) return;
|
|
167
|
+
|
|
168
|
+
const query = editorRef.current.getValue().trim().replace(/;+$/, '');
|
|
169
|
+
if (!query) {
|
|
170
|
+
setQueryResult({
|
|
171
|
+
success: false,
|
|
172
|
+
error: { message: "Query cannot be empty." },
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
setIsExecuting(true);
|
|
179
|
+
setQueryResult(null);
|
|
180
|
+
|
|
181
|
+
const data = await executeQuery(query);
|
|
182
|
+
const isSchemaModifying = /^(CREATE|DROP|ALTER)\s+TABLE/i.test(query);
|
|
183
|
+
if (isSchemaModifying) {
|
|
184
|
+
await refreshTables();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let results = [];
|
|
188
|
+
|
|
189
|
+
// --- Updated extraction logic ---
|
|
190
|
+
if (data.results) {
|
|
191
|
+
if (Array.isArray(data.results)) {
|
|
192
|
+
// Check for the columns/values shape (typical for schema queries)
|
|
193
|
+
if (
|
|
194
|
+
data.results.length > 0 &&
|
|
195
|
+
data.results[0]?.columns &&
|
|
196
|
+
data.results[0]?.values
|
|
197
|
+
) {
|
|
198
|
+
const resultSet = data.results[0];
|
|
199
|
+
results = resultSet.values.map((row) =>
|
|
200
|
+
resultSet.columns.reduce((acc, col, idx) => {
|
|
201
|
+
acc[col] = row[idx];
|
|
202
|
+
return acc;
|
|
203
|
+
}, {})
|
|
204
|
+
);
|
|
205
|
+
} else {
|
|
206
|
+
// If we have one element with a "results" property, unwrap it.
|
|
207
|
+
if (
|
|
208
|
+
data.results.length === 1 &&
|
|
209
|
+
data.results[0].results &&
|
|
210
|
+
Array.isArray(data.results[0].results)
|
|
211
|
+
) {
|
|
212
|
+
results = data.results[0].results;
|
|
213
|
+
} else {
|
|
214
|
+
// Otherwise, assume data.results is already an array of row objects.
|
|
215
|
+
results = data.results;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} else if (data.results.columns && data.results.values) {
|
|
219
|
+
const resultSet = data.results;
|
|
220
|
+
results = resultSet.values.map((row) =>
|
|
221
|
+
resultSet.columns.reduce((acc, col, idx) => {
|
|
222
|
+
acc[col] = row[idx];
|
|
223
|
+
return acc;
|
|
224
|
+
}, {})
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
} else if (data.result && data.result.results) {
|
|
228
|
+
if (Array.isArray(data.result.results)) {
|
|
229
|
+
if (
|
|
230
|
+
data.result.results.length > 0 &&
|
|
231
|
+
data.result.results[0]?.columns &&
|
|
232
|
+
data.result.results[0]?.values
|
|
233
|
+
) {
|
|
234
|
+
const resultSet = data.result.results[0];
|
|
235
|
+
results = resultSet.values.map((row) =>
|
|
236
|
+
resultSet.columns.reduce((acc, col, idx) => {
|
|
237
|
+
acc[col] = row[idx];
|
|
238
|
+
return acc;
|
|
239
|
+
}, {})
|
|
240
|
+
);
|
|
241
|
+
} else {
|
|
242
|
+
if (
|
|
243
|
+
data.result.results.length === 1 &&
|
|
244
|
+
data.result.results[0].results &&
|
|
245
|
+
Array.isArray(data.result.results[0].results)
|
|
246
|
+
) {
|
|
247
|
+
results = data.result.results[0].results;
|
|
248
|
+
} else {
|
|
249
|
+
results = data.result.results;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
} else if (data.result.results.columns && data.result.results.values) {
|
|
253
|
+
const resultSet = data.result.results;
|
|
254
|
+
results = resultSet.values.map((row) =>
|
|
255
|
+
resultSet.columns.reduce((acc, col, idx) => {
|
|
256
|
+
acc[col] = row[idx];
|
|
257
|
+
return acc;
|
|
258
|
+
}, {})
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// --- End updated extraction logic ---
|
|
263
|
+
|
|
264
|
+
setQueryResult({
|
|
265
|
+
success: true,
|
|
266
|
+
results,
|
|
267
|
+
});
|
|
268
|
+
} catch (error) {
|
|
269
|
+
const parsedError = parseSQLError(error) || { message: 'An unknown error occurred', details: {} };
|
|
270
|
+
setQueryResult({
|
|
271
|
+
success: false,
|
|
272
|
+
error: parsedError,
|
|
273
|
+
});
|
|
274
|
+
} finally {
|
|
275
|
+
setIsExecuting(false);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const renderQueryResult = () => {
|
|
280
|
+
if (isExecuting) {
|
|
281
|
+
return (
|
|
282
|
+
<div className="flex items-center text-sm text-neutral-700">
|
|
283
|
+
<Loader2 className="h-4 w-4 animate-spin mr-2 font-sans" />
|
|
284
|
+
Running your query...
|
|
285
|
+
</div>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!queryResult) {
|
|
290
|
+
return <div className="text-sm text-neutral-500 font-sans">Run the query to see the results.</div>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (!queryResult.success) {
|
|
294
|
+
console.debug("SQLEditor - Rendering error:", queryResult.error);
|
|
295
|
+
return <SQLErrorDisplay error={queryResult.error} />;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const results = queryResult.results;
|
|
299
|
+
if (!results || results.length === 0) {
|
|
300
|
+
return <div className="text-sm text-neutral-900 font-sans">Success. No results to display.</div>;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return (
|
|
304
|
+
<SQLResultsView
|
|
305
|
+
query={editorRef.current?.getValue() || ''}
|
|
306
|
+
results={results}
|
|
307
|
+
/>
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<div className="h-full flex flex-col bg-white text-neutral-900 font-sans">
|
|
314
|
+
{/* Toolbar */}
|
|
315
|
+
<div className="px-4 py-2 bg-neutral-100 border-b flex items-center gap-4">
|
|
316
|
+
<QueryTemplateMenu
|
|
317
|
+
onSelectQuery={(queryType) => {
|
|
318
|
+
if (editorRef.current) {
|
|
319
|
+
// Normalize the queryType to match HELPFUL_QUERIES keys
|
|
320
|
+
const formattedQueryType = Object.keys(HELPFUL_QUERIES).find(
|
|
321
|
+
(key) => key.toLowerCase() === queryType.toLowerCase()
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
if (formattedQueryType) {
|
|
325
|
+
const query = HELPFUL_QUERIES[formattedQueryType];
|
|
326
|
+
editorRef.current.setValue(query);
|
|
327
|
+
editorRef.current.focus();
|
|
328
|
+
} else {
|
|
329
|
+
console.warn(`Query template not found for: ${queryType}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}}
|
|
333
|
+
/>
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
{/* Query Editor */}
|
|
337
|
+
<div
|
|
338
|
+
ref={panelRef}
|
|
339
|
+
className="relative pt-2 overflow-hidden"
|
|
340
|
+
style={{ height: `${editorHeight}px`, minHeight: '100px' }}
|
|
341
|
+
>
|
|
342
|
+
<Editor
|
|
343
|
+
height="100%"
|
|
344
|
+
language="sql"
|
|
345
|
+
options={{
|
|
346
|
+
minimap: { enabled: false },
|
|
347
|
+
fontSize: 14,
|
|
348
|
+
wordWrap: "on",
|
|
349
|
+
automaticLayout: true,
|
|
350
|
+
lineNumbers: "on",
|
|
351
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
352
|
+
}}
|
|
353
|
+
onMount={(editor) => {
|
|
354
|
+
editorRef.current = editor;
|
|
355
|
+
// Ensure that the "monaco" global is available.
|
|
356
|
+
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => {
|
|
357
|
+
executeQueryAndRefresh();
|
|
358
|
+
});
|
|
359
|
+
}}
|
|
360
|
+
/>
|
|
361
|
+
</div>
|
|
362
|
+
|
|
363
|
+
{/* Resizer */}
|
|
364
|
+
<div
|
|
365
|
+
className={`relative h-0.5 cursor-row-resize bg-neutral-200 group ${
|
|
366
|
+
isResizing ? "bg-neutral-300" : "hover:bg-neutral-300"
|
|
367
|
+
}`}
|
|
368
|
+
onMouseDown={(e) => {
|
|
369
|
+
setIsResizing(true);
|
|
370
|
+
startResizing(e);
|
|
371
|
+
}}
|
|
372
|
+
onMouseUp={() => setIsResizing(false)}
|
|
373
|
+
>
|
|
374
|
+
<div
|
|
375
|
+
className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-neutral-900 rounded-sm px-0.5
|
|
376
|
+
${isResizing ? "visible" : "invisible group-hover:visible"}`}
|
|
377
|
+
>
|
|
378
|
+
<GripHorizontal className="h-3 w-3 text-white" />
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
{/* Query Results */}
|
|
383
|
+
<div className="px-4 py-3 bg-neutral-100 border-b font-sans">
|
|
384
|
+
<div className="flex justify-between items-center">
|
|
385
|
+
<h3 className="text-sm font-medium">Results</h3>
|
|
386
|
+
<Button
|
|
387
|
+
size="sm"
|
|
388
|
+
onClick={executeQueryAndRefresh}
|
|
389
|
+
disabled={isExecuting}
|
|
390
|
+
className="flex items-center gap-1 text-sm font-medium"
|
|
391
|
+
>
|
|
392
|
+
Run
|
|
393
|
+
{isExecuting ? (
|
|
394
|
+
<Loader2 className="h-4 w-4 animate-spin" />
|
|
395
|
+
) : (
|
|
396
|
+
<>
|
|
397
|
+
<Command className="h-4 w-4" />
|
|
398
|
+
<CornerDownLeft className="h-4 w-4" />
|
|
399
|
+
</>
|
|
400
|
+
)}
|
|
401
|
+
</Button>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
{/* Render Query Results */}
|
|
406
|
+
<div className="flex-1 overflow-auto p-4 bg-white">
|
|
407
|
+
{renderQueryResult()}
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
);
|
|
411
|
+
}
|