@hienlh/ppm 0.13.8 → 0.13.10
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/CHANGELOG.md +6 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/ai-settings-section-ysK_Eixc.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-By4Nv3Gj.js +1 -0
- package/dist/web/assets/{audio-preview-DQbX8gfL.js → audio-preview-DISP-2AE.js} +1 -1
- package/dist/web/assets/{chat-tab-BJQT9kie.js → chat-tab-lp_mVSG-.js} +8 -8
- package/dist/web/assets/code-editor-BofKrbM8.js +8 -0
- package/dist/web/assets/{conflict-editor-BKwJLX0D.js → conflict-editor-kaAZUFD5.js} +1 -1
- package/dist/web/assets/csv-parser-Dly5nqE1.js +6 -0
- package/dist/web/assets/{csv-preview-D5lmgVEy.js → csv-preview-7TsYBQI6.js} +3 -3
- package/dist/web/assets/data-grid-overlay-editor-BjjuE4-G.js +1 -0
- package/dist/web/assets/data-grid-types-BTQHYBUh.js +1 -0
- package/dist/web/assets/database-DOWH9-Vv.js +1 -0
- package/dist/web/assets/database-viewer-P38Vxzkx.js +1 -0
- package/dist/web/assets/{diff-viewer-SAtaBwNI.js → diff-viewer-DlJfbgNJ.js} +1 -1
- package/dist/web/assets/dist-0kPgRaVx.js +1 -0
- package/dist/web/assets/{esm-nXReYVnB.js → esm-zjerHxpO.js} +1 -1
- package/dist/web/assets/{extension-webview-PiV4bKJ1.js → extension-webview-5s2MUx38.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BLXEKVf1.js +1 -0
- package/dist/web/assets/glide-data-grid-D5D1N3L7.js +136 -0
- package/dist/web/assets/glide-data-grid-nthEL3fk.css +1 -0
- package/dist/web/assets/{image-preview-CbFFD9BS.js → image-preview-C9osjEPa.js} +1 -1
- package/dist/web/assets/index-COOnLKGB.css +2 -0
- package/dist/web/assets/index-CpcqiQOx.js +27 -0
- package/dist/web/assets/info-3K5VOQVL-CEkPcChg.js +1 -0
- package/dist/web/assets/{input-BMvRUOr7.js → input-ozrR2DAV.js} +1 -1
- package/dist/web/assets/keybindings-store-COxqSoML.js +1 -0
- package/dist/web/assets/{markdown-renderer-CHWA0KAo.js → markdown-renderer-k3EA9XmF.js} +3 -3
- package/dist/web/assets/number-overlay-editor-BoRxunFN.js +9 -0
- package/dist/web/assets/packet-RMMSAZCW-DECxYTOi.js +1 -0
- package/dist/web/assets/{pdf-preview-DQMdjqa2.js → pdf-preview-DvgyxJX7.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-cjpNfVG5.js +1 -0
- package/dist/web/assets/{port-forwarding-tab-9BpNC9_7.js → port-forwarding-tab-CUkU6wac.js} +1 -1
- package/dist/web/assets/{postgres-viewer-Bm5T51n6.js → postgres-viewer-C1w0tqQw.js} +3 -3
- package/dist/web/assets/radar-KQ55EAFF-Dnpi068b.js +1 -0
- package/dist/web/assets/{settings-store-BHBb62gq.js → settings-store-B-OmHo3J.js} +1 -1
- package/dist/web/assets/settings-tab-D0zKyVwg.js +1 -0
- package/dist/web/assets/sql-query-editor-46hLU7MI.js +3 -0
- package/dist/web/assets/sqlite-viewer-DrLi8P6y.js +1 -0
- package/dist/web/assets/terminal-tab-DqA3fEoQ.js +1 -0
- package/dist/web/assets/treemap-KZPCXAKY-DRyb1eiw.js +1 -0
- package/dist/web/assets/{use-monaco-theme-CP-vyTF8.js → use-monaco-theme-DgzxiZS5.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-CMiurk2b.js → vendor-mermaid-CCmA_6Y0.js} +3 -3
- package/dist/web/assets/{video-preview-BLI_RruT.js → video-preview-BU7tibc4.js} +1 -1
- package/dist/web/assets/x-CG-_0yIW.js +1 -0
- package/dist/web/index.html +13 -14
- package/dist/web/sw.js +1 -1
- package/package.json +2 -1
- package/src/web/components/database/data-grid.tsx +18 -2
- package/src/web/components/database/database-viewer.tsx +19 -8
- package/src/web/components/database/export-button.tsx +38 -18
- package/src/web/components/database/glide-column-search.tsx +81 -0
- package/src/web/components/database/glide-context-menu.tsx +95 -0
- package/src/web/components/database/glide-data-grid.tsx +207 -0
- package/src/web/components/database/glide-data-preview-panel.tsx +113 -0
- package/src/web/components/database/glide-grid-pagination.tsx +34 -0
- package/src/web/components/database/glide-grid-theme.ts +82 -0
- package/src/web/components/database/glide-grid-toolbar.tsx +105 -0
- package/src/web/components/database/glide-grid-types.ts +81 -0
- package/src/web/components/database/glide-header-menu.tsx +111 -0
- package/src/web/components/database/glide-save-bar.tsx +33 -0
- package/src/web/components/database/sql-query-editor.tsx +14 -4
- package/src/web/components/database/use-database.ts +10 -2
- package/src/web/components/database/use-glide-cell-content.ts +159 -0
- package/src/web/components/database/use-glide-columns.ts +69 -0
- package/src/web/components/database/use-glide-grid-actions.ts +164 -0
- package/src/web/components/database/use-glide-pending-edits.ts +72 -0
- package/src/web/components/database/use-glide-row-pinning.ts +35 -0
- package/src/web/components/database/use-glide-selection.ts +48 -0
- package/src/web/components/editor/code-editor.tsx +126 -7
- package/src/web/components/layout/editor-panel.tsx +2 -2
- package/src/web/components/sqlite/sqlite-viewer.tsx +21 -12
- package/src/web/components/sqlite/use-sqlite.ts +1 -1
- package/src/web/hooks/use-terminal.ts +1 -1
- package/src/web/index.html +1 -0
- package/test.sql +1 -0
- package/dist/web/assets/ai-settings-section-CHgpQ_OP.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-WMbLpD5Y.js +0 -1
- package/dist/web/assets/code-editor-CeKTvfyz.js +0 -8
- package/dist/web/assets/csv-parser-DO0dz4x_.js +0 -6
- package/dist/web/assets/database-DCT0OjgQ.js +0 -1
- package/dist/web/assets/database-viewer-DixWWvjx.js +0 -5
- package/dist/web/assets/gitGraph-HDMCJU4V-BdPTuzO3.js +0 -1
- package/dist/web/assets/index-C1RBJe0a.css +0 -2
- package/dist/web/assets/index-ZFyltHwi.js +0 -27
- package/dist/web/assets/info-3K5VOQVL-MHX_1JfR.js +0 -1
- package/dist/web/assets/keybindings-store-D0C-Pq2o.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-CreFbf9A.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-CnaHXUh8.js +0 -1
- package/dist/web/assets/plus-51UQ45rf.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-UxsdRHvt.js +0 -1
- package/dist/web/assets/settings-tab-BUstSDLR.js +0 -1
- package/dist/web/assets/sql-completion-provider-tCzZfqWs.js +0 -1
- package/dist/web/assets/sql-query-editor-CMQpaOjA.js +0 -3
- package/dist/web/assets/sqlite-viewer-C7rhO4bn.js +0 -1
- package/dist/web/assets/terminal-tab-Xtj6RN0d.js +0 -1
- package/dist/web/assets/trash-2-CJYoLw7Q.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-CBVPi4NV.js +0 -1
- package/dist/web/assets/x-BtqbfkR7.js +0 -1
- /package/dist/web/assets/{arrow-up-Dtrfv490.js → arrow-up-Rcw6_KKu.js} +0 -0
- /package/dist/web/assets/{chevron-right-BzAdxJRG.js → chevron-right-DnHIvvcy.js} +0 -0
- /package/dist/web/assets/{code-CuravVys.js → code-DGBecc50.js} +0 -0
- /package/dist/web/assets/{dist-D7KGU7Vl.js → dist-CaKCIxem.js} +0 -0
- /package/dist/web/assets/{dist-CGvx1c8C.js → dist-DGSkE2Ml.js} +0 -0
- /package/dist/web/assets/{katex-BFE6i_OH.js → katex-BuytEdO1.js} +0 -0
- /package/dist/web/assets/{lib-D_kRA9p6.js → lib-DQHnkzGy.js} +0 -0
- /package/dist/web/assets/{refresh-cw-CSFrDtiu.js → refresh-cw-LlbZDJpO.js} +0 -0
- /package/dist/web/assets/{scroll-area-BEllam7_.js → scroll-area-7H-Q_k8c.js} +0 -0
- /package/dist/web/assets/{sparkles-B0mRBy_j.js → sparkles-fWUT5Vzq.js} +0 -0
- /package/dist/web/assets/{table-Dq575bPF.js → table-tf7pRkME.js} +0 -0
- /package/dist/web/assets/{text-wrap-Cn6BNQfq.js → text-wrap-BV-R4Vvy.js} +0 -0
- /package/dist/web/assets/{use-blob-url-Hn6n1730.js → use-blob-url-e9uTXjv5.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-u3AZMvTx.js → vendor-xterm-CU2c3f0A.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as e}from"./vendor-markdown-0Mxgxy0L.js";import{t}from"./file-exclamation-point-Baz81y5z.js";import"./api-client-Dvzcc_EO.js";import{G as n}from"./index-
|
|
1
|
+
import{b as e}from"./vendor-markdown-0Mxgxy0L.js";import{t}from"./file-exclamation-point-Baz81y5z.js";import"./api-client-Dvzcc_EO.js";import{G as n}from"./index-CpcqiQOx.js";import{t as r}from"./use-blob-url-e9uTXjv5.js";var i=e();function a({filePath:e,projectName:a}){let{blobUrl:o,error:s}=r(e,a);return s?(0,i.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,i.jsx)(t,{className:`size-10 text-text-subtle`}),(0,i.jsx)(`p`,{className:`text-sm`,children:`Failed to load video.`})]}):o?(0,i.jsx)(`div`,{className:`flex items-center justify-center h-full p-4 bg-surface overflow-auto`,children:(0,i.jsx)(`video`,{src:o,controls:!0,className:`max-w-full max-h-full`})}):(0,i.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,i.jsx)(n,{className:`size-5 animate-spin text-text-subtle`})})}export{a as VideoPreview};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./createLucideIcon-BjHrJDVb.js";var t=e(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]),n=e(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),r=e(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),i=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]),a=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{t as a,n as i,i as n,r,a as t};
|
package/dist/web/index.html
CHANGED
|
@@ -39,32 +39,31 @@
|
|
|
39
39
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
40
40
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
41
41
|
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
42
|
-
<script type="module" crossorigin src="/assets/index-
|
|
42
|
+
<script type="module" crossorigin src="/assets/index-CpcqiQOx.js"></script>
|
|
43
43
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-FhOqtrmT.js">
|
|
44
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-
|
|
44
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-CCmA_6Y0.js">
|
|
45
45
|
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-0Mxgxy0L.js">
|
|
46
46
|
<link rel="modulepreload" crossorigin href="/assets/vendor-ui-B-89Uj8i.js">
|
|
47
47
|
<link rel="modulepreload" crossorigin href="/assets/utils-CTg5uAYR.js">
|
|
48
48
|
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-BjHrJDVb.js">
|
|
49
|
-
<link rel="modulepreload" crossorigin href="/assets/x-
|
|
50
|
-
<link rel="modulepreload" crossorigin href="/assets/input-
|
|
49
|
+
<link rel="modulepreload" crossorigin href="/assets/x-CG-_0yIW.js">
|
|
50
|
+
<link rel="modulepreload" crossorigin href="/assets/input-ozrR2DAV.js">
|
|
51
51
|
<link rel="modulepreload" crossorigin href="/assets/react-GqWghJ-L.js">
|
|
52
52
|
<link rel="modulepreload" crossorigin href="/assets/api-client-Dvzcc_EO.js">
|
|
53
|
-
<link rel="modulepreload" crossorigin href="/assets/settings-store-
|
|
54
|
-
<link rel="modulepreload" crossorigin href="/assets/scroll-area-
|
|
55
|
-
<link rel="modulepreload" crossorigin href="/assets/dist-
|
|
56
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
57
|
-
<link rel="modulepreload" crossorigin href="/assets/refresh-cw-CSFrDtiu.js">
|
|
58
|
-
<link rel="modulepreload" crossorigin href="/assets/trash-2-CJYoLw7Q.js">
|
|
53
|
+
<link rel="modulepreload" crossorigin href="/assets/settings-store-B-OmHo3J.js">
|
|
54
|
+
<link rel="modulepreload" crossorigin href="/assets/scroll-area-7H-Q_k8c.js">
|
|
55
|
+
<link rel="modulepreload" crossorigin href="/assets/dist-CaKCIxem.js">
|
|
56
|
+
<link rel="modulepreload" crossorigin href="/assets/refresh-cw-LlbZDJpO.js">
|
|
59
57
|
<link rel="modulepreload" crossorigin href="/assets/api-settings-D0_eiIYv.js">
|
|
60
|
-
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-
|
|
61
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
62
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
58
|
+
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-ysK_Eixc.js">
|
|
59
|
+
<link rel="modulepreload" crossorigin href="/assets/database-DOWH9-Vv.js">
|
|
60
|
+
<link rel="modulepreload" crossorigin href="/assets/chevron-right-DnHIvvcy.js">
|
|
63
61
|
<link rel="modulepreload" crossorigin href="/assets/file-store-BrbCNyLm.js">
|
|
64
62
|
<link rel="modulepreload" crossorigin href="/assets/tab-store-0rGchMXr.js">
|
|
65
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
63
|
+
<link rel="stylesheet" crossorigin href="/assets/index-COOnLKGB.css">
|
|
66
64
|
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
67
65
|
<body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
|
|
66
|
+
<div id="portal" style="position: fixed; left: 0; top: 0; z-index: 9999;" /></div>
|
|
68
67
|
<div id="root"></div>
|
|
69
68
|
</body>
|
|
70
69
|
</html>
|
package/dist/web/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"0243ed2ed58acd13176b487d17e042d9","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/dist-D7KGU7Vl.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/scroll-area-BEllam7_.js"},{"revision":null,"url":"assets/extension-webview-PiV4bKJ1.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-BdPTuzO3.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-CnaHXUh8.js"},{"revision":null,"url":"assets/audio-preview-DQbX8gfL.js"},{"revision":null,"url":"assets/chat-tab-BJQT9kie.js"},{"revision":null,"url":"assets/ai-settings-section-CHgpQ_OP.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/code-editor-CeKTvfyz.js"},{"revision":null,"url":"assets/settings-store-BHBb62gq.js"},{"revision":null,"url":"assets/react-GqWghJ-L.js"},{"revision":null,"url":"assets/file-exclamation-point-Baz81y5z.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/diff-viewer-SAtaBwNI.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/chevron-right-BzAdxJRG.js"},{"revision":null,"url":"assets/info-3K5VOQVL-MHX_1JfR.js"},{"revision":null,"url":"assets/conflict-editor-BKwJLX0D.js"},{"revision":null,"url":"assets/lib-D_kRA9p6.js"},{"revision":null,"url":"assets/x-BtqbfkR7.js"},{"revision":null,"url":"assets/dist-CGvx1c8C.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/postgres-viewer-Bm5T51n6.js"},{"revision":null,"url":"assets/api-settings-D0_eiIYv.js"},{"revision":null,"url":"assets/port-forwarding-tab-9BpNC9_7.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-CBVPi4NV.js"},{"revision":null,"url":"assets/csv-preview-D5lmgVEy.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/index-C1RBJe0a.css"},{"revision":null,"url":"assets/radar-KQ55EAFF-UxsdRHvt.js"},{"revision":null,"url":"assets/api-client-Dvzcc_EO.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-WMbLpD5Y.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/table-Dq575bPF.js"},{"revision":null,"url":"assets/tab-store-0rGchMXr.js"},{"revision":null,"url":"assets/settings-tab-BUstSDLR.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/database-viewer-DixWWvjx.js"},{"revision":null,"url":"assets/pdf-preview-DQMdjqa2.js"},{"revision":null,"url":"assets/plus-51UQ45rf.js"},{"revision":null,"url":"assets/sql-query-editor-CMQpaOjA.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/arrow-up-Dtrfv490.js"},{"revision":null,"url":"assets/markdown-renderer-CHWA0KAo.js"},{"revision":null,"url":"assets/sqlite-viewer-C7rhO4bn.js"},{"revision":null,"url":"assets/input-BMvRUOr7.js"},{"revision":null,"url":"assets/refresh-cw-CSFrDtiu.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/esm-nXReYVnB.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"revision":null,"url":"assets/text-wrap-Cn6BNQfq.js"},{"revision":null,"url":"assets/katex-BFE6i_OH.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/trash-2-CJYoLw7Q.js"},{"revision":null,"url":"assets/keybindings-store-D0C-Pq2o.js"},{"revision":null,"url":"assets/use-monaco-theme-CP-vyTF8.js"},{"revision":null,"url":"assets/file-store-BrbCNyLm.js"},{"revision":null,"url":"assets/use-blob-url-Hn6n1730.js"},{"revision":null,"url":"assets/utils-CTg5uAYR.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/database-DCT0OjgQ.js"},{"revision":null,"url":"assets/vendor-mermaid-CMiurk2b.js"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/csv-parser-DO0dz4x_.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/terminal-tab-Xtj6RN0d.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/code-CuravVys.js"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/sparkles-B0mRBy_j.js"},{"revision":null,"url":"assets/vendor-ui-B-89Uj8i.js"},{"revision":null,"url":"assets/index-ZFyltHwi.js"},{"revision":null,"url":"assets/vendor-xterm-u3AZMvTx.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-CreFbf9A.js"},{"revision":null,"url":"assets/sql-completion-provider-tCzZfqWs.js"},{"revision":null,"url":"assets/image-preview-CbFFD9BS.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/video-preview-BLI_RruT.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"79c8870653c8f419f2e3323085e1f4be","url":"manifest.webmanifest"}]),self.addEventListener(`push`,e=>{e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{if(t.some(e=>e.visibilityState===`visible`))return;let n=e.data?.json()??{title:`PPM`,body:`Chat completed`};return self.registration.showNotification(n.title,{body:n.body,icon:`/icon-192.png`,badge:`/icon-192.png`,tag:`ppm-chat-done`,silent:!1,data:{url:self.location.origin}})}))}),self.addEventListener(`notificationclick`,e=>{e.notification.close(),e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{for(let e of t)if(e.url.includes(self.location.origin)&&`focus`in e)return e.focus();return self.clients.openWindow(e.notification.data?.url||`/`)}))});
|
|
1
|
+
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"754be60fd595e9b890e646393f190464","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/use-blob-url-e9uTXjv5.js"},{"revision":null,"url":"assets/vendor-xterm-CU2c3f0A.js"},{"revision":null,"url":"assets/settings-store-B-OmHo3J.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/refresh-cw-LlbZDJpO.js"},{"revision":null,"url":"assets/pdf-preview-DvgyxJX7.js"},{"revision":null,"url":"assets/react-GqWghJ-L.js"},{"revision":null,"url":"assets/file-exclamation-point-Baz81y5z.js"},{"revision":null,"url":"assets/markdown-renderer-k3EA9XmF.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/database-DOWH9-Vv.js"},{"revision":null,"url":"assets/postgres-viewer-C1w0tqQw.js"},{"revision":null,"url":"assets/katex-BuytEdO1.js"},{"revision":null,"url":"assets/conflict-editor-kaAZUFD5.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/pie-UPGHQEXC-cjpNfVG5.js"},{"revision":null,"url":"assets/code-editor-BofKrbM8.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/packet-RMMSAZCW-DECxYTOi.js"},{"revision":null,"url":"assets/api-settings-D0_eiIYv.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/ai-settings-section-ysK_Eixc.js"},{"revision":null,"url":"assets/database-viewer-P38Vxzkx.js"},{"revision":null,"url":"assets/api-client-Dvzcc_EO.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/data-grid-overlay-editor-BjjuE4-G.js"},{"revision":null,"url":"assets/video-preview-BU7tibc4.js"},{"revision":null,"url":"assets/csv-preview-7TsYBQI6.js"},{"revision":null,"url":"assets/tab-store-0rGchMXr.js"},{"revision":null,"url":"assets/port-forwarding-tab-CUkU6wac.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/sql-query-editor-46hLU7MI.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/sqlite-viewer-DrLi8P6y.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/x-CG-_0yIW.js"},{"revision":null,"url":"assets/csv-parser-Dly5nqE1.js"},{"revision":null,"url":"assets/index-CpcqiQOx.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/data-grid-types-BTQHYBUh.js"},{"revision":null,"url":"assets/dist-DGSkE2Ml.js"},{"revision":null,"url":"assets/code-DGBecc50.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/glide-data-grid-D5D1N3L7.js"},{"revision":null,"url":"assets/text-wrap-BV-R4Vvy.js"},{"revision":null,"url":"assets/arrow-up-Rcw6_KKu.js"},{"revision":null,"url":"assets/vendor-mermaid-CCmA_6Y0.js"},{"revision":null,"url":"assets/file-store-BrbCNyLm.js"},{"revision":null,"url":"assets/sparkles-fWUT5Vzq.js"},{"revision":null,"url":"assets/dist-0kPgRaVx.js"},{"revision":null,"url":"assets/index-COOnLKGB.css"},{"revision":null,"url":"assets/treemap-KZPCXAKY-DRyb1eiw.js"},{"revision":null,"url":"assets/utils-CTg5uAYR.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/chat-tab-lp_mVSG-.js"},{"revision":null,"url":"assets/image-preview-C9osjEPa.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/esm-zjerHxpO.js"},{"revision":null,"url":"assets/use-monaco-theme-DgzxiZS5.js"},{"revision":null,"url":"assets/scroll-area-7H-Q_k8c.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-By4Nv3Gj.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-Dnpi068b.js"},{"revision":null,"url":"assets/dist-CaKCIxem.js"},{"revision":null,"url":"assets/chevron-right-DnHIvvcy.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/table-tf7pRkME.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-BLXEKVf1.js"},{"revision":null,"url":"assets/number-overlay-editor-BoRxunFN.js"},{"revision":null,"url":"assets/vendor-ui-B-89Uj8i.js"},{"revision":null,"url":"assets/terminal-tab-DqA3fEoQ.js"},{"revision":null,"url":"assets/extension-webview-5s2MUx38.js"},{"revision":null,"url":"assets/input-ozrR2DAV.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/info-3K5VOQVL-CEkPcChg.js"},{"revision":null,"url":"assets/settings-tab-D0zKyVwg.js"},{"revision":null,"url":"assets/lib-DQHnkzGy.js"},{"revision":null,"url":"assets/keybindings-store-COxqSoML.js"},{"revision":null,"url":"assets/audio-preview-DISP-2AE.js"},{"revision":null,"url":"assets/diff-viewer-DlJfbgNJ.js"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"79c8870653c8f419f2e3323085e1f4be","url":"manifest.webmanifest"}]),self.addEventListener(`push`,e=>{e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{if(t.some(e=>e.visibilityState===`visible`))return;let n=e.data?.json()??{title:`PPM`,body:`Chat completed`};return self.registration.showNotification(n.title,{body:n.body,icon:`/icon-192.png`,badge:`/icon-192.png`,tag:`ppm-chat-done`,silent:!1,data:{url:self.location.origin}})}))}),self.addEventListener(`notificationclick`,e=>{e.notification.close(),e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{for(let e of t)if(e.url.includes(self.location.origin)&&`focus`in e)return e.focus();return self.clients.openWindow(e.notification.data?.url||`/`)}))});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hienlh/ppm",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.10",
|
|
4
4
|
"description": "Personal Project Manager — mobile-first web IDE with AI assistance",
|
|
5
5
|
"author": "hienlh",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@anthropic-ai/claude-agent-sdk": "^0.2.81",
|
|
47
47
|
"@codemirror/lang-sql": "^6.10.0",
|
|
48
|
+
"@glideapps/glide-data-grid": "^6.0.3",
|
|
48
49
|
"@inquirer/prompts": "^8.3.0",
|
|
49
50
|
"@monaco-editor/react": "^4.7.0",
|
|
50
51
|
"@radix-ui/react-switch": "^1.2.6",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback, useMemo, useRef, memo, useEffect } from "react";
|
|
2
2
|
import Editor from "@monaco-editor/react";
|
|
3
|
-
import { Loader2, ChevronLeft, ChevronRight, ChevronUp, ChevronDown, Trash2, Plus, Search, X, Eye, ExternalLink, WrapText, Sparkles, Filter, Pin, PinOff, Columns3 } from "lucide-react";
|
|
3
|
+
import { Loader2, ChevronLeft, ChevronRight, ChevronUp, ChevronDown, Trash2, Plus, Search, X, Eye, ExternalLink, WrapText, Sparkles, GripHorizontal, Filter, Pin, PinOff, Columns3 } from "lucide-react";
|
|
4
4
|
import { useShallow } from "zustand/react/shallow";
|
|
5
5
|
import { useTabStore } from "@/stores/tab-store";
|
|
6
6
|
import { useMonacoTheme } from "@/lib/use-monaco-theme";
|
|
@@ -652,8 +652,24 @@ function DataPreviewPanel({ data, onClose, onOpenInTab }: {
|
|
|
652
652
|
}
|
|
653
653
|
}, [beautified, data.content, data.language]);
|
|
654
654
|
|
|
655
|
+
const [panelHeight, setPanelHeight] = useState(200);
|
|
656
|
+
const handleDrag = useCallback((e: React.MouseEvent) => {
|
|
657
|
+
e.preventDefault();
|
|
658
|
+
const startY = e.clientY;
|
|
659
|
+
const startH = panelHeight;
|
|
660
|
+
const onMove = (ev: MouseEvent) => setPanelHeight(Math.max(80, startH + (startY - ev.clientY)));
|
|
661
|
+
const onUp = () => { document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
|
|
662
|
+
document.addEventListener("mousemove", onMove);
|
|
663
|
+
document.addEventListener("mouseup", onUp);
|
|
664
|
+
}, [panelHeight]);
|
|
665
|
+
|
|
655
666
|
return (
|
|
656
|
-
<div className="shrink-0 border-t border-border flex flex-col" style={{ height:
|
|
667
|
+
<div className="shrink-0 border-t border-border flex flex-col" style={{ height: panelHeight }}>
|
|
668
|
+
{/* Resize handle */}
|
|
669
|
+
<div onMouseDown={handleDrag}
|
|
670
|
+
className="shrink-0 h-1.5 cursor-row-resize bg-border/50 hover:bg-primary/30 flex items-center justify-center transition-colors">
|
|
671
|
+
<GripHorizontal className="size-3 text-muted-foreground/50" />
|
|
672
|
+
</div>
|
|
657
673
|
<div className="flex items-center gap-1 px-2 py-1 bg-muted/50 border-b border-border shrink-0">
|
|
658
674
|
<Eye className="size-3 text-muted-foreground" />
|
|
659
675
|
<span className="text-xs font-medium text-foreground truncate flex-1">{data.title}</span>
|
|
@@ -4,7 +4,7 @@ import { api } from "@/lib/api-client";
|
|
|
4
4
|
import { useDatabase, type DbColumnInfo } from "./use-database";
|
|
5
5
|
import { SqlQueryEditor } from "./sql-query-editor";
|
|
6
6
|
import { ExportButton } from "./export-button";
|
|
7
|
-
import {
|
|
7
|
+
import { GlideDataGrid } from "./glide-data-grid";
|
|
8
8
|
import type { SchemaInfo } from "./sql-completion-provider";
|
|
9
9
|
|
|
10
10
|
/** Parse WHERE "col" ILIKE '%val%' clauses from SQL */
|
|
@@ -141,6 +141,10 @@ export function DatabaseViewer({ metadata }: Props) {
|
|
|
141
141
|
setShowingQueryResult(false);
|
|
142
142
|
db.toggleSort(col);
|
|
143
143
|
}, [db.toggleSort]);
|
|
144
|
+
const handleClearSort = useCallback(() => {
|
|
145
|
+
setShowingQueryResult(false);
|
|
146
|
+
db.clearSort();
|
|
147
|
+
}, [db.clearSort]);
|
|
144
148
|
const handlePageChange = useCallback((p: number) => {
|
|
145
149
|
setShowingQueryResult(false);
|
|
146
150
|
db.setPage(p);
|
|
@@ -178,7 +182,8 @@ export function DatabaseViewer({ metadata }: Props) {
|
|
|
178
182
|
<div className="shrink-0 border-b border-border" style={{ height: queryHeight }}>
|
|
179
183
|
<SqlQueryEditor
|
|
180
184
|
onExecute={handleExecuteQuery} loading={db.queryLoading}
|
|
181
|
-
defaultValue={defaultQuery} schemaInfo={schemaInfo}
|
|
185
|
+
defaultValue={defaultQuery} schemaInfo={schemaInfo}
|
|
186
|
+
cacheKey={connectionId ? String(connectionId) : undefined} />
|
|
182
187
|
</div>
|
|
183
188
|
|
|
184
189
|
{/* Resize handle */}
|
|
@@ -189,10 +194,14 @@ export function DatabaseViewer({ metadata }: Props) {
|
|
|
189
194
|
|
|
190
195
|
{/* Bottom panel: table data OR query results */}
|
|
191
196
|
<div className="flex-1 overflow-hidden">
|
|
192
|
-
{showTableGrid && (
|
|
193
|
-
<
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
{showTableGrid && db.tableData && (
|
|
198
|
+
<GlideDataGrid
|
|
199
|
+
columns={db.tableData.columns} rows={db.tableData.rows}
|
|
200
|
+
total={db.tableData.total} limit={db.tableData.limit}
|
|
201
|
+
schema={db.schema} loading={db.loading}
|
|
202
|
+
page={db.page} onPageChange={handlePageChange}
|
|
203
|
+
onCellUpdate={db.updateCell} onRowDelete={db.deleteRow}
|
|
204
|
+
orderBy={db.orderBy} orderDir={db.orderDir} onToggleSort={handleToggleSort} onClearSort={handleClearSort}
|
|
196
205
|
onBulkDelete={db.bulkDelete} onInsertRow={db.insertRow}
|
|
197
206
|
connectionId={connectionId} selectedTable={db.selectedTable} selectedSchema={db.selectedSchema}
|
|
198
207
|
connectionName={connectionName} columnFilters={columnFilters} onColumnFilter={handleColumnFilter} />
|
|
@@ -244,8 +253,10 @@ function QueryResultPanel({ result, error, loading, schema, connectionName }: {
|
|
|
244
253
|
|
|
245
254
|
{queryTableData && (
|
|
246
255
|
<div className="flex-1 overflow-hidden">
|
|
247
|
-
<
|
|
248
|
-
|
|
256
|
+
<GlideDataGrid
|
|
257
|
+
columns={queryTableData.columns} rows={queryTableData.rows}
|
|
258
|
+
total={queryTableData.total} limit={queryTableData.limit}
|
|
259
|
+
schema={querySchema} loading={!!loading}
|
|
249
260
|
page={1} onPageChange={NOOP} onCellUpdate={NOOP}
|
|
250
261
|
orderBy={null} orderDir="ASC" onToggleSort={NOOP}
|
|
251
262
|
connectionName={connectionName}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { useState, useRef, useEffect } from "react";
|
|
1
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
2
3
|
import { Download } from "lucide-react";
|
|
3
4
|
import { serializeCsv } from "@/lib/csv-parser";
|
|
4
5
|
|
|
@@ -23,18 +24,22 @@ function downloadFile(name: string, content: string, mimeType: string) {
|
|
|
23
24
|
export function ExportButton({ columns, rows, filename = "export", exportAllUrl }: ExportButtonProps) {
|
|
24
25
|
const [open, setOpen] = useState(false);
|
|
25
26
|
const [exporting, setExporting] = useState(false);
|
|
26
|
-
const
|
|
27
|
+
const btnRef = useRef<HTMLButtonElement>(null);
|
|
28
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
27
29
|
|
|
28
30
|
// Close dropdown on outside click
|
|
29
31
|
useEffect(() => {
|
|
30
32
|
if (!open) return;
|
|
31
33
|
const handler = (e: MouseEvent) => {
|
|
32
|
-
if (
|
|
34
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node) &&
|
|
35
|
+
btnRef.current && !btnRef.current.contains(e.target as Node)) setOpen(false);
|
|
33
36
|
};
|
|
34
37
|
document.addEventListener("mousedown", handler);
|
|
35
38
|
return () => document.removeEventListener("mousedown", handler);
|
|
36
39
|
}, [open]);
|
|
37
40
|
|
|
41
|
+
const toggle = useCallback(() => setOpen((v) => !v), []);
|
|
42
|
+
|
|
38
43
|
const exportPageCsv = () => {
|
|
39
44
|
const csvRows = rows.map((r) => columns.map((c) => String(r[c] ?? "")));
|
|
40
45
|
const csv = serializeCsv(columns, csvRows);
|
|
@@ -48,6 +53,13 @@ export function ExportButton({ columns, rows, filename = "export", exportAllUrl
|
|
|
48
53
|
setOpen(false);
|
|
49
54
|
};
|
|
50
55
|
|
|
56
|
+
const copyToClipboard = async () => {
|
|
57
|
+
const header = columns.join("\t");
|
|
58
|
+
const body = rows.map((r) => columns.map((c) => String(r[c] ?? "")).join("\t")).join("\n");
|
|
59
|
+
await navigator.clipboard.writeText(header + "\n" + body);
|
|
60
|
+
setOpen(false);
|
|
61
|
+
};
|
|
62
|
+
|
|
51
63
|
const exportAll = async (format: "csv" | "json") => {
|
|
52
64
|
if (!exportAllUrl) return;
|
|
53
65
|
setExporting(true);
|
|
@@ -63,38 +75,46 @@ export function ExportButton({ columns, rows, filename = "export", exportAllUrl
|
|
|
63
75
|
|
|
64
76
|
if (columns.length === 0 || rows.length === 0) return null;
|
|
65
77
|
|
|
78
|
+
// Compute dropdown position from button
|
|
79
|
+
const rect = btnRef.current?.getBoundingClientRect();
|
|
80
|
+
const portal = document.getElementById("portal");
|
|
81
|
+
|
|
66
82
|
return (
|
|
67
|
-
|
|
68
|
-
<button
|
|
69
|
-
|
|
70
|
-
onClick={() => setOpen((v) => !v)}
|
|
71
|
-
className="p-1 rounded text-muted-foreground hover:text-foreground transition-colors"
|
|
72
|
-
title="Export"
|
|
73
|
-
>
|
|
83
|
+
<>
|
|
84
|
+
<button ref={btnRef} type="button" onClick={toggle}
|
|
85
|
+
className="p-1 rounded text-muted-foreground hover:text-foreground transition-colors" title="Export">
|
|
74
86
|
<Download className="size-3.5" />
|
|
75
87
|
</button>
|
|
76
88
|
|
|
77
|
-
{open && (
|
|
78
|
-
<div
|
|
79
|
-
|
|
89
|
+
{open && portal && rect && createPortal(
|
|
90
|
+
<div ref={dropdownRef}
|
|
91
|
+
style={{ position: "fixed", left: Math.min(rect.left, window.innerWidth - 170), top: rect.bottom + 4, zIndex: 10000 }}
|
|
92
|
+
className="bg-popover border border-border rounded-md shadow-md py-1 min-w-[160px] text-xs">
|
|
93
|
+
<button onClick={copyToClipboard} className="w-full text-left px-3 py-1.5 hover:bg-muted transition-colors text-foreground">
|
|
94
|
+
Copy to Clipboard (TSV)
|
|
95
|
+
</button>
|
|
96
|
+
<button onClick={exportPageCsv} className="w-full text-left px-3 py-1.5 hover:bg-muted transition-colors text-foreground">
|
|
80
97
|
Export Page (CSV)
|
|
81
98
|
</button>
|
|
82
|
-
<button onClick={exportPageJson} className="w-full text-left px-3 py-1.5 hover:bg-muted transition-colors">
|
|
99
|
+
<button onClick={exportPageJson} className="w-full text-left px-3 py-1.5 hover:bg-muted transition-colors text-foreground">
|
|
83
100
|
Export Page (JSON)
|
|
84
101
|
</button>
|
|
85
102
|
{exportAllUrl && (
|
|
86
103
|
<>
|
|
87
104
|
<div className="border-t border-border my-1" />
|
|
88
|
-
<button onClick={() => exportAll("csv")} disabled={exporting}
|
|
105
|
+
<button onClick={() => exportAll("csv")} disabled={exporting}
|
|
106
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted transition-colors disabled:opacity-50 text-foreground">
|
|
89
107
|
{exporting ? "Exporting…" : "Export All (CSV)"}
|
|
90
108
|
</button>
|
|
91
|
-
<button onClick={() => exportAll("json")} disabled={exporting}
|
|
109
|
+
<button onClick={() => exportAll("json")} disabled={exporting}
|
|
110
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted transition-colors disabled:opacity-50 text-foreground">
|
|
92
111
|
{exporting ? "Exporting…" : "Export All (JSON)"}
|
|
93
112
|
</button>
|
|
94
113
|
</>
|
|
95
114
|
)}
|
|
96
|
-
</div
|
|
115
|
+
</div>,
|
|
116
|
+
portal,
|
|
97
117
|
)}
|
|
98
|
-
|
|
118
|
+
</>
|
|
99
119
|
);
|
|
100
120
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useState, useEffect, useRef, useCallback } from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
3
|
+
|
|
4
|
+
interface ColumnSearchProps {
|
|
5
|
+
columns: string[];
|
|
6
|
+
onSelect: (colName: string) => void;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
anchorRect: { x: number; y: number };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Portal dropdown for searching and jumping to a column in the grid */
|
|
12
|
+
export function GlideColumnSearch({ columns, onSelect, onClose, anchorRect }: ColumnSearchProps) {
|
|
13
|
+
const [search, setSearch] = useState("");
|
|
14
|
+
const [activeIdx, setActiveIdx] = useState(0);
|
|
15
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
16
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
17
|
+
|
|
18
|
+
const filtered = search
|
|
19
|
+
? columns.filter((c) => c.toLowerCase().includes(search.toLowerCase()))
|
|
20
|
+
: columns;
|
|
21
|
+
|
|
22
|
+
// Reset active index when filter changes
|
|
23
|
+
useEffect(() => { setActiveIdx(0); }, [search]);
|
|
24
|
+
|
|
25
|
+
// Scroll active item into view
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const list = listRef.current;
|
|
28
|
+
if (!list) return;
|
|
29
|
+
const active = list.children[activeIdx] as HTMLElement | undefined;
|
|
30
|
+
active?.scrollIntoView({ block: "nearest" });
|
|
31
|
+
}, [activeIdx]);
|
|
32
|
+
|
|
33
|
+
// Close on outside click
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const handler = (e: MouseEvent) => {
|
|
36
|
+
if (ref.current && !ref.current.contains(e.target as Node)) onClose();
|
|
37
|
+
};
|
|
38
|
+
document.addEventListener("mousedown", handler);
|
|
39
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
40
|
+
}, [onClose]);
|
|
41
|
+
|
|
42
|
+
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
|
|
43
|
+
if (e.key === "Escape") { onClose(); return; }
|
|
44
|
+
if (e.key === "ArrowDown") { e.preventDefault(); setActiveIdx((i) => Math.min(i + 1, filtered.length - 1)); return; }
|
|
45
|
+
if (e.key === "ArrowUp") { e.preventDefault(); setActiveIdx((i) => Math.max(i - 1, 0)); return; }
|
|
46
|
+
if (e.key === "Enter") {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
const col = filtered[activeIdx];
|
|
49
|
+
if (col) { onSelect(col); onClose(); }
|
|
50
|
+
}
|
|
51
|
+
}, [filtered, activeIdx, onSelect, onClose]);
|
|
52
|
+
|
|
53
|
+
const portal = document.getElementById("portal");
|
|
54
|
+
if (!portal) return null;
|
|
55
|
+
|
|
56
|
+
return createPortal(
|
|
57
|
+
<div ref={ref} style={{ position: "fixed", left: Math.min(anchorRect.x, window.innerWidth - 216), top: Math.min(anchorRect.y, window.innerHeight - 308), zIndex: 10000 }}
|
|
58
|
+
className="w-[200px] max-h-[300px] bg-popover border border-border rounded-md shadow-lg text-xs overflow-hidden flex flex-col">
|
|
59
|
+
<div className="px-2 py-1.5 border-b border-border">
|
|
60
|
+
<input autoFocus value={search} onChange={(e) => setSearch(e.target.value)}
|
|
61
|
+
onKeyDown={handleKeyDown}
|
|
62
|
+
placeholder="Search columns…"
|
|
63
|
+
className="w-full bg-transparent outline-none text-foreground placeholder:text-muted-foreground text-xs" />
|
|
64
|
+
</div>
|
|
65
|
+
<div ref={listRef} className="overflow-y-auto py-1">
|
|
66
|
+
{filtered.map((col, i) => (
|
|
67
|
+
<button key={col} type="button"
|
|
68
|
+
onClick={() => { onSelect(col); onClose(); }}
|
|
69
|
+
onMouseEnter={() => setActiveIdx(i)}
|
|
70
|
+
className={`w-full text-left px-3 py-1 truncate text-foreground ${i === activeIdx ? "bg-muted" : "hover:bg-muted"}`}>
|
|
71
|
+
{col}
|
|
72
|
+
</button>
|
|
73
|
+
))}
|
|
74
|
+
{filtered.length === 0 && (
|
|
75
|
+
<div className="px-3 py-2 text-muted-foreground">No columns found</div>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
</div>,
|
|
79
|
+
portal,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
3
|
+
import { Eye, Pin, PinOff, Trash2, ExternalLink } from "lucide-react";
|
|
4
|
+
|
|
5
|
+
interface ContextMenuProps {
|
|
6
|
+
position: { x: number; y: number };
|
|
7
|
+
isPinned: boolean;
|
|
8
|
+
onViewRow: () => void;
|
|
9
|
+
onViewCell?: () => void;
|
|
10
|
+
onPinRow: () => void;
|
|
11
|
+
onDeleteRow: () => void;
|
|
12
|
+
/** FK navigation: open referenced table filtered by this cell's value */
|
|
13
|
+
onOpenFkTable?: () => void;
|
|
14
|
+
/** Label for FK menu item, e.g. "Open users.id" */
|
|
15
|
+
fkLabel?: string;
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Right-click / long-press context menu for grid rows.
|
|
21
|
+
* Rendered via portal. Includes View JSON, Pin/Unpin, Delete with confirm.
|
|
22
|
+
*/
|
|
23
|
+
export function GlideContextMenu({
|
|
24
|
+
position, isPinned, onViewRow, onViewCell, onPinRow, onDeleteRow, onOpenFkTable, fkLabel, onClose,
|
|
25
|
+
}: ContextMenuProps) {
|
|
26
|
+
const [confirmDelete, setConfirmDelete] = useState(false);
|
|
27
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
28
|
+
|
|
29
|
+
// Close on outside click
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const handler = (e: MouseEvent) => {
|
|
32
|
+
if (ref.current && !ref.current.contains(e.target as Node)) onClose();
|
|
33
|
+
};
|
|
34
|
+
document.addEventListener("mousedown", handler);
|
|
35
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
36
|
+
}, [onClose]);
|
|
37
|
+
|
|
38
|
+
// Close on Escape
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };
|
|
41
|
+
document.addEventListener("keydown", handler);
|
|
42
|
+
return () => document.removeEventListener("keydown", handler);
|
|
43
|
+
}, [onClose]);
|
|
44
|
+
|
|
45
|
+
// Clamp to viewport
|
|
46
|
+
const menuWidth = 180;
|
|
47
|
+
const menuHeight = 130;
|
|
48
|
+
const left = Math.min(position.x, window.innerWidth - menuWidth - 8);
|
|
49
|
+
const top = Math.min(position.y, window.innerHeight - menuHeight - 8);
|
|
50
|
+
|
|
51
|
+
const portal = document.getElementById("portal");
|
|
52
|
+
if (!portal) return null;
|
|
53
|
+
|
|
54
|
+
return createPortal(
|
|
55
|
+
<div ref={ref} style={{ position: "fixed", left, top, zIndex: 10000 }}
|
|
56
|
+
className="w-[180px] bg-popover border border-border rounded-md shadow-lg text-xs overflow-hidden py-1">
|
|
57
|
+
<button type="button" onClick={() => { onViewRow(); onClose(); }}
|
|
58
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted flex items-center gap-2 text-foreground">
|
|
59
|
+
<Eye className="size-3" /> View as JSON
|
|
60
|
+
</button>
|
|
61
|
+
{onViewCell && (
|
|
62
|
+
<button type="button" onClick={() => { onViewCell(); onClose(); }}
|
|
63
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted flex items-center gap-2 text-foreground">
|
|
64
|
+
<Eye className="size-3" /> View Cell
|
|
65
|
+
</button>
|
|
66
|
+
)}
|
|
67
|
+
{onOpenFkTable && (
|
|
68
|
+
<button type="button" onClick={() => { onOpenFkTable(); onClose(); }}
|
|
69
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted flex items-center gap-2 text-blue-400">
|
|
70
|
+
<ExternalLink className="size-3" /> {fkLabel ?? "Open Referenced Table"}
|
|
71
|
+
</button>
|
|
72
|
+
)}
|
|
73
|
+
<button type="button" onClick={() => { onPinRow(); onClose(); }}
|
|
74
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted flex items-center gap-2 text-foreground">
|
|
75
|
+
{isPinned ? <PinOff className="size-3" /> : <Pin className="size-3" />}
|
|
76
|
+
{isPinned ? "Unpin Row" : "Pin Row"}
|
|
77
|
+
</button>
|
|
78
|
+
<div className="border-t border-border my-0.5" />
|
|
79
|
+
{confirmDelete ? (
|
|
80
|
+
<div className="px-3 py-1.5 flex items-center gap-2">
|
|
81
|
+
<button type="button" onClick={() => { onDeleteRow(); onClose(); }}
|
|
82
|
+
className="text-destructive font-medium hover:underline">Delete?</button>
|
|
83
|
+
<button type="button" onClick={() => setConfirmDelete(false)}
|
|
84
|
+
className="text-muted-foreground hover:underline">Cancel</button>
|
|
85
|
+
</div>
|
|
86
|
+
) : (
|
|
87
|
+
<button type="button" onClick={() => setConfirmDelete(true)}
|
|
88
|
+
className="w-full text-left px-3 py-1.5 hover:bg-muted flex items-center gap-2 text-destructive">
|
|
89
|
+
<Trash2 className="size-3" /> Delete Row
|
|
90
|
+
</button>
|
|
91
|
+
)}
|
|
92
|
+
</div>,
|
|
93
|
+
portal,
|
|
94
|
+
);
|
|
95
|
+
}
|