@hienlh/ppm 0.6.2 → 0.6.4
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 +16 -0
- package/dist/web/assets/api-client-BHpHp5Lz.js +1 -0
- package/dist/web/assets/{chat-tab-BdiG3Gnr.js → chat-tab-CDVCDw_H.js} +5 -5
- package/dist/web/assets/code-editor-wmS73ejX.js +1 -0
- package/dist/web/assets/diff-viewer-BsYccTx1.js +4 -0
- package/dist/web/assets/{dist-CJbcT4CK.js → dist-PpKqMvyx.js} +2 -2
- package/dist/web/assets/git-graph-BbWb6_Jq.js +1 -0
- package/dist/web/assets/index-DhuAmTQ1.js +21 -0
- package/dist/web/assets/index-aIGuIMQ8.css +2 -0
- package/dist/web/assets/input-CCCPR1s4.js +41 -0
- package/dist/web/assets/jsx-runtime-wQxeESYQ.js +1 -0
- package/dist/web/assets/keybindings-store-BqgrTQAC.js +1 -0
- package/dist/web/assets/{markdown-renderer-BPKEwysz.js → markdown-renderer-aPdw9BhU.js} +1 -1
- package/dist/web/assets/postgres-viewer-V4hKmmzV.js +1 -0
- package/dist/web/assets/{jsx-runtime-B4BJKQ1u.js → react-CYzKIDNi.js} +1 -1
- package/dist/web/assets/react-l9v2XLcs.js +1 -0
- package/dist/web/assets/settings-store-DgOSmeGL.js +1 -0
- package/dist/web/assets/settings-tab-DwsKpk9T.js +1 -0
- package/dist/web/assets/sqlite-viewer-BRsj8GXc.js +1 -0
- package/dist/web/assets/{tab-store-Bf9z6T8D.js → tab-store-DhXold0e.js} +1 -1
- package/dist/web/assets/{terminal-tab-Dt9bjwC8.js → terminal-tab-3tDV4RCn.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-yxUtuNlu.js → use-monaco-theme-Ccqh1RD4.js} +1 -1
- package/dist/web/index.html +9 -8
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +41 -14
- package/docs/project-roadmap.md +31 -6
- package/docs/system-architecture.md +222 -7
- package/package.json +1 -1
- package/src/cli/commands/db-cmd.ts +355 -0
- package/src/server/index.ts +6 -0
- package/src/server/routes/database.ts +259 -0
- package/src/server/routes/settings.ts +33 -0
- package/src/services/database/adapter-registry.ts +13 -0
- package/src/services/database/init-adapters.ts +9 -0
- package/src/services/database/postgres-adapter.ts +42 -0
- package/src/services/database/readonly-check.ts +17 -0
- package/src/services/database/sqlite-adapter.ts +55 -0
- package/src/services/db.service.ts +173 -2
- package/src/services/table-cache.service.ts +75 -0
- package/src/types/database.ts +50 -0
- package/src/web/app.tsx +11 -1
- package/src/web/components/database/connection-color-picker.tsx +67 -0
- package/src/web/components/database/connection-form-dialog.tsx +234 -0
- package/src/web/components/database/connection-list.tsx +208 -0
- package/src/web/components/database/database-sidebar.tsx +100 -0
- package/src/web/components/database/use-connections.ts +99 -0
- package/src/web/components/layout/command-palette.tsx +57 -6
- package/src/web/components/layout/draggable-tab.tsx +13 -2
- package/src/web/components/layout/mobile-drawer.tsx +7 -2
- package/src/web/components/layout/sidebar.tsx +6 -1
- package/src/web/components/postgres/postgres-viewer.tsx +12 -3
- package/src/web/components/postgres/use-postgres.ts +57 -21
- package/src/web/components/settings/keyboard-shortcuts-section.tsx +182 -0
- package/src/web/components/settings/settings-tab.tsx +5 -0
- package/src/web/components/sqlite/sqlite-viewer.tsx +27 -3
- package/src/web/components/sqlite/use-sqlite.ts +21 -12
- package/src/web/hooks/use-global-keybindings.ts +74 -14
- package/src/web/lib/api-client.ts +7 -1
- package/src/web/lib/color-utils.ts +23 -0
- package/src/web/stores/keybindings-store.ts +192 -0
- package/src/web/stores/settings-store.ts +2 -2
- package/dist/web/assets/api-client-DPWUomlf.js +0 -1
- package/dist/web/assets/code-editor-soN1frMc.js +0 -1
- package/dist/web/assets/diff-viewer-DJEB1zOd.js +0 -4
- package/dist/web/assets/git-graph-CrU7vGxw.js +0 -1
- package/dist/web/assets/index-CmrE0Xoy.js +0 -21
- package/dist/web/assets/index-g11aaU-x.css +0 -2
- package/dist/web/assets/input-DMu1FA4M.js +0 -41
- package/dist/web/assets/postgres-viewer-lBV4F44Q.js +0 -1
- package/dist/web/assets/react-Bo97Lrzq.js +0 -1
- package/dist/web/assets/rotate-ccw-Dx0ShAKj.js +0 -1
- package/dist/web/assets/settings-store-BRFvbsHd.js +0 -1
- package/dist/web/assets/settings-tab-Div5NL2d.js +0 -1
- package/dist/web/assets/sqlite-viewer-BbgWU-v3.js +0 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
import { api } from "@/lib/api-client";
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Types
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
export type KeyCategory = "general" | "tabs" | "projects";
|
|
9
|
+
|
|
10
|
+
export interface KeyAction {
|
|
11
|
+
id: string;
|
|
12
|
+
label: string;
|
|
13
|
+
category: KeyCategory;
|
|
14
|
+
defaultKey: string;
|
|
15
|
+
locked?: boolean;
|
|
16
|
+
note?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Action catalog
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.userAgent);
|
|
24
|
+
|
|
25
|
+
export const KEY_ACTIONS: KeyAction[] = [
|
|
26
|
+
// General
|
|
27
|
+
{ id: "command-palette", label: "Command Palette", category: "general", defaultKey: "F1", note: "Shift+Shift also opens (not customizable)" },
|
|
28
|
+
{ id: "toggle-sidebar", label: "Toggle Sidebar", category: "general", defaultKey: "Mod+B" },
|
|
29
|
+
{ id: "save-prevent", label: "Prevent Save Dialog", category: "general", defaultKey: "Mod+S", locked: true, note: "Always active — prevents browser save" },
|
|
30
|
+
// Tabs
|
|
31
|
+
{ id: "next-tab", label: "Next Tab", category: "tabs", defaultKey: "Alt+]" },
|
|
32
|
+
{ id: "prev-tab", label: "Previous Tab", category: "tabs", defaultKey: "Alt+[" },
|
|
33
|
+
{ id: "open-chat", label: "Open Chat", category: "tabs", defaultKey: "Mod+Shift+L" },
|
|
34
|
+
{ id: "open-terminal", label: "Open Terminal", category: "tabs", defaultKey: "Mod+`" },
|
|
35
|
+
{ id: "open-settings", label: "Open Settings", category: "tabs", defaultKey: "Mod+," },
|
|
36
|
+
{ id: "open-git-graph", label: "Git Graph", category: "tabs", defaultKey: "Mod+Shift+G" },
|
|
37
|
+
{ id: "open-git-status", label: "Git Status (sidebar)", category: "tabs", defaultKey: "Mod+Shift+E" },
|
|
38
|
+
// Projects — Mod+1..9
|
|
39
|
+
...Array.from({ length: 9 }, (_, i) => ({
|
|
40
|
+
id: `switch-project-${i + 1}`,
|
|
41
|
+
label: `Switch to Project ${i + 1}`,
|
|
42
|
+
category: "projects" as KeyCategory,
|
|
43
|
+
defaultKey: `Mod+${i + 1}`,
|
|
44
|
+
})),
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
/** Map action ID → default key for fast lookup */
|
|
48
|
+
const DEFAULT_MAP = new Map(KEY_ACTIONS.map((a) => [a.id, a.defaultKey]));
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Key combo parsing & matching
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
interface ParsedCombo {
|
|
55
|
+
ctrl: boolean;
|
|
56
|
+
meta: boolean;
|
|
57
|
+
alt: boolean;
|
|
58
|
+
shift: boolean;
|
|
59
|
+
key: string; // lowercase
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function parseCombo(combo: string): ParsedCombo {
|
|
63
|
+
const parts = combo.split("+");
|
|
64
|
+
const result: ParsedCombo = { ctrl: false, meta: false, alt: false, shift: false, key: "" };
|
|
65
|
+
for (const part of parts) {
|
|
66
|
+
const p = part.trim();
|
|
67
|
+
switch (p) {
|
|
68
|
+
case "Mod":
|
|
69
|
+
if (isMac) result.meta = true;
|
|
70
|
+
else result.ctrl = true;
|
|
71
|
+
break;
|
|
72
|
+
case "Ctrl": result.ctrl = true; break;
|
|
73
|
+
case "Meta": case "Cmd": result.meta = true; break;
|
|
74
|
+
case "Alt": result.alt = true; break;
|
|
75
|
+
case "Shift": result.shift = true; break;
|
|
76
|
+
default: result.key = p.toLowerCase(); break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function eventMatchesCombo(e: KeyboardEvent, combo: ParsedCombo): boolean {
|
|
83
|
+
if (e.ctrlKey !== combo.ctrl) return false;
|
|
84
|
+
if (e.metaKey !== combo.meta) return false;
|
|
85
|
+
if (e.altKey !== combo.alt) return false;
|
|
86
|
+
if (e.shiftKey !== combo.shift) return false;
|
|
87
|
+
return e.key.toLowerCase() === combo.key;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Format combo for display
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
export function formatCombo(combo: string): string {
|
|
95
|
+
return combo
|
|
96
|
+
.replace(/Mod/g, isMac ? "\u2318" : "Ctrl")
|
|
97
|
+
.replace(/Shift/g, isMac ? "\u21E7" : "Shift")
|
|
98
|
+
.replace(/Alt/g, isMac ? "\u2325" : "Alt")
|
|
99
|
+
.replace(/Meta|Cmd/g, "\u2318")
|
|
100
|
+
.replace(/Ctrl/g, isMac ? "\u2303" : "Ctrl");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Build combo string from a KeyboardEvent (for recording) */
|
|
104
|
+
export function comboFromEvent(e: KeyboardEvent): string | null {
|
|
105
|
+
// Ignore bare modifier keys
|
|
106
|
+
if (["Control", "Meta", "Alt", "Shift"].includes(e.key)) return null;
|
|
107
|
+
|
|
108
|
+
const parts: string[] = [];
|
|
109
|
+
if (e.ctrlKey && !e.metaKey) parts.push(isMac ? "Ctrl" : "Mod");
|
|
110
|
+
if (e.metaKey) parts.push(isMac ? "Mod" : "Meta");
|
|
111
|
+
if (e.altKey) parts.push("Alt");
|
|
112
|
+
if (e.shiftKey) parts.push("Shift");
|
|
113
|
+
|
|
114
|
+
// Normalize key
|
|
115
|
+
let key = e.key;
|
|
116
|
+
if (key === " ") key = "Space";
|
|
117
|
+
else if (key.length === 1) key = key.toUpperCase();
|
|
118
|
+
parts.push(key);
|
|
119
|
+
|
|
120
|
+
return parts.join("+");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Store
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
interface KeybindingsState {
|
|
128
|
+
/** User overrides from server (action ID → combo string) */
|
|
129
|
+
overrides: Record<string, string>;
|
|
130
|
+
loaded: boolean;
|
|
131
|
+
|
|
132
|
+
/** Get the effective binding for an action */
|
|
133
|
+
getBinding: (actionId: string) => string;
|
|
134
|
+
/** Check if a keyboard event matches an action */
|
|
135
|
+
matchesEvent: (e: KeyboardEvent, actionId: string) => boolean;
|
|
136
|
+
/** Set a custom binding (persists to server) */
|
|
137
|
+
setBinding: (actionId: string, combo: string) => void;
|
|
138
|
+
/** Reset a single binding to default (persists to server) */
|
|
139
|
+
resetBinding: (actionId: string) => void;
|
|
140
|
+
/** Reset all bindings to defaults (persists to server) */
|
|
141
|
+
resetAll: () => void;
|
|
142
|
+
/** Load overrides from server */
|
|
143
|
+
loadFromServer: () => Promise<void>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const useKeybindingsStore = create<KeybindingsState>((set, get) => ({
|
|
147
|
+
overrides: {},
|
|
148
|
+
loaded: false,
|
|
149
|
+
|
|
150
|
+
getBinding: (actionId) => {
|
|
151
|
+
return get().overrides[actionId] ?? DEFAULT_MAP.get(actionId) ?? "";
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
matchesEvent: (e, actionId) => {
|
|
155
|
+
const combo = get().getBinding(actionId);
|
|
156
|
+
if (!combo) return false;
|
|
157
|
+
return eventMatchesCombo(e, parseCombo(combo));
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
setBinding: (actionId, combo) => {
|
|
161
|
+
const newOverrides = { ...get().overrides, [actionId]: combo };
|
|
162
|
+
set({ overrides: newOverrides });
|
|
163
|
+
// Persist to server (fire-and-forget)
|
|
164
|
+
api.put("/api/settings/keybindings", { [actionId]: combo }).catch(() => {});
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
resetBinding: (actionId) => {
|
|
168
|
+
const newOverrides = { ...get().overrides };
|
|
169
|
+
delete newOverrides[actionId];
|
|
170
|
+
set({ overrides: newOverrides });
|
|
171
|
+
api.put("/api/settings/keybindings", { [actionId]: null }).catch(() => {});
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
resetAll: () => {
|
|
175
|
+
set({ overrides: {} });
|
|
176
|
+
// Send all current override keys as null to clear them
|
|
177
|
+
const nulled: Record<string, null> = {};
|
|
178
|
+
for (const key of Object.keys(get().overrides)) nulled[key] = null;
|
|
179
|
+
if (Object.keys(nulled).length > 0) {
|
|
180
|
+
api.put("/api/settings/keybindings", nulled).catch(() => {});
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
loadFromServer: async () => {
|
|
185
|
+
try {
|
|
186
|
+
const overrides = await api.get<Record<string, string>>("/api/settings/keybindings");
|
|
187
|
+
set({ overrides, loaded: true });
|
|
188
|
+
} catch {
|
|
189
|
+
set({ loaded: true }); // proceed with defaults on error
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
}));
|
|
@@ -2,7 +2,7 @@ import { create } from "zustand";
|
|
|
2
2
|
|
|
3
3
|
export type Theme = "light" | "dark" | "system";
|
|
4
4
|
export type GitStatusViewMode = "flat" | "tree";
|
|
5
|
-
export type SidebarActiveTab = "explorer" | "git" | "settings";
|
|
5
|
+
export type SidebarActiveTab = "explorer" | "git" | "settings" | "database";
|
|
6
6
|
|
|
7
7
|
const STORAGE_KEY = "ppm-settings";
|
|
8
8
|
|
|
@@ -78,7 +78,7 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
|
|
|
78
78
|
sidebarWidth: _initial.sidebarWidth ?? 280,
|
|
79
79
|
gitStatusViewMode: _initial.gitStatusViewMode === "flat" ? "flat" : "tree",
|
|
80
80
|
wordWrap: _initial.wordWrap ?? false,
|
|
81
|
-
sidebarActiveTab: (
|
|
81
|
+
sidebarActiveTab: (["git", "settings", "database"] as SidebarActiveTab[]).includes(_initial.sidebarActiveTab as SidebarActiveTab) ? _initial.sidebarActiveTab! : "explorer",
|
|
82
82
|
deviceName: null,
|
|
83
83
|
version: null,
|
|
84
84
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./jsx-runtime-B4BJKQ1u.js";var t=e({api:()=>r,getAuthToken:()=>o,projectUrl:()=>i,setAuthToken:()=>a}),n=`ppm-auth-token`,r=new class{baseUrl;constructor(e=``){this.baseUrl=e}getToken(){return localStorage.getItem(n)}headers(){let e={"Content-Type":`application/json`},t=this.getToken();return t&&(e.Authorization=`Bearer ${t}`),e}async get(e){let t=await fetch(`${this.baseUrl}${e}`,{headers:this.headers()});return this.handleResponse(t)}async post(e,t){let n=await fetch(`${this.baseUrl}${e}`,{method:`POST`,headers:this.headers(),body:t==null?void 0:JSON.stringify(t)});return this.handleResponse(n)}async put(e,t){let n=await fetch(`${this.baseUrl}${e}`,{method:`PUT`,headers:this.headers(),body:t==null?void 0:JSON.stringify(t)});return this.handleResponse(n)}async patch(e,t){let n=await fetch(`${this.baseUrl}${e}`,{method:`PATCH`,headers:this.headers(),body:t==null?void 0:JSON.stringify(t)});return this.handleResponse(n)}async del(e,t){let n=await fetch(`${this.baseUrl}${e}`,{method:`DELETE`,headers:this.headers(),body:t==null?void 0:JSON.stringify(t)});await this.handleResponse(n)}async handleResponse(e){if(e.status===401)throw localStorage.removeItem(n),window.location.reload(),Error(`Unauthorized`);let t=await e.json();if(t.ok===!1)throw Error(t.error??`HTTP ${e.status}`);return t.data}};function i(e){return`/api/project/${encodeURIComponent(e)}`}function a(e){localStorage.setItem(n,e)}function o(){return localStorage.getItem(n)}export{a,i,t as n,o as r,r as t};
|
|
@@ -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-Bf9z6T8D.js";import{n as o}from"./settings-store-BRFvbsHd.js";import{t as s}from"./utils-CAPYyGV3.js";import{i as c,r as l,t as u}from"./api-client-DPWUomlf.js";import{T as d}from"./index-CmrE0Xoy.js";import{t as f}from"./markdown-renderer-BPKEwysz.js";import{n as p,t as m}from"./use-monaco-theme-yxUtuNlu.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`]),y=new Set([`db`,`sqlite`,`sqlite3`]);function b(e){return e.split(`.`).pop()?.toLowerCase()??``}function x(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`}[b(e)]??`plaintext`}function S({metadata:e,tabId:t}){let n=e?.filePath,r=e?.projectName,[i,l]=(0,g.useState)(null),[f,S]=(0,g.useState)(`utf-8`),[E,D]=(0,g.useState)(!0),[O,k]=(0,g.useState)(null),[A,j]=(0,g.useState)(!1),M=(0,g.useRef)(null),N=(0,g.useRef)(``),P=(0,g.useRef)(null),{tabs:F,updateTab:I}=a(),{wordWrap:L,toggleWordWrap:R}=o(),z=m(),B=F.find(e=>e.id===t),V=n?b(n):``,H=v.has(V),U=V===`pdf`,W=y.has(V),G=V===`md`||V===`mdx`,[K,q]=(0,g.useState)(`preview`);(0,g.useEffect)(()=>{W&&t&&I(t,{type:`sqlite`})},[W,t,I]);let J=n?/^(\/|[A-Za-z]:[/\\])/.test(n):!1;(0,g.useEffect)(()=>{if(!n||!J&&!r)return;if(H||U){D(!1);return}D(!0),k(null);let e=J?`/api/fs/read?path=${encodeURIComponent(n)}`:`${c(r)}/files/read?path=${encodeURIComponent(n)}`;return u.get(e).then(e=>{l(e.content),e.encoding&&S(e.encoding),N.current=e.content,D(!1)}).catch(e=>{k(e instanceof Error?e.message:`Failed to load file`),D(!1)}),()=>{M.current&&clearTimeout(M.current)}},[n,r,H,U,J]),(0,g.useEffect)(()=>{if(!B)return;let e=n?s(n):`Untitled`,t=A?`${e} \u25CF`:e;B.title!==t&&I(B.id,{title:t})},[A]);let Y=(0,g.useCallback)(async e=>{if(n&&!(!J&&!r))try{J?await u.put(`/api/fs/write`,{path:n,content:e}):await u.put(`${c(r)}/files/write`,{path:n,content:e}),j(!1)}catch{}},[n,r,J]);function X(e){let t=e??``;l(t),N.current=t,j(!0),M.current&&clearTimeout(M.current),M.current=setTimeout(()=>Y(N.current),1e3)}let Z=(0,g.useCallback)((e,t)=>{P.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||!J&&!r?(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full text-text-secondary text-sm`,children:`No file selected.`}):E?(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...`})]}):O?(0,_.jsx)(`div`,{className:`flex items-center justify-center h-full text-error text-sm`,children:O}):H?(0,_.jsx)(w,{filePath:n,projectName:r}):U?(0,_.jsx)(T,{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:G&&K===`preview`?(0,_.jsx)(C,{content:i??``}):(0,_.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,_.jsx)(p,{height:`100%`,language:x(n),value:i??``,onChange:X,onMount:Z,theme:z,options:{fontSize:13,fontFamily:`Menlo, Monaco, Consolas, monospace`,wordWrap:L?`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 C({content:e}){return(0,_.jsx)(f,{content:e,className:`flex-1 overflow-auto p-4`})}function w({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 T({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{S as CodeEditor};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{o as e,r as t,t as n}from"./jsx-runtime-B4BJKQ1u.js";import{n as r}from"./settings-store-BRFvbsHd.js";import{i,t as a}from"./api-client-DPWUomlf.js";import{T as o,j as s}from"./index-CmrE0Xoy.js";import{r as c,t as l}from"./use-monaco-theme-yxUtuNlu.js";var u=e(t(),1),d=n();function f(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`}[e.split(`.`).pop()?.toLowerCase()??``]??`plaintext`}function p({metadata:e}){let t=e?.filePath,n=e?.projectName,p=e?.ref1,h=e?.ref2,g=e?.file1,_=e?.file2,v=e?.original,y=e?.modified,b=v!=null||y!=null,x=!!(g&&_),[S,C]=(0,u.useState)(null),[w,T]=(0,u.useState)(null),[E,D]=(0,u.useState)(!b),[O,k]=(0,u.useState)(null),[A,j]=(0,u.useState)(`both`),{wordWrap:M,toggleWordWrap:N}=r(),P=l(),F=(0,u.useRef)(null),[I,L]=(0,u.useState)();(0,u.useEffect)(()=>{let e=F.current;if(!e)return;let t=new ResizeObserver(([e])=>{e&&L(Math.floor(e.contentRect.height))});return t.observe(e),()=>t.disconnect()},[]),(0,u.useEffect)(()=>{if(b||!n)return;if(D(!0),k(null),g&&_){let e=new URLSearchParams({file1:g,file2:_});a.get(`${i(n)}/files/compare?${e}`).then(e=>{T(e),D(!1)}).catch(e=>{k(e instanceof Error?e.message:`Failed to compare files`),D(!1)});return}let e;if(t){let r=new URLSearchParams({file:t});p&&r.set(`ref`,p),e=`${i(n)}/git/file-diff?${r}`}else if(p||h){let t=new URLSearchParams;p&&t.set(`ref1`,p),h&&t.set(`ref2`,h),e=`${i(n)}/git/diff?${t}`}else e=`${i(n)}/git/diff`;a.get(e).then(e=>{C(e.diff),D(!1)}).catch(e=>{k(e instanceof Error?e.message:`Failed to load diff`),D(!1)})},[t,n,p,h,g,_,b]);let{original:R,modified:z}=(0,u.useMemo)(()=>b?{original:v??``,modified:y??``}:x&&w?w:S?m(S):{original:``,modified:``},[S,b,v,y,x,w]),B=(0,u.useMemo)(()=>{let e=t??_??g;return e?f(e):`plaintext`},[t,g,_]),V=typeof window<`u`&&window.innerWidth<768,H=!V&&A===`both`;return!n&&!b?(0,d.jsx)(`div`,{className:`flex items-center justify-center h-full text-muted-foreground text-sm`,children:`No project selected.`}):E?(0,d.jsxs)(`div`,{className:`flex items-center justify-center h-full gap-2 text-muted-foreground`,children:[(0,d.jsx)(o,{className:`size-5 animate-spin`}),(0,d.jsx)(`span`,{className:`text-sm`,children:`Loading diff...`})]}):O?(0,d.jsx)(`div`,{className:`flex items-center justify-center h-full text-destructive text-sm`,children:O}):!b&&!x&&(!S||S.trim()===``)&&!R&&!z?(0,d.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-2 text-muted-foreground`,children:[(0,d.jsx)(s,{className:`size-8`}),(0,d.jsx)(`p`,{className:`text-sm`,children:`No changes detected`}),t&&(0,d.jsx)(`p`,{className:`text-xs font-mono`,children:t})]}):(0,d.jsx)(`div`,{className:`flex flex-col h-full`,children:(0,d.jsx)(`div`,{ref:F,className:`flex-1 overflow-hidden`,children:I&&I>0?(0,d.jsx)(c,{height:I,language:B,original:R,modified:z,theme:P,options:{fontSize:V?11:13,fontFamily:`Menlo, Monaco, Consolas, monospace`,wordWrap:V||M?`on`:`off`,renderSideBySide:H,readOnly:!0,automaticLayout:!0,scrollBeyondLastLine:!1},loading:(0,d.jsx)(o,{className:`size-5 animate-spin text-text-subtle`})}):(0,d.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,d.jsx)(o,{className:`size-5 animate-spin text-text-subtle`})})})})}function m(e){let t=e.split(`
|
|
2
|
-
`),n=[],r=[],i=!1;for(let e of t)if(!(e.startsWith(`diff --git`)||e.startsWith(`diff --no-index`)||e.startsWith(`index `)||e.startsWith(`new file`)||e.startsWith(`deleted file`)||e.startsWith(`old mode`)||e.startsWith(`new mode`)||e.startsWith(`---`)||e.startsWith(`+++`)||e.startsWith(`Binary files`)||e.startsWith(`\\ No newline`))){if(e.startsWith(`@@`)){i=!0;continue}if(i)if(e.startsWith(`-`))n.push(e.slice(1));else if(e.startsWith(`+`))r.push(e.slice(1));else{let t=e.startsWith(` `)?e.slice(1):e;n.push(t),r.push(t)}}return{original:n.join(`
|
|
3
|
-
`),modified:r.join(`
|
|
4
|
-
`)}}export{p as DiffViewer};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e,o as t,r as n,t as r}from"./jsx-runtime-B4BJKQ1u.js";import{t as i}from"./input-DMu1FA4M.js";import{a,t as o}from"./tab-store-Bf9z6T8D.js";import{t as s}from"./rotate-ccw-Dx0ShAKj.js";import{t as c}from"./utils-CAPYyGV3.js";import{i as l,t as u}from"./api-client-DPWUomlf.js";import{D as d,E as f,N as p,S as m,T as h,a as g,c as ee,d as _,f as v,i as te,l as y,m as b,o as ne,p as x,s as re,u as ie,y as S,z as C}from"./index-CmrE0Xoy.js";var ae=e(`cherry`,[[`path`,{d:`M2 17a5 5 0 0 0 10 0c0-2.76-2.5-5-5-3-2.5-2-5 .24-5 3Z`,key:`cvxqlc`}],[`path`,{d:`M12 17a5 5 0 0 0 10 0c0-2.76-2.5-5-5-3-2.5-2-5 .24-5 3Z`,key:`1ostrc`}],[`path`,{d:`M7 14c3.22-2.91 4.29-8.75 5-12 1.66 2.38 4.94 9 5 12`,key:`hqx58h`}],[`path`,{d:`M22 9c-4.29 0-7.14-2.33-10-7 5.71 0 10 4.67 10 7Z`,key:`eykp1o`}]]),w=e(`git-merge`,[[`circle`,{cx:`18`,cy:`18`,r:`3`,key:`1xkwt0`}],[`circle`,{cx:`6`,cy:`6`,r:`3`,key:`1lh9wr`}],[`path`,{d:`M6 21V9a9 9 0 0 0 9 9`,key:`7kw0sc`}]]),T=e(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]),E=t(n(),1),D=r(),O=[`#4fc3f7`,`#81c784`,`#ffb74d`,`#e57373`,`#ba68c8`,`#4dd0e1`,`#aed581`,`#ff8a65`,`#f06292`,`#7986cb`],k=32,A=20,oe=5;function j({metadata:e}){let t=e?.projectName,[n,r]=(0,E.useState)(null),[a,S]=(0,E.useState)(!0),[C,w]=(0,E.useState)(null),[j,M]=(0,E.useState)(!1),[N,P]=(0,E.useState)({type:null}),[F,I]=(0,E.useState)(``),[L,R]=(0,E.useState)(null),[z,B]=(0,E.useState)([]),[ce,V]=(0,E.useState)(!1),{openTab:H}=o(),U=(0,E.useCallback)(async()=>{if(t)try{S(!0),r(await u.get(`${l(t)}/git/graph?max=200`)),w(null)}catch(e){w(e instanceof Error?e.message:`Failed to fetch graph`)}finally{S(!1)}},[t]);(0,E.useEffect)(()=>{U();let e=setInterval(U,1e4);return()=>clearInterval(e)},[U]);let W=async(e,n)=>{if(t){M(!0);try{await u.post(`${l(t)}${e}`,n),await U()}catch(e){w(e instanceof Error?e.message:`Action failed`)}finally{M(!1)}}},G=e=>W(`/git/checkout`,{ref:e}),le=e=>W(`/git/cherry-pick`,{hash:e}),ue=e=>W(`/git/revert`,{hash:e}),de=e=>W(`/git/merge`,{source:e}),fe=e=>W(`/git/branch/delete`,{name:e}),pe=e=>W(`/git/push`,{branch:e}),K=async(e,t)=>{if(n?.branches.some(t=>t.name===e||t.name.endsWith(`/${e}`))){if(!window.confirm(`Branch "${e}" already exists.\nDelete it and recreate from this commit?`))return;await W(`/git/branch/delete`,{name:e})}await W(`/git/branch/create`,{name:e,from:t})},q=(e,t)=>W(`/git/tag`,{name:e,hash:t}),me=async e=>{if(t)try{let n=await u.get(`${l(t)}/git/pr-url?branch=${encodeURIComponent(e)}`);n.url&&window.open(n.url,`_blank`)}catch{}},J=e=>{navigator.clipboard.writeText(e)},he=async e=>{if(L?.hash===e.hash){R(null);return}R(e),V(!0);try{let n=e.parents[0]??``,r=n?`ref1=${encodeURIComponent(n)}&`:``,i=await u.get(`${l(t)}/git/diff-stat?${r}ref2=${encodeURIComponent(e.hash)}`);B(Array.isArray(i)?i:[])}catch(e){console.error(`diff-stat error:`,e),B([])}finally{V(!1)}},ge=e=>{let n=e.parents[0];H({type:`git-diff`,title:`Diff ${e.abbreviatedHash}`,closable:!0,metadata:{projectName:t,ref1:n??void 0,ref2:e.hash},projectId:t??null})},{laneMap:Y,maxLane:_e}=(0,E.useMemo)(()=>{let e=new Map;if(!n)return{laneMap:e,maxLane:0};let t=0,r=new Map;for(let i of n.commits){let n=r.get(i.hash);n===void 0&&(n=t++),e.set(i.hash,n),r.delete(i.hash);for(let e=0;e<i.parents.length;e++){let a=i.parents[e];r.has(a)||r.set(a,e===0?n:t++)}}return{laneMap:e,maxLane:Math.max(t-1,0)}},[n]),X=n?.branches.find(e=>e.current),ve=(0,E.useMemo)(()=>{let e=new Map;if(!n)return e;for(let t of n.branches){let n=e.get(t.commitHash)??[];n.push({name:t.name,type:`branch`}),e.set(t.commitHash,n)}for(let t of n.commits)for(let n of t.refs)if(n.startsWith(`tag: `)){let r=n.replace(`tag: `,``),i=e.get(t.hash)??[];i.push({name:r,type:`tag`}),e.set(t.hash,i)}return e},[n]),ye=(0,E.useMemo)(()=>{if(!n)return[];let e=[];for(let t=0;t<n.commits.length;t++){let r=n.commits[t],i=Y.get(r.hash)??0,a=O[i%O.length];for(let o of r.parents){let s=n.commits.findIndex(e=>e.hash===o);if(s<0)continue;let c=Y.get(o)??0,l=O[c%O.length],u=i*A+A/2,d=t*k+k/2,f=c*A+A/2,p=s*k+k/2,m,h=r.parents.indexOf(o)>0;if(u===f)m=`M ${u} ${d} L ${f} ${p}`;else if(h){let e=d+k;m=`M ${u} ${d} C ${u} ${e} ${f} ${d} ${f} ${e} L ${f} ${p}`}else{let e=p-k;m=`M ${u} ${d} L ${u} ${e} C ${u} ${p} ${f} ${e} ${f} ${p}`}let g=r.parents.indexOf(o)===0?a:l;e.push({d:m,color:g})}}return e},[n,Y]);(_e+1)*A+A;let be=(n?.commits.length??0)*k,[Z,xe]=(0,E.useState)((typeof window<`u`&&window.innerWidth<768?6:10)*A+A),Q=(0,E.useRef)(!1),$=(0,E.useCallback)(e=>{Q.current=!0;let t=Z,n=n=>{if(!Q.current)return;let r=`touches`in n?n.touches[0].clientX:n.clientX;xe(Math.max(40,t+r-e))},r=()=>{Q.current=!1,window.removeEventListener(`mousemove`,n),window.removeEventListener(`mouseup`,r),window.removeEventListener(`touchmove`,n),window.removeEventListener(`touchend`,r)};window.addEventListener(`mousemove`,n),window.addEventListener(`mouseup`,r),window.addEventListener(`touchmove`,n,{passive:!1}),window.addEventListener(`touchend`,r)},[Z]),Se=(0,E.useCallback)(e=>{e.preventDefault(),$(e.clientX)},[$]),Ce=(0,E.useCallback)(e=>{$(e.touches[0].clientX)},[$]);if(!t)return(0,D.jsx)(`div`,{className:`flex items-center justify-center h-full text-muted-foreground text-sm`,children:`No project selected.`});if(a&&!n)return(0,D.jsxs)(`div`,{className:`flex items-center justify-center h-full gap-2 text-muted-foreground`,children:[(0,D.jsx)(h,{className:`size-5 animate-spin`}),(0,D.jsx)(`span`,{className:`text-sm`,children:`Loading git graph...`})]});if(C&&!n)return(0,D.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-2 text-destructive text-sm`,children:[(0,D.jsx)(`p`,{children:C}),(0,D.jsx)(y,{variant:`outline`,size:`sm`,onClick:U,children:`Retry`})]});function we(e){let t=new Date(e),n=new Date().getTime()-t.getTime(),r=Math.floor(n/6e4);if(r<1)return`just now`;if(r<60)return`${r}m ago`;let i=Math.floor(r/60);if(i<24)return`${i}h ago`;let a=Math.floor(i/24);if(a<30)return`${a}d ago`;let o=Math.floor(a/30);return o<12?`${o}mo ago`:`${Math.floor(o/12)}y ago`}return(0,D.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,D.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-2 border-b`,children:[(0,D.jsxs)(`span`,{className:`text-sm font-medium`,children:[`Git Graph`,X?` - ${X.name}`:``]}),(0,D.jsx)(y,{variant:`ghost`,size:`icon-xs`,onClick:U,disabled:j,children:(0,D.jsx)(m,{className:a?`animate-spin`:``})})]}),C&&(0,D.jsx)(`div`,{className:`px-3 py-1.5 text-xs text-destructive bg-destructive/10`,children:C}),(0,D.jsx)(`div`,{className:`flex-1 overflow-y-auto overflow-x-auto md:overflow-x-hidden`,children:(0,D.jsxs)(`div`,{className:`flex min-w-max md:min-w-0`,style:{height:`${be}px`},children:[(0,D.jsxs)(`div`,{className:`sticky left-0 z-10 shrink-0 bg-background`,style:{width:`${Z}px`},children:[(0,D.jsxs)(`svg`,{width:Z,height:be,children:[ye.map((e,t)=>(0,D.jsx)(`path`,{d:e.d,stroke:e.color,strokeWidth:2,fill:`none`},t)),n?.commits.map((e,t)=>{let n=Y.get(e.hash)??0,r=n*A+A/2,i=t*k+k/2,a=O[n%O.length];return(0,D.jsx)(`circle`,{cx:r,cy:i,r:oe,fill:a,stroke:`#0f1419`,strokeWidth:2},e.hash)})]}),(0,D.jsx)(`div`,{className:`absolute top-0 right-0 w-3 md:w-2 h-full cursor-col-resize hover:bg-primary/20 flex items-center justify-center bg-primary/10 md:bg-transparent`,onMouseDown:Se,onTouchStart:Ce,children:(0,D.jsx)(f,{className:`size-3 text-muted-foreground md:opacity-0 md:hover:opacity-100`})})]}),(0,D.jsx)(`div`,{className:`flex-1 min-w-[400px]`,children:n?.commits.map((e,t)=>{let n=O[(Y.get(e.hash)??0)%O.length],r=ve.get(e.hash)??[],i=r.filter(e=>e.type===`branch`),a=r.filter(e=>e.type===`tag`);return(0,D.jsxs)(ie,{children:[(0,D.jsx)(b,{asChild:!0,children:(0,D.jsx)(`div`,{className:`flex items-center hover:bg-muted/50 cursor-pointer text-sm border-b border-border/30 ${L?.hash===e.hash?`bg-primary/10`:``}`,style:{height:`${k}px`},onClick:()=>he(e),children:(0,D.jsxs)(`div`,{className:`flex items-center gap-2 flex-1 min-w-0 px-2`,children:[(0,D.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground w-14 shrink-0`,children:e.abbreviatedHash}),i.map(e=>(0,D.jsx)(se,{label:e,color:n,currentBranch:X,onCheckout:G,onMerge:de,onPush:pe,onCreatePr:me,onDelete:fe},`branch-${e.name}`)),a.map(e=>(0,D.jsxs)(`span`,{className:`inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] font-medium shrink-0 bg-amber-500/20 text-amber-500 border border-amber-500/30`,children:[(0,D.jsx)(T,{className:`size-2.5`}),e.name]},`tag-${e.name}`)),(0,D.jsx)(`span`,{className:`flex-1 truncate`,children:e.subject}),(0,D.jsx)(`span`,{className:`text-xs text-muted-foreground shrink-0 hidden sm:inline`,children:e.authorName}),(0,D.jsx)(`span`,{className:`text-xs text-muted-foreground shrink-0 w-14 text-right`,children:we(e.authorDate)})]})})}),(0,D.jsxs)(_,{children:[(0,D.jsx)(v,{onClick:()=>G(e.hash),children:`Checkout`}),(0,D.jsxs)(v,{onClick:()=>{P({type:`branch`,hash:e.hash}),I(``)},children:[(0,D.jsx)(d,{className:`size-3`}),`Create Branch...`]}),(0,D.jsx)(x,{}),(0,D.jsxs)(v,{onClick:()=>le(e.hash),children:[(0,D.jsx)(ae,{className:`size-3`}),`Cherry Pick`]}),(0,D.jsxs)(v,{onClick:()=>ue(e.hash),children:[(0,D.jsx)(s,{className:`size-3`}),`Revert`]}),(0,D.jsxs)(v,{onClick:()=>{P({type:`tag`,hash:e.hash}),I(``)},children:[(0,D.jsx)(T,{className:`size-3`}),`Create Tag...`]}),(0,D.jsx)(x,{}),(0,D.jsx)(v,{onClick:()=>ge(e),children:`View Diff`}),(0,D.jsxs)(v,{onClick:()=>J(e.hash),children:[(0,D.jsx)(p,{className:`size-3`}),`Copy Hash`]})]})]},e.hash)})})]})}),L&&(0,D.jsxs)(`div`,{className:`border-t bg-muted/30 max-h-[40%] overflow-auto`,children:[(0,D.jsxs)(`div`,{className:`px-3 py-2 border-b flex items-center justify-between`,children:[(0,D.jsxs)(`span`,{className:`text-sm font-medium truncate`,children:[L.abbreviatedHash,` — `,L.subject]}),(0,D.jsx)(y,{variant:`ghost`,size:`icon-xs`,onClick:()=>R(null),children:`✕`})]}),(0,D.jsxs)(`div`,{className:`px-3 py-2 text-xs space-y-1`,children:[(0,D.jsxs)(`div`,{className:`flex gap-4`,children:[(0,D.jsx)(`span`,{className:`text-muted-foreground`,children:`Author`}),(0,D.jsxs)(`span`,{children:[L.authorName,` <`,L.authorEmail,`>`]})]}),(0,D.jsxs)(`div`,{className:`flex gap-4`,children:[(0,D.jsx)(`span`,{className:`text-muted-foreground`,children:`Date`}),(0,D.jsx)(`span`,{children:new Date(L.authorDate).toLocaleString()})]}),(0,D.jsxs)(`div`,{className:`flex gap-4`,children:[(0,D.jsx)(`span`,{className:`text-muted-foreground`,children:`Hash`}),(0,D.jsx)(`span`,{className:`font-mono cursor-pointer hover:text-primary`,onClick:()=>J(L.hash),children:L.hash})]}),L.parents.length>0&&(0,D.jsxs)(`div`,{className:`flex gap-4`,children:[(0,D.jsx)(`span`,{className:`text-muted-foreground`,children:`Parents`}),(0,D.jsx)(`span`,{className:`font-mono`,children:L.parents.map(e=>e.slice(0,7)).join(`, `)})]}),L.body&&(0,D.jsx)(`div`,{className:`mt-2 p-2 bg-background rounded text-xs whitespace-pre-wrap`,children:L.body})]}),(0,D.jsxs)(`div`,{className:`px-3 py-1 border-t`,children:[(0,D.jsx)(`div`,{className:`text-xs text-muted-foreground py-1`,children:ce?`Loading files...`:`${z.length} file${z.length===1?``:`s`} changed`}),z.map(e=>(0,D.jsxs)(`div`,{className:`flex items-center gap-2 py-0.5 text-xs hover:bg-muted/50 rounded px-1 cursor-pointer`,onClick:()=>H({type:`git-diff`,title:`Diff ${c(e.path)}`,closable:!0,metadata:{projectName:t,ref1:L.parents[0]??void 0,ref2:L.hash,filePath:e.path},projectId:t??null}),children:[(0,D.jsx)(`span`,{className:`flex-1 truncate font-mono`,children:e.path}),e.additions>0&&(0,D.jsxs)(`span`,{className:`text-green-500`,children:[`+`,e.additions]}),e.deletions>0&&(0,D.jsxs)(`span`,{className:`text-red-500`,children:[`-`,e.deletions]})]},e.path))]})]}),(0,D.jsx)(te,{open:N.type!==null,onOpenChange:e=>{e||P({type:null})},children:(0,D.jsxs)(g,{children:[(0,D.jsx)(re,{children:(0,D.jsx)(ee,{children:N.type===`branch`?`Create Branch`:`Create Tag`})}),(0,D.jsx)(i,{placeholder:N.type===`branch`?`Branch name`:`Tag name`,value:F,onChange:e=>I(e.target.value),onKeyDown:e=>{e.key===`Enter`&&F.trim()&&(N.type===`branch`?K(F.trim(),N.hash):q(F.trim(),N.hash),P({type:null}))},autoFocus:!0}),(0,D.jsxs)(ne,{children:[(0,D.jsx)(y,{variant:`outline`,onClick:()=>P({type:null}),children:`Cancel`}),(0,D.jsx)(y,{disabled:!F.trim(),onClick:()=>{N.type===`branch`?K(F.trim(),N.hash):q(F.trim(),N.hash),P({type:null})},children:`Create`})]})]})})]})}function se({label:e,color:t,currentBranch:n,onCheckout:r,onMerge:i,onPush:o,onCreatePr:s,onDelete:c}){return(0,D.jsxs)(ie,{children:[(0,D.jsx)(b,{asChild:!0,children:(0,D.jsxs)(`span`,{className:`inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] font-medium shrink-0 cursor-context-menu`,style:{backgroundColor:`${t}30`,color:t,border:`1px solid ${t}50`},children:[(0,D.jsx)(d,{className:`size-2.5`}),e.name]})}),(0,D.jsxs)(_,{children:[(0,D.jsx)(v,{onClick:()=>r(e.name),children:`Checkout`}),(0,D.jsxs)(v,{onClick:()=>i(e.name),disabled:e.name===n?.name,children:[(0,D.jsx)(w,{className:`size-3`}),`Merge into current`]}),(0,D.jsx)(x,{}),(0,D.jsxs)(v,{onClick:()=>o(e.name),children:[(0,D.jsx)(C,{className:`size-3`}),`Push`]}),(0,D.jsxs)(v,{onClick:()=>s(e.name),children:[(0,D.jsx)(a,{className:`size-3`}),`Create PR`]}),(0,D.jsx)(x,{}),(0,D.jsxs)(v,{variant:`destructive`,onClick:()=>c(e.name),disabled:e.name===n?.name,children:[(0,D.jsx)(S,{className:`size-3`}),`Delete`]})]})]})}export{j as GitGraph};
|