@hienlh/ppm 0.18.4 → 0.18.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +1 -1
  4. package/dist/web/assets/{ai-resource-editor-Bb-NNlp1.js → ai-resource-editor-C59ti0ED.js} +1 -1
  5. package/dist/web/assets/{audio-preview-DG2Tw0cO.js → audio-preview-GGksv6U8.js} +1 -1
  6. package/dist/web/assets/chat-tab-CM5hUNpk.js +15 -0
  7. package/dist/web/assets/code-editor-2yL9lCL1.js +10 -0
  8. package/dist/web/assets/{conflict-editor-B6hVffX3.js → conflict-editor-H1zmUXSQ.js} +1 -1
  9. package/dist/web/assets/{csv-preview-hL4Z9HS5.js → csv-preview-Dzzyx_Gv.js} +1 -1
  10. package/dist/web/assets/{database-viewer-CTK5kMaA.js → database-viewer-CiVA--mM.js} +1 -1
  11. package/dist/web/assets/{diff-viewer-DZxnANY4.js → diff-viewer-69nl3mqO.js} +1 -1
  12. package/dist/web/assets/{docx-preview-CrAc7Qjv.js → docx-preview-CFvopEBf.js} +1 -1
  13. package/dist/web/assets/explorer-body-DyPXovdU.js +2 -0
  14. package/dist/web/assets/{explorer-window-content-NS8Y0v8c.js → explorer-window-content-CXFdvs_i.js} +1 -1
  15. package/dist/web/assets/{extension-webview-D6eywKPN.js → extension-webview-DIoKwGV4.js} +1 -1
  16. package/dist/web/assets/{git-log-panel-DAogZ9QV.js → git-log-panel-Copm8mzy.js} +1 -1
  17. package/dist/web/assets/{glide-data-grid-DxfJRN-r.js → glide-data-grid-D0L8SZVt.js} +4 -4
  18. package/dist/web/assets/group-chat-tab-D9cazEAI.js +1 -0
  19. package/dist/web/assets/{image-preview-Byjx8MoL.js → image-preview-vFeN8o43.js} +1 -1
  20. package/dist/web/assets/{index-CcN0TBm4.js → index-BewcuJw5.js} +24 -24
  21. package/dist/web/assets/index-oxsyfDa0.css +2 -0
  22. package/dist/web/assets/keybindings-store-ruNjhVT3.js +1 -0
  23. package/dist/web/assets/{markdown-renderer-CXlEe3ma.js → markdown-renderer-B46VJEHH.js} +2 -2
  24. package/dist/web/assets/markdown-renderer-CYiMPviS.js +1 -0
  25. package/dist/web/assets/{mobile-explorer-sheet-BuqBlP3o.js → mobile-explorer-sheet-BkMZxqs3.js} +1 -1
  26. package/dist/web/assets/notification-store-B3IK7PXf.js +1 -0
  27. package/dist/web/assets/{pdf-preview-F2DWVB85.js → pdf-preview-DU_NRMno.js} +1 -1
  28. package/dist/web/assets/{postgres-viewer-KZqPYfOB.js → postgres-viewer-C0h3Zfk9.js} +2 -2
  29. package/dist/web/assets/{settings-store-CY-4_U3H.js → settings-store-C9YT1Hir.js} +2 -2
  30. package/dist/web/assets/{settings-tab-Khj-w6Sr.js → settings-tab-Cep8gjxG.js} +1 -1
  31. package/dist/web/assets/{sql-query-editor-Cp0_e2P1.js → sql-query-editor-DJofTC9F.js} +1 -1
  32. package/dist/web/assets/{sqlite-viewer-CIv3sagZ.js → sqlite-viewer-D7bskeyk.js} +1 -1
  33. package/dist/web/assets/{system-monitor-tab-CrssTOf4.js → system-monitor-tab-CxgFsQx9.js} +1 -1
  34. package/dist/web/assets/team-member-sheet-Dn5NGkcp.js +2 -0
  35. package/dist/web/assets/{team-member-window-content-D-hXax3c.js → team-member-window-content-DS9V4trr.js} +1 -1
  36. package/dist/web/assets/{terminal-tab-BIQDG-Ti.js → terminal-tab-CMs8AyFJ.js} +3 -3
  37. package/dist/web/assets/tool-cards-HHRTIlFv.js +8 -0
  38. package/dist/web/assets/{use-monaco-theme-Djp1_fKi.js → use-monaco-theme-BLt-n9r1.js} +1 -1
  39. package/dist/web/assets/use-open-team-member-BwtzTuxf.js +1 -0
  40. package/dist/web/assets/{use-websocket-CCYA9-a2.js → use-websocket-DA3Zwl3Z.js} +1 -1
  41. package/dist/web/assets/video-preview-BZhTYMFX.js +1 -0
  42. package/dist/web/index.html +3 -3
  43. package/dist/web/sw.js +1 -1
  44. package/package.json +1 -1
  45. package/src/web/app.tsx +12 -0
  46. package/src/web/components/chat/chat-tab.tsx +11 -0
  47. package/src/web/components/chat/team-activity-panel.tsx +4 -4
  48. package/src/web/components/chat/team-member-activity-format.ts +38 -0
  49. package/src/web/components/chat/team-member-activity-row.tsx +1 -29
  50. package/src/web/components/chat/team-member-sheet.tsx +47 -0
  51. package/src/web/components/chat/team-working-bar.tsx +62 -0
  52. package/src/web/components/chat/use-open-team-member.ts +41 -0
  53. package/src/web/components/os-explorer/actions/collision-prompt-queue.ts +133 -0
  54. package/src/web/components/os-explorer/actions/explorer-actions-clipboard.ts +29 -3
  55. package/src/web/components/os-explorer/actions/explorer-actions-upload.ts +88 -33
  56. package/src/web/components/os-explorer/actions/use-collision-prompt.ts +56 -0
  57. package/src/web/components/os-explorer/actions/use-explorer-actions.ts +29 -44
  58. package/src/web/components/os-explorer/actions/use-permanent-overwrite-prompt.ts +47 -0
  59. package/src/web/components/os-explorer/dnd/use-drop-transfer.tsx +19 -27
  60. package/src/web/components/os-explorer/explorer-dialogs.tsx +12 -1
  61. package/src/web/components/os-explorer/upload/capture-picked-files.ts +18 -0
  62. package/src/web/components/os-explorer/upload/upload-batch-card.tsx +64 -0
  63. package/src/web/components/os-explorer/upload/upload-batch-progress.ts +34 -0
  64. package/src/web/components/os-explorer/upload/upload-batch-row.tsx +79 -0
  65. package/src/web/components/os-explorer/upload/upload-error-message.ts +19 -0
  66. package/src/web/components/os-explorer/upload/upload-progress-panel.tsx +72 -0
  67. package/src/web/components/os-explorer/upload/upload-store.ts +109 -0
  68. package/src/web/components/os-explorer/upload/use-upload-picker.tsx +7 -5
  69. package/src/web/lib/fs-upload-xhr.ts +13 -2
  70. package/dist/web/assets/chat-tab-CgAv-crh.js +0 -15
  71. package/dist/web/assets/code-editor-bX4jlgMy.js +0 -10
  72. package/dist/web/assets/explorer-body-DykJXCTw.js +0 -2
  73. package/dist/web/assets/group-chat-tab-DkVi6qL2.js +0 -1
  74. package/dist/web/assets/index-Bucbpby-.css +0 -2
  75. package/dist/web/assets/keybindings-store-DJIHqbLM.js +0 -1
  76. package/dist/web/assets/markdown-renderer-pYznJDbh.js +0 -1
  77. package/dist/web/assets/notification-store-Bcl5efY2.js +0 -1
  78. package/dist/web/assets/tool-cards-Dx-Rrpri.js +0 -8
  79. package/dist/web/assets/video-preview-cvjNMjWA.js +0 -1
  80. /package/dist/web/assets/{api-themes-CEyYK7AK.js → api-themes-8WTH6KpV.js} +0 -0
  81. /package/dist/web/assets/{can-open-in-ppm-Cu-XYIgu.js → can-open-in-ppm-DXGOSUQc.js} +0 -0
  82. /package/dist/web/assets/{csv-parser-r-Nk1oHT.js → csv-parser-BRtnJCfv.js} +0 -0
  83. /package/dist/web/assets/{edit-diff-preview-HTZPC9VP.js → edit-diff-preview-BivQwZMD.js} +0 -0
  84. /package/dist/web/assets/{lib-BzxL1ARZ.js → lib-B1clP4ai.js} +0 -0
  85. /package/dist/web/assets/{media-url-C5vA0ha9.js → media-url-CUpN5vI1.js} +0 -0
  86. /package/dist/web/assets/{run-in-terminal-B8TDtaM_.js → run-in-terminal-CGW6o37_.js} +0 -0
  87. /package/dist/web/assets/{send-to-chat-CuBAVC8l.js → send-to-chat-YXHdAyLG.js} +0 -0
  88. /package/dist/web/assets/{vendor-xterm-BeaIjRrv.js → vendor-xterm-C1diXHJl.js} +0 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Global upload progress state — batches of in-flight uploads (a drop or a picker pick), each
3
+ * with per-file rows. Backs the persistent upload panel that replaced the old
4
+ * "Uploading N files… NN%" toast, which had no room for per-file outcomes or a cancel button.
5
+ *
6
+ * Cancel hooks are kept in a side map (`cancellers`), not on the serializable item/batch
7
+ * state — an `AbortController.abort` closure has no business living next to plain data a
8
+ * test might snapshot or log.
9
+ */
10
+
11
+ import { create } from "zustand";
12
+
13
+ export type UploadItemState = "queued" | "uploading" | "done" | "skipped" | "failed" | "cancelled";
14
+
15
+ export interface UploadItem {
16
+ id: string;
17
+ name: string;
18
+ relativePath: string;
19
+ size: number;
20
+ bytesLoaded: number;
21
+ state: UploadItemState;
22
+ errorMessage?: string;
23
+ }
24
+
25
+ export interface UploadBatch {
26
+ id: string;
27
+ dstDir: string;
28
+ items: UploadItem[];
29
+ /** True once every item has left "queued"/"uploading" — the panel swaps Cancel for Close. */
30
+ settled: boolean;
31
+ }
32
+
33
+ type NewUploadItem = Pick<UploadItem, "id" | "name" | "relativePath" | "size">;
34
+
35
+ function deriveSettled(items: UploadItem[]): boolean {
36
+ return items.every((i) => i.state !== "queued" && i.state !== "uploading");
37
+ }
38
+
39
+ interface UploadStoreState {
40
+ order: string[];
41
+ batches: Record<string, UploadBatch>;
42
+ cancellers: Record<string, () => void>;
43
+
44
+ addBatch(id: string, dstDir: string, items: NewUploadItem[]): void;
45
+ registerCanceller(batchId: string, itemId: string, cancel: () => void): void;
46
+ setItemState(batchId: string, itemId: string, state: UploadItemState, errorMessage?: string): void;
47
+ setItemProgress(batchId: string, itemId: string, bytesLoaded: number): void;
48
+ cancelItem(batchId: string, itemId: string): void;
49
+ cancelBatch(batchId: string): void;
50
+ dismissBatch(batchId: string): void;
51
+ }
52
+
53
+ export const useUploadStore = create<UploadStoreState>((set, get) => ({
54
+ order: [],
55
+ batches: {},
56
+ cancellers: {},
57
+
58
+ addBatch: (id, dstDir, items) => {
59
+ const batch: UploadBatch = {
60
+ id,
61
+ dstDir,
62
+ items: items.map((item) => ({ ...item, bytesLoaded: 0, state: "queued" })),
63
+ settled: false,
64
+ };
65
+ set((s) => ({ order: [...s.order, id], batches: { ...s.batches, [id]: batch } }));
66
+ },
67
+
68
+ registerCanceller: (batchId, itemId, cancel) => {
69
+ set((s) => ({ cancellers: { ...s.cancellers, [`${batchId}:${itemId}`]: cancel } }));
70
+ },
71
+
72
+ setItemState: (batchId, itemId, state, errorMessage) => {
73
+ set((s) => {
74
+ const batch = s.batches[batchId];
75
+ if (!batch) return s;
76
+ const items = batch.items.map((i) => (i.id === itemId ? { ...i, state, errorMessage } : i));
77
+ return { batches: { ...s.batches, [batchId]: { ...batch, items, settled: deriveSettled(items) } } };
78
+ });
79
+ },
80
+
81
+ setItemProgress: (batchId, itemId, bytesLoaded) => {
82
+ set((s) => {
83
+ const batch = s.batches[batchId];
84
+ if (!batch) return s;
85
+ const items = batch.items.map((i) => (i.id === itemId ? { ...i, bytesLoaded } : i));
86
+ return { batches: { ...s.batches, [batchId]: { ...batch, items } } };
87
+ });
88
+ },
89
+
90
+ // Cancelling only ever *asks* the in-flight job to stop (abort the XHR, or skip a queued
91
+ // job before it starts) — the resulting "cancelled" state is set by the job itself once its
92
+ // promise actually rejects, not here, so state and reality never disagree.
93
+ cancelItem: (batchId, itemId) => {
94
+ get().cancellers[`${batchId}:${itemId}`]?.();
95
+ },
96
+
97
+ cancelBatch: (batchId) => {
98
+ const batch = get().batches[batchId];
99
+ if (!batch) return;
100
+ for (const item of batch.items) get().cancelItem(batchId, item.id);
101
+ },
102
+
103
+ dismissBatch: (batchId) => {
104
+ set((s) => {
105
+ const { [batchId]: _removed, ...batches } = s.batches;
106
+ return { batches, order: s.order.filter((id) => id !== batchId) };
107
+ });
108
+ },
109
+ }));
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import { useRef, type ChangeEvent, type ReactNode } from "react";
11
+ import { capturePickedFiles } from "./capture-picked-files";
11
12
  import type { DroppedEntry } from "./collect-dropped-entries";
12
13
 
13
14
  export interface UploadPicker {
@@ -30,11 +31,12 @@ export function useUploadPicker(onFiles: (entries: DroppedEntry[]) => void): Upl
30
31
  typeof document !== "undefined" && "webkitdirectory" in document.createElement("input");
31
32
 
32
33
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
33
- const files = e.target.files;
34
- // Clears the value so picking the exact same file/folder again still fires `onChange`.
35
- e.target.value = "";
36
- if (!files || files.length === 0) return;
37
- const entries: DroppedEntry[] = Array.from(files).map((file) => ({
34
+ // Captures the live FileList into a plain array BEFORE clearing `value` (see
35
+ // `capture-picked-files.ts`) clearing first, so picking the exact same file/folder
36
+ // again still fires `onChange`, would otherwise race Chromium emptying the list itself.
37
+ const picked = capturePickedFiles(e.target.files, () => { e.target.value = ""; });
38
+ if (picked.length === 0) return;
39
+ const entries: DroppedEntry[] = picked.map((file) => ({
38
40
  file,
39
41
  // The folder picker sets `webkitRelativePath` ("folder/sub/file.txt"); a plain file
40
42
  // picker leaves it empty, so the bare name is the relative path.
@@ -29,8 +29,14 @@ export function uploadFileXhr(
29
29
  file: File,
30
30
  overwrite: boolean,
31
31
  onProgress: (progress: UploadProgress) => void,
32
+ signal?: AbortSignal,
32
33
  ): Promise<{ path: string; size: number }> {
33
34
  return new Promise((resolve, reject) => {
35
+ if (signal?.aborted) {
36
+ reject(new DOMException("Upload aborted", "AbortError"));
37
+ return;
38
+ }
39
+
34
40
  const xhr = new XMLHttpRequest();
35
41
  xhr.open("PUT", fsApi.uploadUrl(path, overwrite));
36
42
  const token = getAuthToken();
@@ -41,7 +47,12 @@ export function uploadFileXhr(
41
47
  if (e.lengthComputable) onProgress({ loaded: e.loaded, total: e.total });
42
48
  };
43
49
 
50
+ const onAbortSignal = () => xhr.abort();
51
+ signal?.addEventListener("abort", onAbortSignal);
52
+ const detach = () => signal?.removeEventListener("abort", onAbortSignal);
53
+
44
54
  xhr.onload = () => {
55
+ detach();
45
56
  let json: UploadResponseBody = {};
46
57
  try {
47
58
  json = JSON.parse(xhr.responseText);
@@ -54,8 +65,8 @@ export function uploadFileXhr(
54
65
  }
55
66
  reject(new FsError(json.error ?? `HTTP ${xhr.status}`, json.code ?? "EUNKNOWN", xhr.status));
56
67
  };
57
- xhr.onerror = () => reject(new Error("Network error during upload"));
58
- xhr.onabort = () => reject(new DOMException("Upload aborted", "AbortError"));
68
+ xhr.onerror = () => { detach(); reject(new Error("Network error during upload")); };
69
+ xhr.onabort = () => { detach(); reject(new DOMException("Upload aborted", "AbortError")); };
59
70
 
60
71
  xhr.send(file);
61
72
  });