@hienlh/ppm 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/web/assets/{chat-tab-C24nbKz1.js → chat-tab-CjKO_uYf.js} +1 -1
- package/dist/web/assets/code-editor-CCvD-8SS.js +1 -0
- package/dist/web/assets/{diff-viewer-BnvcXY3g.js → diff-viewer-D_bM4Kmw.js} +1 -1
- package/dist/web/assets/{git-graph-iAf_zaqe.js → git-graph-zmdDLInW.js} +1 -1
- package/dist/web/assets/{index-BwLVvoev.js → index-l7z-nYoz.js} +3 -3
- package/dist/web/assets/{markdown-renderer-CIfiE3o8.js → markdown-renderer-BKfKwtec.js} +1 -1
- package/dist/web/assets/{settings-tab-B_QwULcp.js → settings-tab-CP5UZGRD.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-DpGb3i2g.js → sqlite-viewer-C1MIuoOX.js} +2 -2
- package/dist/web/assets/{terminal-tab-4-DINw_B.js → terminal-tab-CmdZtyZW.js} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/services/sqlite.service.ts +5 -4
- package/src/web/components/editor/code-editor.tsx +8 -0
- package/src/web/components/sqlite/sqlite-data-grid.tsx +1 -0
- package/src/web/components/sqlite/use-sqlite.ts +1 -1
- package/dist/web/assets/code-editor-DjIL6ta3.js +0 -1
package/package.json
CHANGED
|
@@ -34,10 +34,11 @@ interface CachedDb {
|
|
|
34
34
|
class SqliteService {
|
|
35
35
|
private cache = new Map<string, CachedDb>();
|
|
36
36
|
|
|
37
|
-
/** Resolve
|
|
37
|
+
/** Resolve db path — supports both project-relative and absolute paths */
|
|
38
38
|
private resolvePath(projectPath: string, dbRelPath: string): string {
|
|
39
|
-
const
|
|
40
|
-
|
|
39
|
+
const isAbsolute = /^(\/|[A-Za-z]:[/\\])/.test(dbRelPath);
|
|
40
|
+
const abs = isAbsolute ? dbRelPath : resolve(projectPath, dbRelPath);
|
|
41
|
+
if (!isAbsolute && !abs.startsWith(projectPath)) throw new Error("Access denied: path outside project");
|
|
41
42
|
if (!existsSync(abs)) throw new Error(`Database not found: ${dbRelPath}`);
|
|
42
43
|
return abs;
|
|
43
44
|
}
|
|
@@ -117,7 +118,7 @@ class SqliteService {
|
|
|
117
118
|
if (isSelect) {
|
|
118
119
|
const stmt = db.query(sql);
|
|
119
120
|
const rows = stmt.all() as Record<string, unknown>[];
|
|
120
|
-
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
121
|
+
const columns = rows.length > 0 ? Object.keys(rows[0]!) : [];
|
|
121
122
|
return { columns, rows, rowsAffected: 0, changeType: "select" };
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -11,6 +11,8 @@ import { Loader2, FileWarning, ExternalLink, Code, Eye, WrapText } from "lucide-
|
|
|
11
11
|
|
|
12
12
|
/** Image extensions renderable inline */
|
|
13
13
|
const IMAGE_EXTS = new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "ico"]);
|
|
14
|
+
/** SQLite extensions — redirect to sqlite viewer */
|
|
15
|
+
const SQLITE_EXTS = new Set(["db", "sqlite", "sqlite3"]);
|
|
14
16
|
|
|
15
17
|
function getFileExt(filename: string): string {
|
|
16
18
|
return filename.split(".").pop()?.toLowerCase() ?? "";
|
|
@@ -54,9 +56,15 @@ export function CodeEditor({ metadata, tabId }: CodeEditorProps) {
|
|
|
54
56
|
const ext = filePath ? getFileExt(filePath) : "";
|
|
55
57
|
const isImage = IMAGE_EXTS.has(ext);
|
|
56
58
|
const isPdf = ext === "pdf";
|
|
59
|
+
const isSqlite = SQLITE_EXTS.has(ext);
|
|
57
60
|
const isMarkdown = ext === "md" || ext === "mdx";
|
|
58
61
|
const [mdMode, setMdMode] = useState<"edit" | "preview">("preview");
|
|
59
62
|
|
|
63
|
+
// Redirect .db files to sqlite viewer by changing tab type
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (isSqlite && tabId) updateTab(tabId, { type: "sqlite" });
|
|
66
|
+
}, [isSqlite, tabId, updateTab]);
|
|
67
|
+
|
|
60
68
|
// Detect external (absolute) file path — not relative to project
|
|
61
69
|
const isExternalFile = filePath ? /^(\/|[A-Za-z]:[/\\])/.test(filePath) : false;
|
|
62
70
|
|
|
@@ -73,6 +73,7 @@ function DataTable({ columns, rows, schema, onCellUpdate }: {
|
|
|
73
73
|
const commitEdit = useCallback(() => {
|
|
74
74
|
if (!editingCell) return;
|
|
75
75
|
const row = rows[editingCell.rowIdx];
|
|
76
|
+
if (!row) return;
|
|
76
77
|
const rowid = row.rowid as number;
|
|
77
78
|
const oldVal = row[editingCell.col];
|
|
78
79
|
if (String(oldVal ?? "") !== editValue) {
|
|
@@ -28,7 +28,7 @@ export function useSqlite(projectName: string, dbPath: string) {
|
|
|
28
28
|
try {
|
|
29
29
|
const data = await api.get<TableInfo[]>(`${base}/tables?${qs}`);
|
|
30
30
|
setTables(data);
|
|
31
|
-
if (data.length > 0 && !selectedTable) setSelectedTable(data[0]
|
|
31
|
+
if (data.length > 0 && !selectedTable) setSelectedTable(data[0]!.name);
|
|
32
32
|
} catch (e) {
|
|
33
33
|
setError((e as Error).message);
|
|
34
34
|
} finally {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e,o as t,r as n,t as r}from"./jsx-runtime-B4BJKQ1u.js";import{a as i,t as a}from"./tab-store-L0a7ao4c.js";import{n as o}from"./settings-store-BGF8--S9.js";import{t as s}from"./utils-C2KxHr1H.js";import{i as c,r as l,t as u}from"./api-client-ANLU-Irq.js";import{T as d}from"./index-BwLVvoev.js";import{t as f}from"./markdown-renderer-CIfiE3o8.js";import{n as p,t as m}from"./use-monaco-theme-RFoGvnp0.js";var h=e(`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`}]]),g=t(n(),1),_=r(),v=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`ico`]);function y(e){return e.split(`.`).pop()?.toLowerCase()??``}function b(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`}[y(e)]??`plaintext`}function x({metadata:e,tabId:t}){let n=e?.filePath,r=e?.projectName,[i,l]=(0,g.useState)(null),[f,x]=(0,g.useState)(`utf-8`),[T,E]=(0,g.useState)(!0),[D,O]=(0,g.useState)(null),[k,A]=(0,g.useState)(!1),j=(0,g.useRef)(null),M=(0,g.useRef)(``),N=(0,g.useRef)(null),{tabs:P,updateTab:F}=a(),{wordWrap:I,toggleWordWrap:L}=o(),R=m(),z=P.find(e=>e.id===t),B=n?y(n):``,V=v.has(B),H=B===`pdf`,U=B===`md`||B===`mdx`,[W,G]=(0,g.useState)(`preview`),K=n?/^(\/|[A-Za-z]:[/\\])/.test(n):!1;(0,g.useEffect)(()=>{if(!n||!K&&!r)return;if(V||H){E(!1);return}E(!0),O(null);let e=K?`/api/fs/read?path=${encodeURIComponent(n)}`:`${c(r)}/files/read?path=${encodeURIComponent(n)}`;return u.get(e).then(e=>{l(e.content),e.encoding&&x(e.encoding),M.current=e.content,E(!1)}).catch(e=>{O(e instanceof Error?e.message:`Failed to load file`),E(!1)}),()=>{j.current&&clearTimeout(j.current)}},[n,r,V,H,K]),(0,g.useEffect)(()=>{if(!z)return;let e=n?s(n):`Untitled`,t=k?`${e} \u25CF`:e;z.title!==t&&F(z.id,{title:t})},[k]);let q=(0,g.useCallback)(async e=>{if(n&&!(!K&&!r))try{K?await u.put(`/api/fs/write`,{path:n,content:e}):await u.put(`${c(r)}/files/write`,{path:n,content:e}),A(!1)}catch{}},[n,r,K]);function J(e){let t=e??``;l(t),M.current=t,A(!0),j.current&&clearTimeout(j.current),j.current=setTimeout(()=>q(M.current),1e3)}let Y=(0,g.useCallback)((e,t)=>{N.current=e,e.addCommand(t.KeyMod.Alt|t.KeyCode.KeyZ,()=>o.getState().toggleWordWrap()),t.languages.typescript.typescriptDefaults.setDiagnosticsOptions({noSemanticValidation:!0,noSyntaxValidation:!0,noSuggestionDiagnostics:!0}),t.languages.typescript.javascriptDefaults.setDiagnosticsOptions({noSemanticValidation:!0,noSyntaxValidation:!0,noSuggestionDiagnostics:!0})},[]);return!n||!K&&!r?(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full text-text-secondary text-sm`,children:`No file selected.`}):T?(0,_.jsxs)(`div`,{className:`flex items-center justify-center h-full gap-2 text-text-secondary`,children:[(0,_.jsx)(d,{className:`size-5 animate-spin`}),(0,_.jsx)(`span`,{className:`text-sm`,children:`Loading file...`})]}):D?(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full text-error text-sm`,children:D}):V?(0,_.jsx)(C,{filePath:n,projectName:r}):H?(0,_.jsx)(w,{filePath:n,projectName:r}):f===`base64`?(0,_.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,_.jsx)(h,{className:`size-10 text-text-subtle`}),(0,_.jsx)(`p`,{className:`text-sm`,children:`This file is a binary format and cannot be displayed.`}),(0,_.jsx)(`p`,{className:`text-xs text-text-subtle`,children:n})]}):(0,_.jsx)(`div`,{className:`flex flex-col h-full w-full overflow-hidden`,children:U&&W===`preview`?(0,_.jsx)(S,{content:i??``}):(0,_.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,_.jsx)(p,{height:`100%`,language:b(n),value:i??``,onChange:J,onMount:Y,theme:R,options:{fontSize:13,fontFamily:`Menlo, Monaco, Consolas, monospace`,wordWrap:I?`on`:`off`,minimap:{enabled:!1},scrollBeyondLastLine:!1,automaticLayout:!0,lineNumbers:`on`,folding:!0,bracketPairColorization:{enabled:!0}},loading:(0,_.jsx)(d,{className:`size-5 animate-spin text-text-subtle`})})})})}function S({content:e}){return(0,_.jsx)(f,{content:e,className:`flex-1 overflow-auto p-4`})}function C({filePath:e,projectName:t}){let[n,r]=(0,g.useState)(null),[i,a]=(0,g.useState)(!1);return(0,g.useEffect)(()=>{let n,i=`${c(t)}/files/raw?path=${encodeURIComponent(e)}`,o=l();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,_.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,_.jsx)(h,{className:`size-10 text-text-subtle`}),(0,_.jsx)(`p`,{className:`text-sm`,children:`Failed to load image.`})]}):n?(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full p-4 bg-surface overflow-auto`,children:(0,_.jsx)(`img`,{src:n,alt:e,className:`max-w-full max-h-full object-contain`})}):(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,_.jsx)(d,{className:`size-5 animate-spin text-text-subtle`})})}function w({filePath:e,projectName:t}){let[n,r]=(0,g.useState)(null),[a,o]=(0,g.useState)(!1);(0,g.useEffect)(()=>{let n,i=`${c(t)}/files/raw?path=${encodeURIComponent(e)}`,a=l();return fetch(i,{headers:a?{Authorization:`Bearer ${a}`}:{}}).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(()=>o(!0)),()=>{n&&URL.revokeObjectURL(n)}},[e,t]);let s=(0,g.useCallback)(()=>{n&&window.open(n,`_blank`)},[n]);return a?(0,_.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,_.jsx)(h,{className:`size-10 text-text-subtle`}),(0,_.jsx)(`p`,{className:`text-sm`,children:`Failed to load PDF.`})]}):n?(0,_.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-1.5 border-b border-border bg-background shrink-0`,children:[(0,_.jsx)(`span`,{className:`text-xs text-text-secondary truncate`,children:e}),(0,_.jsxs)(`button`,{onClick:s,className:`flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary transition-colors`,children:[(0,_.jsx)(i,{className:`size-3`}),` Open in new tab`]})]}),(0,_.jsx)(`iframe`,{src:n,title:e,className:`flex-1 w-full border-none`})]}):(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,_.jsx)(d,{className:`size-5 animate-spin text-text-subtle`})})}export{x as CodeEditor};
|