@hienlh/ppm 0.13.56 → 0.13.58

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +1 -1
  4. package/bun.lock +2129 -0
  5. package/bunfig.toml +2 -0
  6. package/dist/web/assets/{audio-preview-LCxWo-25.js → audio-preview-DEiWicib.js} +1 -1
  7. package/dist/web/assets/{chat-tab-3GUmdAJN.js → chat-tab-cTNzjeke.js} +3 -3
  8. package/dist/web/assets/{code-editor-Cd7NZ0VX.js → code-editor-DfI-ziOx.js} +2 -2
  9. package/dist/web/assets/{conflict-editor-No7IVPRN.js → conflict-editor-D3O6LScu.js} +1 -1
  10. package/dist/web/assets/{database-viewer-zeQXxkg-.js → database-viewer--56cGHzb.js} +1 -1
  11. package/dist/web/assets/{diff-viewer-DmSkyBaT.js → diff-viewer-DcodJCRl.js} +1 -1
  12. package/dist/web/assets/{extension-webview-DCwz2Wso.js → extension-webview-D4B6-SMy.js} +1 -1
  13. package/dist/web/assets/{git-log-panel-Bk7Eh-Bn.js → git-log-panel-DNzozRgD.js} +1 -1
  14. package/dist/web/assets/{glide-data-grid-ha8hjunf.js → glide-data-grid-DNkYYw65.js} +1 -1
  15. package/dist/web/assets/{image-preview-C1VLHLdJ.js → image-preview-Z_2ryPZN.js} +1 -1
  16. package/dist/web/assets/{index-CP6EIXkh.js → index-BD-x9C-z.js} +3 -3
  17. package/dist/web/assets/keybindings-store-CtCmu4r4.js +1 -0
  18. package/dist/web/assets/{markdown-renderer-C7ZoGWso.js → markdown-renderer-CyYPNwWJ.js} +1 -1
  19. package/dist/web/assets/notification-store-g7oIcSzX.js +1 -0
  20. package/dist/web/assets/pdf-preview-DP53VE-6.js +1 -0
  21. package/dist/web/assets/{port-forwarding-tab-BMb8neu0.js → port-forwarding-tab-Do8vqJWR.js} +1 -1
  22. package/dist/web/assets/{postgres-viewer-DkM6ndux.js → postgres-viewer-Caj1bdFn.js} +1 -1
  23. package/dist/web/assets/{settings-tab-WdL5pYxG.js → settings-tab-Dd85LS_2.js} +1 -1
  24. package/dist/web/assets/{sql-query-editor-CNwOnFgF.js → sql-query-editor-KIv3CAg8.js} +1 -1
  25. package/dist/web/assets/{sqlite-viewer-FFlsRPWf.js → sqlite-viewer-CoeXNWfR.js} +1 -1
  26. package/dist/web/assets/{system-monitor-tab-CefzxLVi.js → system-monitor-tab-Dax2F-1U.js} +1 -1
  27. package/dist/web/assets/{terminal-tab-C4MNU5S3.js → terminal-tab-DVeEspLf.js} +1 -1
  28. package/dist/web/assets/use-blob-url-DCUIEzjB.js +1 -0
  29. package/dist/web/assets/{video-preview-izCy3xj7.js → video-preview-T9iHZknc.js} +1 -1
  30. package/dist/web/index.html +1 -1
  31. package/dist/web/sw.js +1 -1
  32. package/package.json +1 -1
  33. package/packages/ext-git-graph/src/webview-html.ts +17 -11
  34. package/src/index.ts +0 -0
  35. package/src/web/components/editor/pdf-preview.tsx +27 -3
  36. package/src/web/components/editor/use-blob-url.ts +18 -9
  37. package/dist/web/assets/keybindings-store-Rf9YKWAp.js +0 -1
  38. package/dist/web/assets/notification-store-C3tg-ZXm.js +0 -1
  39. package/dist/web/assets/pdf-preview-BdmR2RsT.js +0 -1
  40. package/dist/web/assets/use-blob-url-CI2h4qu0.js +0 -1
@@ -1,12 +1,36 @@
1
- import { useCallback } from "react";
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { Loader2, FileWarning, ExternalLink } from "lucide-react";
3
3
  import { useBlobUrl } from "./use-blob-url";
4
4
 
5
5
  export function PdfPreview({ filePath, projectName }: { filePath: string; projectName: string }) {
6
- const { blobUrl, error } = useBlobUrl(filePath, projectName, "application/pdf");
6
+ const [refreshKey, setRefreshKey] = useState(0);
7
+ const iframeRef = useRef<HTMLIFrameElement>(null);
8
+ const pageHashRef = useRef("");
9
+
10
+ const { blobUrl, error } = useBlobUrl(filePath, projectName, "application/pdf", refreshKey);
11
+
12
+ // Auto-reload: listen for file:changed WS events
13
+ useEffect(() => {
14
+ const handler = (e: Event) => {
15
+ const detail = (e as CustomEvent).detail;
16
+ if (detail.projectName !== projectName || detail.path !== filePath) return;
17
+ // Save current page hash before re-fetch (Chrome PDF viewer uses #page=N&zoom=...)
18
+ try {
19
+ pageHashRef.current = iframeRef.current?.contentWindow?.location.hash || "";
20
+ } catch { /* cross-origin */ }
21
+ setRefreshKey((k) => k + 1);
22
+ };
23
+ window.addEventListener("file:changed", handler);
24
+ return () => window.removeEventListener("file:changed", handler);
25
+ }, [filePath, projectName]);
7
26
 
8
27
  const openInNewTab = useCallback(() => { if (blobUrl) window.open(blobUrl, "_blank"); }, [blobUrl]);
9
28
 
29
+ // Append saved page hash to blob URL so PDF viewer restores position
30
+ const iframeSrc = blobUrl
31
+ ? `${blobUrl}${pageHashRef.current}`
32
+ : undefined;
33
+
10
34
  if (error) {
11
35
  return (
12
36
  <div className="flex flex-col items-center justify-center h-full gap-3 text-text-secondary">
@@ -26,7 +50,7 @@ export function PdfPreview({ filePath, projectName }: { filePath: string; projec
26
50
  <ExternalLink className="size-3" /> Open in new tab
27
51
  </button>
28
52
  </div>
29
- <iframe src={blobUrl} title={filePath} className="flex-1 w-full border-none" />
53
+ <iframe ref={iframeRef} src={iframeSrc} title={filePath} className="flex-1 w-full border-none" />
30
54
  </div>
31
55
  );
32
56
  }
@@ -1,18 +1,21 @@
1
- import { useEffect, useState } from "react";
1
+ import { useEffect, useRef, useState } from "react";
2
2
  import { projectUrl, getAuthToken } from "@/lib/api-client";
3
3
 
4
4
  /** Shared hook: fetch a project file as a blob URL via /files/raw endpoint.
5
- * Detects absolute paths (external files) and uses /api/fs/raw instead. */
5
+ * Detects absolute paths (external files) and uses /api/fs/raw instead.
6
+ * Pass a changing `refreshKey` to re-fetch without unmounting. */
6
7
  export function useBlobUrl(
7
8
  filePath: string,
8
9
  projectName: string,
9
10
  mimeOverride?: string,
11
+ refreshKey = 0,
10
12
  ) {
11
13
  const [blobUrl, setBlobUrl] = useState<string | null>(null);
12
14
  const [error, setError] = useState(false);
15
+ const urlRef = useRef<string | null>(null);
13
16
 
14
17
  useEffect(() => {
15
- let revoke: string | undefined;
18
+ let cancelled = false;
16
19
  const isExternal = /^(\/|[A-Za-z]:[/\\])/.test(filePath);
17
20
  const url = isExternal
18
21
  ? `/api/fs/raw?path=${encodeURIComponent(filePath)}`
@@ -24,16 +27,22 @@ export function useBlobUrl(
24
27
  return r.blob();
25
28
  })
26
29
  .then((blob) => {
30
+ if (cancelled) return;
27
31
  const final = mimeOverride ? new Blob([blob], { type: mimeOverride }) : blob;
28
32
  const u = URL.createObjectURL(final);
29
- revoke = u;
33
+ // Revoke old URL only after new one is ready (avoids blank flash)
34
+ if (urlRef.current) URL.revokeObjectURL(urlRef.current);
35
+ urlRef.current = u;
30
36
  setBlobUrl(u);
31
37
  })
32
- .catch(() => setError(true));
33
- return () => {
34
- if (revoke) URL.revokeObjectURL(revoke);
35
- };
36
- }, [filePath, projectName, mimeOverride]);
38
+ .catch(() => { if (!cancelled) setError(true); });
39
+ return () => { cancelled = true; };
40
+ }, [filePath, projectName, mimeOverride, refreshKey]);
41
+
42
+ // Revoke on unmount
43
+ useEffect(() => () => {
44
+ if (urlRef.current) URL.revokeObjectURL(urlRef.current);
45
+ }, []);
37
46
 
38
47
  return { blobUrl, error };
39
48
  }
@@ -1 +0,0 @@
1
- import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-DiZgVOok.js";import{D as e}from"./index-CP6EIXkh.js";export{e as useKeybindingsStore};
@@ -1 +0,0 @@
1
- import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-DiZgVOok.js";import{P as e}from"./index-CP6EIXkh.js";export{e as useNotificationStore};
@@ -1 +0,0 @@
1
- import{o as e}from"./rolldown-runtime-FhOqtrmT.js";import{b as t,x as n}from"./vendor-markdown-0Mxgxy0L.js";import{t as r}from"./file-exclamation-point-B__2Hrd6.js";import"./api-client-DiZgVOok.js";import{$ as i,ct as a}from"./index-CP6EIXkh.js";import{t as o}from"./use-blob-url-CI2h4qu0.js";var s=e(n(),1),c=t();function l({filePath:e,projectName:t}){let{blobUrl:n,error:l}=o(e,t,`application/pdf`),u=(0,s.useCallback)(()=>{n&&window.open(n,`_blank`)},[n]);return l?(0,c.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,c.jsx)(r,{className:`size-10 text-text-subtle`}),(0,c.jsx)(`p`,{className:`text-sm`,children:`Failed to load PDF.`})]}):n?(0,c.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,c.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-1.5 border-b border-border bg-background shrink-0`,children:[(0,c.jsx)(`span`,{className:`text-xs text-text-secondary truncate`,children:e}),(0,c.jsxs)(`button`,{onClick:u,className:`flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary transition-colors`,children:[(0,c.jsx)(a,{className:`size-3`}),` Open in new tab`]})]}),(0,c.jsx)(`iframe`,{src:n,title:e,className:`flex-1 w-full border-none`})]}):(0,c.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,c.jsx)(i,{className:`size-5 animate-spin text-text-subtle`})})}export{l as PdfPreview};
@@ -1 +0,0 @@
1
- import{o as e}from"./rolldown-runtime-FhOqtrmT.js";import{x as t}from"./vendor-markdown-0Mxgxy0L.js";import{i as n,r}from"./api-client-DiZgVOok.js";var i=e(t(),1);function a(e,t,a){let[o,s]=(0,i.useState)(null),[c,l]=(0,i.useState)(!1);return(0,i.useEffect)(()=>{let i,o=/^(\/|[A-Za-z]:[/\\])/.test(e)?`/api/fs/raw?path=${encodeURIComponent(e)}`:`${n(t)}/files/raw?path=${encodeURIComponent(e)}`,c=r();return fetch(o,{headers:c?{Authorization:`Bearer ${c}`}:{}}).then(e=>{if(!e.ok)throw Error(`Failed`);return e.blob()}).then(e=>{let t=a?new Blob([e],{type:a}):e,n=URL.createObjectURL(t);i=n,s(n)}).catch(()=>l(!0)),()=>{i&&URL.revokeObjectURL(i)}},[e,t,a]),{blobUrl:o,error:c}}export{a as t};