@hienlh/ppm 0.13.9 → 0.13.11
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 +8 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/bun.lock +2135 -0
- package/bunfig.toml +2 -0
- 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-C1p-Q5XZ.js → audio-preview-dOvnFQN8.js} +1 -1
- package/dist/web/assets/chat-tab-C6NVtLx3.js +12 -0
- package/dist/web/assets/code-editor-3e9UAnzv.js +8 -0
- package/dist/web/assets/{conflict-editor-Dcn3HuLD.js → conflict-editor-XMpuwtUv.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-viewer-GNKYeCIc.js +1 -0
- package/dist/web/assets/{diff-viewer-NMLD4V8q.js → diff-viewer-DjFe6idy.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-DW2dBswj.js → extension-webview-hgbO93RZ.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BLXEKVf1.js +1 -0
- package/dist/web/assets/glide-data-grid-nthEL3fk.css +1 -0
- package/dist/web/assets/glide-data-grid-uLRTmkwH.js +136 -0
- package/dist/web/assets/{image-preview-Dqp1KSus.js → image-preview-CzwOU5op.js} +1 -1
- package/dist/web/assets/index-BAPR3hYQ.js +27 -0
- package/dist/web/assets/index-COOnLKGB.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-CEkPcChg.js +1 -0
- package/dist/web/assets/{input-DYWhyaze.js → input-ozrR2DAV.js} +1 -1
- package/dist/web/assets/keybindings-store-D9GV2h8K.js +1 -0
- package/dist/web/assets/{markdown-renderer-DNIXdY0d.js → markdown-renderer-BD5P19YN.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-ChC1gaaZ.js → pdf-preview-DRbBRYIF.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-cjpNfVG5.js +1 -0
- package/dist/web/assets/{port-forwarding-tab-dLhH_g2l.js → port-forwarding-tab-BSFhNv-A.js} +1 -1
- package/dist/web/assets/{postgres-viewer-De0pzd1C.js → postgres-viewer-D51L9fxD.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-DdbYEmAC.js +1 -0
- package/dist/web/assets/sql-query-editor-7pD60nKZ.js +3 -0
- package/dist/web/assets/sqlite-viewer-DLNJ_IGM.js +1 -0
- package/dist/web/assets/terminal-tab-6T5e8Nar.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-CHPVrMtx.js → video-preview-BwDNFl7v.js} +1 -1
- package/dist/web/assets/x-CG-_0yIW.js +1 -0
- package/dist/web/index.html +10 -11
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +0 -0
- package/src/web/components/chat/chat-tab.tsx +4 -1
- package/src/web/components/chat/message-input.tsx +28 -14
- 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-toolbar.tsx +105 -0
- package/src/web/components/database/glide-grid-types.ts +2 -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 +65 -30
- package/src/web/components/database/use-glide-columns.ts +24 -16
- 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/editor/code-editor.tsx +7 -5
- 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-chat.ts +27 -20
- package/src/web/hooks/use-global-keybindings.ts +12 -0
- package/src/web/hooks/use-terminal.ts +1 -1
- package/dist/web/assets/ai-settings-section-CLNBWLS4.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-WMbLpD5Y.js +0 -1
- package/dist/web/assets/chat-tab-BSJUkgxB.js +0 -12
- package/dist/web/assets/code-editor-rNw5_pXh.js +0 -8
- package/dist/web/assets/csv-parser-DO0dz4x_.js +0 -6
- package/dist/web/assets/data-grid-nZfSIop5.js +0 -5
- package/dist/web/assets/database-viewer-CNoq5Uxp.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BdPTuzO3.js +0 -1
- package/dist/web/assets/index-CoMWx5VS.js +0 -27
- package/dist/web/assets/index-Dzb3OtrX.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-MHX_1JfR.js +0 -1
- package/dist/web/assets/keybindings-store-B7nlHmDh.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/radar-KQ55EAFF-UxsdRHvt.js +0 -1
- package/dist/web/assets/settings-tab-Mrs9uzCZ.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-BqtIjvil.js +0 -1
- package/dist/web/assets/terminal-tab-CeHEtoE2.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-OGGXhtlb.js +0 -1
- /package/dist/web/assets/{arrow-up-Dtrfv490.js → arrow-up-Rcw6_KKu.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-BAPR3hYQ.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,29 +39,28 @@
|
|
|
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-BAPR3hYQ.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/refresh-cw-
|
|
57
|
-
<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">
|
|
58
57
|
<link rel="modulepreload" crossorigin href="/assets/api-settings-D0_eiIYv.js">
|
|
59
|
-
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-
|
|
58
|
+
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-ysK_Eixc.js">
|
|
60
59
|
<link rel="modulepreload" crossorigin href="/assets/database-DOWH9-Vv.js">
|
|
61
60
|
<link rel="modulepreload" crossorigin href="/assets/chevron-right-DnHIvvcy.js">
|
|
62
61
|
<link rel="modulepreload" crossorigin href="/assets/file-store-BrbCNyLm.js">
|
|
63
62
|
<link rel="modulepreload" crossorigin href="/assets/tab-store-0rGchMXr.js">
|
|
64
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
63
|
+
<link rel="stylesheet" crossorigin href="/assets/index-COOnLKGB.css">
|
|
65
64
|
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
66
65
|
<body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
|
|
67
66
|
<div id="portal" style="position: fixed; left: 0; top: 0; z-index: 9999;" /></div>
|
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":"b828c433c952d5869f7f8c6f4f241f09","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/diff-viewer-NMLD4V8q.js"},{"revision":null,"url":"assets/dist-D7KGU7Vl.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/audio-preview-C1p-Q5XZ.js"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/scroll-area-BEllam7_.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-BdPTuzO3.js"},{"revision":null,"url":"assets/terminal-tab-CeHEtoE2.js"},{"revision":null,"url":"assets/chat-tab-BSJUkgxB.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-CnaHXUh8.js"},{"revision":null,"url":"assets/port-forwarding-tab-dLhH_g2l.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/settings-tab-Mrs9uzCZ.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/database-DOWH9-Vv.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/info-3K5VOQVL-MHX_1JfR.js"},{"revision":null,"url":"assets/lib-D_kRA9p6.js"},{"revision":null,"url":"assets/dist-CGvx1c8C.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/api-settings-D0_eiIYv.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/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/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/index-Dzb3OtrX.css"},{"revision":null,"url":"assets/code-editor-rNw5_pXh.js"},{"revision":null,"url":"assets/sql-query-editor-CMQpaOjA.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/image-preview-Dqp1KSus.js"},{"revision":null,"url":"assets/data-grid-nZfSIop5.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/arrow-up-Dtrfv490.js"},{"revision":null,"url":"assets/refresh-cw-CSFrDtiu.js"},{"revision":null,"url":"assets/postgres-viewer-De0pzd1C.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/esm-nXReYVnB.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/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/extension-webview-DW2dBswj.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/pdf-preview-ChC1gaaZ.js"},{"revision":null,"url":"assets/utils-CTg5uAYR.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/conflict-editor-Dcn3HuLD.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/database-viewer-CNoq5Uxp.js"},{"revision":null,"url":"assets/ai-settings-section-CLNBWLS4.js"},{"revision":null,"url":"assets/csv-parser-DO0dz4x_.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/input-DYWhyaze.js"},{"revision":null,"url":"assets/chevron-right-DnHIvvcy.js"},{"revision":null,"url":"assets/video-preview-CHPVrMtx.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/markdown-renderer-DNIXdY0d.js"},{"revision":null,"url":"assets/index-CoMWx5VS.js"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/x-OGGXhtlb.js"},{"revision":null,"url":"assets/sparkles-B0mRBy_j.js"},{"revision":null,"url":"assets/vendor-ui-B-89Uj8i.js"},{"revision":null,"url":"assets/vendor-xterm-u3AZMvTx.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-CreFbf9A.js"},{"revision":null,"url":"assets/keybindings-store-B7nlHmDh.js"},{"revision":null,"url":"assets/sql-completion-provider-tCzZfqWs.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/sqlite-viewer-BqtIjvil.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":"6f6ecec6b82555c721c9eb1c2c52446a","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/audio-preview-dOvnFQN8.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/image-preview-CzwOU5op.js"},{"revision":null,"url":"assets/diff-viewer-DjFe6idy.js"},{"revision":null,"url":"assets/index-BAPR3hYQ.js"},{"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/database-viewer-GNKYeCIc.js"},{"revision":null,"url":"assets/conflict-editor-XMpuwtUv.js"},{"revision":null,"url":"assets/react-GqWghJ-L.js"},{"revision":null,"url":"assets/file-exclamation-point-Baz81y5z.js"},{"revision":null,"url":"assets/video-preview-BwDNFl7v.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/database-DOWH9-Vv.js"},{"revision":null,"url":"assets/katex-BuytEdO1.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/chat-tab-C6NVtLx3.js"},{"revision":null,"url":"assets/sql-query-editor-7pD60nKZ.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-cjpNfVG5.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/glide-data-grid-uLRTmkwH.js"},{"revision":null,"url":"assets/ai-settings-section-ysK_Eixc.js"},{"revision":null,"url":"assets/markdown-renderer-BD5P19YN.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/csv-preview-7TsYBQI6.js"},{"revision":null,"url":"assets/tab-store-0rGchMXr.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/terminal-tab-6T5e8Nar.js"},{"revision":null,"url":"assets/code-editor-3e9UAnzv.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/x-CG-_0yIW.js"},{"revision":null,"url":"assets/csv-parser-Dly5nqE1.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/extension-webview-hgbO93RZ.js"},{"revision":null,"url":"assets/data-grid-types-BTQHYBUh.js"},{"revision":null,"url":"assets/sqlite-viewer-DLNJ_IGM.js"},{"revision":null,"url":"assets/dist-DGSkE2Ml.js"},{"revision":null,"url":"assets/keybindings-store-D9GV2h8K.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/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/postgres-viewer-D51L9fxD.js"},{"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/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/settings-tab-DdbYEmAC.js"},{"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/pdf-preview-DRbBRYIF.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/port-forwarding-tab-BSFhNv-A.js"},{"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/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/lib-DQHnkzGy.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
package/src/index.ts
CHANGED
|
File without changes
|
|
@@ -288,6 +288,9 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
288
288
|
setSlashFilter("");
|
|
289
289
|
}, []);
|
|
290
290
|
|
|
291
|
+
// Stable callback: clear external paths once consumed (avoids inline lambda breaking MessageInput memo)
|
|
292
|
+
const handleExternalPathsConsumed = useCallback(() => setExternalPaths(null), []);
|
|
293
|
+
|
|
291
294
|
// --- Disambiguation picker handler (OS drag resolve with multiple matches) ---
|
|
292
295
|
const handleDisambiguate = useCallback((matches: FileNode[]) => {
|
|
293
296
|
setDisambiguateItems(matches);
|
|
@@ -470,7 +473,7 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
470
473
|
fileSelected={fileSelected}
|
|
471
474
|
externalFiles={externalFiles}
|
|
472
475
|
externalPaths={externalPaths}
|
|
473
|
-
onExternalPathsConsumed={
|
|
476
|
+
onExternalPathsConsumed={handleExternalPathsConsumed}
|
|
474
477
|
onDisambiguate={handleDisambiguate}
|
|
475
478
|
permissionMode={permissionMode}
|
|
476
479
|
onModeChange={setPermissionMode}
|
|
@@ -107,9 +107,9 @@ export const MessageInput = memo(function MessageInput({
|
|
|
107
107
|
typeof CSS === "undefined" || !CSS.supports("field-sizing", "content"),
|
|
108
108
|
);
|
|
109
109
|
|
|
110
|
-
// File index
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
// File index: subscribe imperatively to avoid re-renders on every file store update.
|
|
111
|
+
// The component only needs fileIndex for the effect below (populating fileItemsRef),
|
|
112
|
+
// not for rendering — so we use Zustand's subscribe() instead of selector hooks.
|
|
113
113
|
|
|
114
114
|
/** Write value to both textareas + ref + update hasText state */
|
|
115
115
|
const writeTextareas = useCallback((newValue: string) => {
|
|
@@ -208,18 +208,32 @@ export const MessageInput = memo(function MessageInput({
|
|
|
208
208
|
return () => window.removeEventListener("ppm:slash-items-refresh", handler);
|
|
209
209
|
}, [fetchSlashItems]);
|
|
210
210
|
|
|
211
|
-
// Sync file picker items from store index —
|
|
211
|
+
// Sync file picker items from store index — subscribe imperatively to avoid re-renders.
|
|
212
|
+
// Reads fileIndex on mount + whenever fileIndex/indexStatus changes in the store.
|
|
212
213
|
useEffect(() => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
214
|
+
const syncFromStore = () => {
|
|
215
|
+
if (!projectName) {
|
|
216
|
+
fileItemsRef.current = [];
|
|
217
|
+
onFileItemsLoaded?.([]);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const { fileIndex } = useFileStore.getState();
|
|
221
|
+
const nodes: FileNode[] = fileIndex.map((e) => ({ name: e.name, path: e.path, type: e.type }));
|
|
222
|
+
fileItemsRef.current = nodes;
|
|
223
|
+
onFileItemsLoaded?.(nodes);
|
|
224
|
+
};
|
|
225
|
+
syncFromStore();
|
|
226
|
+
// Track previous values to only sync on relevant changes
|
|
227
|
+
let prevIdx = useFileStore.getState().fileIndex;
|
|
228
|
+
let prevStatus = useFileStore.getState().indexStatus;
|
|
229
|
+
return useFileStore.subscribe((state) => {
|
|
230
|
+
if (state.fileIndex !== prevIdx || state.indexStatus !== prevStatus) {
|
|
231
|
+
prevIdx = state.fileIndex;
|
|
232
|
+
prevStatus = state.indexStatus;
|
|
233
|
+
syncFromStore();
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}, [projectName]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
223
237
|
|
|
224
238
|
// Handle parent selecting a slash item
|
|
225
239
|
useEffect(() => {
|
|
@@ -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
|
+
}
|