@hienlh/ppm 0.11.5 → 0.11.6
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/dist/web/assets/{chat-tab-CWc9ZYVY.js → chat-tab-2znvnxzD.js} +3 -3
- package/dist/web/assets/code-editor-CUyFYiwJ.js +8 -0
- package/dist/web/assets/{conflict-editor-BmuhLalI.js → conflict-editor-DXnqiS4c.js} +1 -1
- package/dist/web/assets/{database-viewer-CqW0fH7Q.js → database-viewer-DK4PfwVJ.js} +1 -1
- package/dist/web/assets/{diff-viewer-ium8zJhL.js → diff-viewer-Cy4oX3mb.js} +1 -1
- package/dist/web/assets/{extension-webview-AxcQX8ML.js → extension-webview-DIVrmdfu.js} +1 -1
- package/dist/web/assets/{index-CyciQ-Gz.js → index-oqP6ldWs.js} +3 -3
- package/dist/web/assets/{markdown-renderer-Ckjp96ej.js → markdown-renderer-BLhcNL42.js} +1 -1
- package/dist/web/assets/{port-forwarding-tab-DR5Bngg2.js → port-forwarding-tab-iZost0RL.js} +1 -1
- package/dist/web/assets/{postgres-viewer-hy2EksiB.js → postgres-viewer-CabnbH06.js} +1 -1
- package/dist/web/assets/{settings-tab-D5SXI74b.js → settings-tab-D2th4Hfj.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-DDPZjt-X.js → sqlite-viewer-cGe2bGlF.js} +1 -1
- package/dist/web/assets/{terminal-tab-DSWdc4AO.js → terminal-tab-CPAMJoNK.js} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/server/ws/chat.ts +10 -0
- package/src/services/file-watcher.service.ts +72 -0
- package/src/web/components/editor/code-editor.tsx +23 -0
- package/src/web/components/explorer/file-tree.tsx +16 -5
- package/src/web/hooks/use-chat.ts +6 -0
- package/dist/web/assets/code-editor-CSej2S2J.js +0 -8
|
@@ -240,6 +240,29 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
240
240
|
return () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current); };
|
|
241
241
|
}, [filePath, projectName, isImage, isPdf, isExternalFile, isUntitled]);
|
|
242
242
|
|
|
243
|
+
// Real-time reload: listen for file:changed WS events, re-fetch if editor is clean
|
|
244
|
+
const unsavedRef = useRef(unsaved);
|
|
245
|
+
unsavedRef.current = unsaved;
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
if (!filePath || !projectName || inlineContent != null || isUntitled) return;
|
|
248
|
+
const handler = (e: Event) => {
|
|
249
|
+
const detail = (e as CustomEvent).detail;
|
|
250
|
+
if (detail.projectName !== projectName || detail.path !== filePath) return;
|
|
251
|
+
if (unsavedRef.current) return; // don't overwrite unsaved changes
|
|
252
|
+
const readUrl = isExternalFile
|
|
253
|
+
? `/api/fs/read?path=${encodeURIComponent(filePath)}`
|
|
254
|
+
: `${projectUrl(projectName)}/files/read?path=${encodeURIComponent(filePath)}`;
|
|
255
|
+
api.get<{ content: string; encoding?: string }>(readUrl).then((data) => {
|
|
256
|
+
if (data.content === latestContentRef.current) return; // skip if unchanged (e.g. self-save)
|
|
257
|
+
setContent(data.content);
|
|
258
|
+
latestContentRef.current = data.content;
|
|
259
|
+
if (data.encoding) setEncoding(data.encoding);
|
|
260
|
+
}).catch(() => {});
|
|
261
|
+
};
|
|
262
|
+
window.addEventListener("file:changed", handler);
|
|
263
|
+
return () => window.removeEventListener("file:changed", handler);
|
|
264
|
+
}, [filePath, projectName, isExternalFile, inlineContent, isUntitled]);
|
|
265
|
+
|
|
243
266
|
// Update tab title unsaved indicator
|
|
244
267
|
useEffect(() => {
|
|
245
268
|
if (!ownTab) return;
|
|
@@ -277,12 +277,23 @@ export function FileTree({ onFileOpen }: FileTreeProps = {}) {
|
|
|
277
277
|
}
|
|
278
278
|
}, [activeProject?.name]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
279
279
|
|
|
280
|
-
// Auto-refresh file tree
|
|
281
|
-
// TODO: Replace with fs.watch + WebSocket push for real-time sync without needing window focus
|
|
280
|
+
// Auto-refresh file tree on window focus and real-time file changes via WebSocket
|
|
282
281
|
useEffect(() => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
if (!activeProject) return;
|
|
283
|
+
const refresh = () => fetchTree(activeProject.name);
|
|
284
|
+
let debounceTimer: ReturnType<typeof setTimeout>;
|
|
285
|
+
const debouncedRefresh = () => { clearTimeout(debounceTimer); debounceTimer = setTimeout(refresh, 300); };
|
|
286
|
+
const handleFileChanged = (e: Event) => {
|
|
287
|
+
const detail = (e as CustomEvent).detail;
|
|
288
|
+
if (detail.projectName === activeProject.name) debouncedRefresh();
|
|
289
|
+
};
|
|
290
|
+
window.addEventListener("focus", refresh);
|
|
291
|
+
window.addEventListener("file:changed", handleFileChanged);
|
|
292
|
+
return () => {
|
|
293
|
+
clearTimeout(debounceTimer);
|
|
294
|
+
window.removeEventListener("focus", refresh);
|
|
295
|
+
window.removeEventListener("file:changed", handleFileChanged);
|
|
296
|
+
};
|
|
286
297
|
}, [activeProject, fetchTree]);
|
|
287
298
|
|
|
288
299
|
const uploadFiles = useCallback(async (targetDir: string, files: FileList) => {
|
|
@@ -415,6 +415,12 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
415
415
|
// Ignore keepalive pings
|
|
416
416
|
if ((data as any).type === "ping") return;
|
|
417
417
|
|
|
418
|
+
// Dispatch file change events for real-time editor reload
|
|
419
|
+
if ((data as any).type === "file:changed") {
|
|
420
|
+
window.dispatchEvent(new CustomEvent("file:changed", { detail: data }));
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
418
424
|
// Dispatch global Jira events so components can listen via window events
|
|
419
425
|
if (typeof (data as any).type === "string" && (data as any).type.startsWith("jira:")) {
|
|
420
426
|
window.dispatchEvent(new CustomEvent((data as any).type, { detail: data }));
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/markdown-renderer-Ckjp96ej.js","assets/rolldown-runtime-FhOqtrmT.js","assets/index-CyciQ-Gz.js","assets/vendor-mermaid-CylkVm4U.js","assets/vendor-ui-B-T_damt.js","assets/vendor-markdown-0Mxgxy0L.js","assets/input-CHRMley8.js","assets/utils-ChWX7pZv.js","assets/createLucideIcon-BjHrJDVb.js","assets/x-DlFGzN8d.js","assets/scroll-area-DwWF9FpN.js","assets/ai-settings-section-D2vqiydT.js","assets/dist-C5IgeqrV.js","assets/plus-51UQ45rf.js","assets/refresh-cw-CSFrDtiu.js","assets/trash-2-BgDIBl6f.js","assets/api-client-C3tXCh0r.js","assets/api-settings-2eTz4SgY.js","assets/chevron-right-BzAdxJRG.js","assets/database-D4DIhgi-.js","assets/react-BkWDCPD7.js","assets/extension-store-CkyOvGbF.js","assets/keybindings-store-CpP5_miA.js","assets/tab-store-Jvy1eZGM.js","assets/project-store-CczGNZyf.js","assets/settings-store-CuYjM0FF.js","assets/index-iZHWllzQ.css","assets/csv-preview-D37K2LRd.js","assets/lib-BqkcKGFq.js","assets/arrow-up-Dtrfv490.js","assets/csv-parser-BAa56Nnn.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{o as e}from"./rolldown-runtime-FhOqtrmT.js";import{b as t,x as n}from"./vendor-markdown-0Mxgxy0L.js";import"./vendor-ui-B-T_damt.js";import{t as r}from"./createLucideIcon-BjHrJDVb.js";import"./scroll-area-DwWF9FpN.js";import{t as i}from"./chevron-right-BzAdxJRG.js";import{a,l as o,n as s,o as c,r as l,s as u,t as d}from"./input-CHRMley8.js";import{t as f}from"./code-CuravVys.js";import{t as ee}from"./database-D4DIhgi-.js";import{n as p,r as m}from"./x-DlFGzN8d.js";import{t as h}from"./table-DbSviOmw.js";import{t as g}from"./text-wrap-DzvCTq_i.js";import{i as _,r as v,t as y}from"./api-client-C3tXCh0r.js";import{G as b}from"./vendor-mermaid-CylkVm4U.js";import{n as te}from"./settings-store-CuYjM0FF.js";import{t as x}from"./utils-ChWX7pZv.js";import{n as ne,t as re}from"./tab-store-Jvy1eZGM.js";import{n as ie}from"./project-store-CczGNZyf.js";import{B as S,E as ae,F as C,I as w,L as T,M as E,P as D,R as O,a as oe,c as se,d as k,f as A,g as j,h as M,l as N,m as P,o as F,p as ce,u as le,y as I,z as ue}from"./index-CyciQ-Gz.js";import{n as de,t as fe}from"./use-monaco-theme-kjiAwvOp.js";import{n as pe,t as me}from"./sql-completion-provider-D3acAhav.js";var he=r(`file-exclamation-point`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),L=e(n(),1),R=t(),ge={ts:O,tsx:O,js:O,jsx:O,py:O,rs:O,go:O,html:O,css:O,scss:O,json:ue,md:T,txt:T,yaml:w,yml:w};function z(e,t){return t?D:ge[e.split(`.`).pop()?.toLowerCase()??``]??C}function _e(e,t){let n=[],r=e;for(let e=0;e<t.length;e++){let i=t[e],a=t.slice(0,e+1).join(`/`),o=r.find(e=>e.name===i);if(n.push({name:i,fullPath:a,node:o??null,siblings:r}),o?.children)r=o.children;else{for(let r=e+1;r<t.length;r++)n.push({name:t[r],fullPath:t.slice(0,r+1).join(`/`),node:null,siblings:[]});break}}return n}function B(e){return[...e].sort((e,t)=>e.type===t.type?e.name.localeCompare(t.name):e.type===`directory`?-1:1)}function ve({filePath:e,projectName:t,tabId:n,className:r}){let a=I(e=>e.tree),{updateTab:o,openTab:s}=re(M(e=>({updateTab:e.updateTab,openTab:e.openTab}))),c=(0,L.useRef)(null),l=(0,L.useMemo)(()=>_e(a,e.split(`/`).filter(Boolean)),[a,e]);(0,L.useEffect)(()=>{c.current&&(c.current.scrollLeft=c.current.scrollWidth)},[l]);function u(e,r){let i=x(e);r.metaKey||r.ctrlKey?s({type:`editor`,title:i,metadata:{filePath:e,projectName:t},projectId:t,closable:!0}):o(n,{title:i,metadata:{filePath:e,projectName:t}})}return(0,R.jsx)(`div`,{ref:c,className:r,children:l.map((e,n)=>(0,R.jsxs)(`div`,{className:`flex items-center shrink-0`,children:[n>0&&(0,R.jsx)(i,{className:`size-3 text-muted-foreground shrink-0 mx-0.5`}),e.siblings.length>0?(0,R.jsx)(V,{segment:e,isLast:n===l.length-1,projectName:t,onFileClick:u}):(0,R.jsx)(`span`,{className:`text-xs text-muted-foreground px-1 py-0.5`,children:e.name})]},e.fullPath))})}function V({segment:e,isLast:t,projectName:n,onFileClick:r}){let i=(0,L.useMemo)(()=>B(e.siblings),[e.siblings]);return(0,R.jsxs)(se,{children:[(0,R.jsx)(P,{asChild:!0,children:(0,R.jsx)(`button`,{type:`button`,className:`text-xs px-1 py-0.5 rounded hover:bg-muted transition-colors truncate max-w-[120px] ${t?`text-foreground font-medium`:`text-muted-foreground`}`,children:e.name})}),(0,R.jsx)(N,{align:`start`,className:`max-h-[300px] p-1`,children:i.map(t=>(0,R.jsx)(H,{node:t,projectName:n,activePath:e.fullPath,onFileClick:r},t.path))})]})}function H({node:e,projectName:t,activePath:n,onFileClick:r}){let i=z(e.name,e.type===`directory`),a=e.path===n;return e.type===`directory`&&e.children&&e.children.length>0?(0,R.jsxs)(k,{children:[(0,R.jsxs)(ce,{className:`text-xs gap-1.5 ${a?`bg-muted`:``}`,children:[(0,R.jsx)(i,{className:`size-3.5 shrink-0 text-muted-foreground`}),(0,R.jsx)(`span`,{className:`truncate`,children:e.name})]}),(0,R.jsx)(A,{className:`max-h-[300px] overflow-y-auto p-1`,children:B(e.children).map(e=>(0,R.jsx)(H,{node:e,projectName:t,activePath:n,onFileClick:r},e.path))})]}):(0,R.jsxs)(le,{className:`text-xs gap-1.5 cursor-pointer ${a?`bg-muted`:``}`,onSelect:e=>{},onClick:t=>{e.type!==`directory`&&r(e.path,t)},children:[(0,R.jsx)(i,{className:`size-3.5 shrink-0 text-muted-foreground`}),(0,R.jsx)(`span`,{className:`truncate`,children:e.name})]})}function U({active:e,onClick:t,icon:n,label:r}){return(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1 px-2 py-1 rounded text-xs transition-colors ${e?`bg-muted text-foreground`:`text-muted-foreground hover:text-foreground`}`,children:[(0,R.jsx)(n,{className:`size-3`}),(0,R.jsx)(`span`,{className:`hidden sm:inline`,children:r})]})}function ye({ext:e,mdMode:t,onMdModeChange:n,csvMode:r,onCsvModeChange:i,wordWrap:a,onToggleWordWrap:o,filePath:s,projectName:c,className:l}){return(0,R.jsxs)(`div`,{className:l,children:[(e===`md`||e===`mdx`)&&n&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(U,{active:t===`edit`,onClick:()=>n(`edit`),icon:f,label:`Edit`}),(0,R.jsx)(U,{active:t===`preview`,onClick:()=>n(`preview`),icon:p,label:`Preview`})]}),e===`csv`&&i&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(U,{active:r===`table`,onClick:()=>i(`table`),icon:h,label:`Table`}),(0,R.jsx)(U,{active:r===`raw`,onClick:()=>i(`raw`),icon:f,label:`Raw`})]}),(0,R.jsx)(U,{active:a,onClick:o,icon:g,label:`Wrap`}),s&&c&&(0,R.jsx)(U,{active:!1,onClick:()=>j(c,s),icon:m,label:`Download`})]})}function be({open:e,defaultName:t,content:n,onSave:r,onCancel:i}){let[f,ee]=(0,L.useState)(t),[p,m]=(0,L.useState)(!1),[h,g]=(0,L.useState)(``),_=ie(e=>e.activeProject),v=(0,L.useCallback)(()=>{let e=f.trim();if(!e){g(`Filename cannot be empty`);return}if(/[/\\]/.test(e)){g(`Filename cannot contain / or \\`);return}g(``),m(!0)},[f]),y=(0,L.useCallback)(e=>{let t=e.includes(`\\`)?`\\`:`/`;r(e.endsWith(t)?`${e}${f.trim()}`:`${e}${t}${f.trim()}`,n)},[f,n,r]);return p?(0,R.jsx)(F,{open:!0,mode:`folder`,root:_?.path,title:`Save "${f.trim()}" to...`,onSelect:y,onCancel:()=>m(!1)}):(0,R.jsx)(s,{open:e,onOpenChange:e=>{e||i()},children:(0,R.jsxs)(l,{className:`sm:max-w-md`,children:[(0,R.jsx)(c,{children:(0,R.jsx)(u,{children:`Save As`})}),(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 py-2`,children:[(0,R.jsx)(`label`,{className:`text-sm text-muted-foreground`,children:`Filename`}),(0,R.jsx)(d,{value:f,onChange:e=>{ee(e.target.value),g(``)},onKeyDown:e=>{e.key===`Enter`&&v()},placeholder:`e.g. my-file.ts`,autoFocus:!0}),h&&(0,R.jsx)(`p`,{className:`text-xs text-destructive`,children:h})]}),(0,R.jsxs)(a,{children:[(0,R.jsx)(o,{variant:`outline`,onClick:i,children:`Cancel`}),(0,R.jsx)(o,{onClick:v,children:`Choose Folder...`})]})]})})}var xe=(0,L.lazy)(()=>b(()=>import(`./markdown-renderer-Ckjp96ej.js`).then(e=>({default:e.MarkdownRenderer})),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]))),Se=(0,L.lazy)(()=>b(()=>import(`./csv-preview-D37K2LRd.js`).then(e=>({default:e.CsvPreview})),__vite__mapDeps([27,1,4,5,28,8,29,30]))),Ce=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`ico`]),we=new Set([`db`,`sqlite`,`sqlite3`]);function Te(e){return e.split(`.`).pop()?.toLowerCase()??``}function Ee(e){return{js:`javascript`,jsx:`javascript`,ts:`typescript`,tsx:`typescript`,py:`python`,html:`html`,css:`css`,scss:`scss`,json:`json`,md:`markdown`,mdx:`markdown`,yaml:`yaml`,yml:`yaml`,sh:`shell`,bash:`shell`,sql:`sql`}[Te(e)]??`plaintext`}var W=(0,L.memo)(function({metadata:e,tabId:t}){let n=e?.filePath,r=e?.projectName,i=e?.inlineContent,a=e?.inlineLanguage,[o,s]=(0,L.useState)(i??null),[c,l]=(0,L.useState)(`utf-8`),[u,d]=(0,L.useState)(!0),[f,p]=(0,L.useState)(null),[m,h]=(0,L.useState)(!1),g=(0,L.useRef)(null),v=(0,L.useRef)(``),b=(0,L.useRef)(null),{tabs:ie,updateTab:S}=re(M(e=>({tabs:e.tabs,updateTab:e.updateTab}))),{wordWrap:C,toggleWordWrap:w}=te(M(e=>({wordWrap:e.wordWrap,toggleWordWrap:e.toggleWordWrap}))),T=fe(),D=e?.isUntitled===!0,O=e?.unsavedContent,[se,k]=(0,L.useState)(!1),A=ie.find(e=>e.id===t),j=n?Te(n):``,N=Ce.has(j),P=j===`pdf`,F=we.has(j),ce=j===`md`||j===`mdx`,le=j===`csv`,I=j===`sql`,[ue,ge]=(0,L.useState)(`preview`),[z,_e]=(0,L.useState)(`table`),{connections:B,cachedTables:V,refreshTables:H}=oe(),[U,xe]=(0,L.useState)(()=>{if(!I||!n)return null;let e=localStorage.getItem(`ppm:sql-conn:${n}`);return e?Number(e):null}),W=(0,L.useRef)(null),G=(0,L.useRef)(null),K=(0,L.useMemo)(()=>B.find(e=>e.id===U)??null,[B,U]),Ae=i!=null&&(a===`json`||a===`xml`),[q,J]=(0,L.useState)(!1),je=(0,L.useCallback)(()=>{if(i)if(q)s(i),J(!1);else{let e=i.trimStart();if(a===`json`)try{s(JSON.stringify(JSON.parse(e),null,2)),J(!0)}catch{}else if(a===`xml`){let t=0;s(e.replace(/(>)(<)(\/*)/g,`$1
|
|
3
|
-
$2$3`).split(`
|
|
4
|
-
`).map(e=>{let n=e.trim();n.startsWith(`</`)&&(t=Math.max(0,t-1));let r=` `.repeat(t)+n;return n.startsWith(`<`)&&!n.startsWith(`</`)&&!n.endsWith(`/>`)&&!n.includes(`</`)&&t++,r}).join(`
|
|
5
|
-
`)),J(!0)}}},[i,a,q]),Me=(0,L.useCallback)(e=>{xe(e),n&&localStorage.setItem(`ppm:sql-conn:${n}`,String(e)),H(e).catch(()=>{})},[n,H]),Y=(0,L.useMemo)(()=>{if(!I||!U)return;let e=(V.get(U)??[]).map(e=>({name:e.tableName,schema:e.schemaName}));if(e.length!==0)return{tables:e,getColumns:async(e,t)=>y.get(`/api/db/connections/${U}/schema?table=${encodeURIComponent(e)}${t?`&schema=${encodeURIComponent(t)}`:``}`)}},[I,U,V]);(0,L.useEffect)(()=>{if(!(!W.current||!Y))return G.current?.dispose(),me(),G.current=W.current.languages.registerCompletionItemProvider(`sql`,pe(W.current,Y)),()=>{G.current?.dispose()}},[Y]);let Ne=re(e=>e.openTab),X=(0,L.useCallback)(e=>{K&&Ne({type:`database`,title:`${K.name} · Query`,projectId:null,closable:!0,metadata:{connectionId:K.id,connectionName:K.name,dbType:K.type,initialSql:e}})},[K,Ne]),Pe=(0,L.useCallback)(()=>{if(!b.current||!K)return;let e=b.current,t=e.getSelection();X(t&&!t.isEmpty()?e.getModel()?.getValueInRange(t)??e.getValue():e.getValue())},[K,X]),Z=(0,L.useRef)([]),Fe=(0,L.useRef)(X);Fe.current=X,(0,L.useEffect)(()=>()=>{Z.current.forEach(e=>e.dispose()),Z.current=[]},[]),(0,L.useEffect)(()=>{F&&t&&S(t,{type:`sqlite`})},[F,t,S]);let Q=n?/^(\/|[A-Za-z]:[/\\])/.test(n):!1;(0,L.useEffect)(()=>{if(i!=null){d(!1);return}if(D){s(O??``),v.current=O??``,d(!1),O&&h(!0);return}if(!n||!Q&&!r)return;if(N||P){d(!1);return}d(!0),p(null);let e=Q?`/api/fs/read?path=${encodeURIComponent(n)}`:`${_(r)}/files/read?path=${encodeURIComponent(n)}`;return y.get(e).then(e=>{s(e.content),e.encoding&&l(e.encoding),v.current=e.content,d(!1)}).catch(e=>{p(e instanceof Error?e.message:`Failed to load file`),d(!1)}),()=>{g.current&&clearTimeout(g.current)}},[n,r,N,P,Q,D]),(0,L.useEffect)(()=>{if(!A)return;let t=D?`Untitled-${e?.untitledNumber??1}`:n?x(n):`Untitled`,r=m?`${t} \u25CF`:t;A.title!==r&&S(A.id,{title:r})},[m]);let Ie=(0,L.useCallback)(async e=>{if(n&&!(!Q&&!r))try{Q?await y.put(`/api/fs/write`,{path:n,content:e}):await y.put(`${_(r)}/files/write`,{path:n,content:e}),h(!1)}catch{}},[n,r,Q]);function Le(n){let r=n??``;s(r),v.current=r,h(!0),g.current&&clearTimeout(g.current),D?g.current=setTimeout(()=>{t&&S(t,{metadata:{...e,unsavedContent:v.current}})},2e3):g.current=setTimeout(()=>Ie(v.current),1e3)}let Re=(0,L.useCallback)(async(e,n)=>{try{if(g.current&&clearTimeout(g.current),await y.put(`/api/fs/write`,{path:e,content:n}),t){let{closeTab:n,openTab:r}=ne.getState();n(t),r({type:`editor`,title:x(e),projectId:null,metadata:{filePath:e},closable:!0})}h(!1),k(!1)}catch{}},[t]),$=e?.lineNumber,ze=(0,L.useCallback)((e,t)=>{if(b.current=e,W.current=t,$&&$>0&&setTimeout(()=>{e.revealLineInCenter($),e.setPosition({lineNumber:$,column:1}),e.focus()},100),D&&e.addCommand(t.KeyMod.CtrlCmd|t.KeyCode.KeyS,()=>k(!0)),e.addCommand(t.KeyMod.Alt|t.KeyCode.KeyZ,()=>te.getState().toggleWordWrap()),t.languages.typescript.typescriptDefaults.setDiagnosticsOptions({noSemanticValidation:!0,noSyntaxValidation:!0,noSuggestionDiagnostics:!0}),t.languages.typescript.javascriptDefaults.setDiagnosticsOptions({noSemanticValidation:!0,noSyntaxValidation:!0,noSuggestionDiagnostics:!0}),Y&&(G.current?.dispose(),G.current=t.languages.registerCompletionItemProvider(`sql`,pe(t,Y))),I){Z.current.forEach(e=>e.dispose()),Z.current=[];let n=e.getModel(),r=e.addCommand(0,(e,t)=>{t&&Fe.current(t)});if(r&&n){let e=t.languages.registerCodeLensProvider(`sql`,{provideCodeLenses:e=>{if(e!==n)return{lenses:[],dispose:()=>{}};let t=[],i=e.getValue().split(`
|
|
6
|
-
`),a=-1,o=[],s=!1,c=(e,n)=>{let i=n.trim();!i||i.startsWith(`--`)||t.push({range:{startLineNumber:e,startColumn:1,endLineNumber:e,endColumn:1},command:{id:r,title:`▷ Run`,arguments:[i]}})};for(let e=0;e<i.length;e++){let t=i[e].trim();if(a===-1){if(!t||t.startsWith(`--`))continue;a=e+1,o=[]}o.push(i[e]),(t.match(/\$\$/g)||[]).length%2==1&&(s=!s),!s&&t.endsWith(`;`)&&(c(a,o.join(`
|
|
7
|
-
`)),a=-1,o=[])}return a>0&&o.join(``).trim()&&c(a,o.join(`
|
|
8
|
-
`)),{lenses:t,dispose:()=>{}}}});Z.current.push(e)}}},[Y]);if(!i&&!D&&(!n||!Q&&!r))return(0,R.jsx)(`div`,{className:`flex items-center justify-center h-full text-text-secondary text-sm`,children:`No file selected.`});if(u)return(0,R.jsxs)(`div`,{className:`flex items-center justify-center h-full gap-2 text-text-secondary`,children:[(0,R.jsx)(E,{className:`size-5 animate-spin`}),(0,R.jsx)(`span`,{className:`text-sm`,children:`Loading file...`})]});if(f)return(0,R.jsx)(`div`,{className:`flex items-center justify-center h-full text-error text-sm`,children:f});if(N)return(0,R.jsx)(Oe,{filePath:n,projectName:r});if(P)return(0,R.jsx)(ke,{filePath:n,projectName:r});if(c===`base64`)return(0,R.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,R.jsx)(he,{className:`size-10 text-text-subtle`}),(0,R.jsx)(`p`,{className:`text-sm`,children:`This file is a binary format and cannot be displayed.`}),(0,R.jsx)(`p`,{className:`text-xs text-text-subtle`,children:n})]});let Be=I?(0,R.jsxs)(`div`,{className:`shrink-0 flex items-center gap-1 px-2 border-l border-border`,children:[(0,R.jsx)(ee,{className:`size-3 text-muted-foreground`}),(0,R.jsxs)(`select`,{value:U??``,onChange:e=>{let t=Number(e.target.value);t&&Me(t)},className:`h-5 text-[10px] bg-transparent border border-border rounded px-1 text-foreground outline-none max-w-[140px]`,title:`Select connection for autocomplete`,children:[(0,R.jsx)(`option`,{value:``,children:`Connection…`}),B.map(e=>(0,R.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,R.jsx)(`button`,{type:`button`,onClick:Pe,disabled:!K,className:`p-0.5 rounded text-muted-foreground hover:text-primary disabled:opacity-30 transition-colors`,title:`Run all in DB Viewer`,children:(0,R.jsx)(ae,{className:`size-3.5`})})]}):null;return(0,R.jsxs)(`div`,{className:`flex flex-col h-full w-full overflow-hidden`,children:[i!=null&&Ae&&(0,R.jsx)(`div`,{className:`flex items-center h-7 border-b border-border bg-background shrink-0 px-2 gap-2`,children:(0,R.jsx)(`button`,{type:`button`,onClick:je,className:`text-[10px] px-2 py-0.5 rounded border border-border hover:bg-muted transition-colors text-foreground`,children:q?`Raw`:`Beautify`})}),n&&r&&t&&(0,R.jsxs)(`div`,{className:`hidden md:flex items-center h-7 border-b border-border bg-background shrink-0`,children:[(0,R.jsx)(ve,{filePath:n,projectName:r,tabId:t,className:`flex items-center flex-1 min-w-0 overflow-x-auto scrollbar-none px-2 gap-0.5`}),Be,(0,R.jsx)(ye,{ext:j,mdMode:ue,onMdModeChange:ge,csvMode:z,onCsvModeChange:_e,wordWrap:C,onToggleWordWrap:w,filePath:n,projectName:r,className:`shrink-0 flex items-center gap-1 px-2`})]}),I&&(!r||!t)&&(0,R.jsxs)(`div`,{className:`hidden md:flex items-center h-7 border-b border-border bg-background shrink-0 px-2`,children:[(0,R.jsx)(`span`,{className:`text-xs text-muted-foreground truncate flex-1`,children:n?x(n):`SQL`}),Be]}),le&&z===`table`?(0,R.jsx)(L.Suspense,{fallback:(0,R.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,R.jsx)(E,{className:`size-5 animate-spin text-text-subtle`})}),children:(0,R.jsx)(Se,{content:o??``,onContentChange:Le,wordWrap:C})}):ce&&ue===`preview`?(0,R.jsx)(De,{content:o??``}):(0,R.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,R.jsx)(de,{height:`100%`,language:a??Ee(n??``),value:o??``,onChange:i==null?Le:void 0,onMount:ze,theme:T,options:{fontSize:13,fontFamily:`Menlo, Monaco, Consolas, monospace`,wordWrap:C?`on`:`off`,minimap:{enabled:!1},scrollBeyondLastLine:!1,automaticLayout:!0,lineNumbers:`on`,folding:!0,bracketPairColorization:{enabled:!0},readOnly:i!=null},loading:(0,R.jsx)(E,{className:`size-5 animate-spin text-text-subtle`})})}),se&&(0,R.jsx)(be,{open:se,defaultName:`Untitled-${e?.untitledNumber??1}`,content:v.current,onSave:Re,onCancel:()=>k(!1)})]})});function De({content:e}){return(0,R.jsx)(L.Suspense,{fallback:(0,R.jsx)(`div`,{className:`animate-pulse h-4 bg-muted rounded m-4`}),children:(0,R.jsx)(xe,{content:e,className:`flex-1 overflow-auto p-4`})})}function Oe({filePath:e,projectName:t}){let[n,r]=(0,L.useState)(null),[i,a]=(0,L.useState)(!1);return(0,L.useEffect)(()=>{let n,i=`${_(t)}/files/raw?path=${encodeURIComponent(e)}`,o=v();return fetch(i,{headers:o?{Authorization:`Bearer ${o}`}:{}}).then(e=>{if(!e.ok)throw Error(`Failed`);return e.blob()}).then(e=>{let t=URL.createObjectURL(e);n=t,r(t)}).catch(()=>a(!0)),()=>{n&&URL.revokeObjectURL(n)}},[e,t]),i?(0,R.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,R.jsx)(he,{className:`size-10 text-text-subtle`}),(0,R.jsx)(`p`,{className:`text-sm`,children:`Failed to load image.`})]}):n?(0,R.jsx)(`div`,{className:`flex items-center justify-center h-full p-4 bg-surface overflow-auto`,children:(0,R.jsx)(`img`,{src:n,alt:e,className:`max-w-full max-h-full object-contain`})}):(0,R.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,R.jsx)(E,{className:`size-5 animate-spin text-text-subtle`})})}function ke({filePath:e,projectName:t}){let[n,r]=(0,L.useState)(null),[i,a]=(0,L.useState)(!1);(0,L.useEffect)(()=>{let n,i=`${_(t)}/files/raw?path=${encodeURIComponent(e)}`,o=v();return fetch(i,{headers:o?{Authorization:`Bearer ${o}`}:{}}).then(e=>{if(!e.ok)throw Error(`Failed`);return e.blob()}).then(e=>{let t=URL.createObjectURL(new Blob([e],{type:`application/pdf`}));n=t,r(t)}).catch(()=>a(!0)),()=>{n&&URL.revokeObjectURL(n)}},[e,t]);let o=(0,L.useCallback)(()=>{n&&window.open(n,`_blank`)},[n]);return i?(0,R.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,R.jsx)(he,{className:`size-10 text-text-subtle`}),(0,R.jsx)(`p`,{className:`text-sm`,children:`Failed to load PDF.`})]}):n?(0,R.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-1.5 border-b border-border bg-background shrink-0`,children:[(0,R.jsx)(`span`,{className:`text-xs text-text-secondary truncate`,children:e}),(0,R.jsxs)(`button`,{onClick:o,className:`flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary transition-colors`,children:[(0,R.jsx)(S,{className:`size-3`}),` Open in new tab`]})]}),(0,R.jsx)(`iframe`,{src:n,title:e,className:`flex-1 w-full border-none`})]}):(0,R.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,R.jsx)(E,{className:`size-5 animate-spin text-text-subtle`})})}export{W as CodeEditor};
|