Function bodies 465 total
elementOuterHeight function · typescript · L25-L31 (7 LOC)src/components/FileExplorer.tsx
function elementOuterHeight(el: HTMLElement): number {
const rect = el.getBoundingClientRect();
const style = window.getComputedStyle(el);
const marginTop = Number.parseFloat(style.marginTop) || 0;
const marginBottom = Number.parseFloat(style.marginBottom) || 0;
return rect.height + marginTop + marginBottom;
}computeRepoInsertIndex function · typescript · L33-L60 (28 LOC)src/components/FileExplorer.tsx
function computeRepoInsertIndex(
orderedPaths: string[],
draggedPath: string,
cardRefs: Map<string, HTMLDivElement>,
pointerY: number,
): number {
if (orderedPaths.length <= 1) return 0;
const dragIdx = orderedPaths.indexOf(draggedPath);
let insertionIndex = 0;
for (let i = 0; i < orderedPaths.length; i++) {
const path = orderedPaths[i];
if (path === draggedPath) continue;
const el = cardRefs.get(path);
if (!el) continue;
const rect = el.getBoundingClientRect();
const threshold = Math.min(rect.height * 0.2, 28);
// Direction-aware: swap triggers when pointer enters the NEAR edge
// of each card. Cards above → use bottom edge; cards below → use top edge.
const crossLine =
i < dragIdx
? rect.bottom - threshold // dragging UP past this card
: rect.top + threshold; // dragging DOWN past this card
if (pointerY > crossLine) {
insertionIndex++;
}
}
return clamp(insertionIndex, 0, orderedPaths.length - saveExpandedPaths function · typescript · L74-L79 (6 LOC)src/components/FileExplorer.tsx
function saveExpandedPaths() {
localStorage.setItem(
"rally:expandedPaths",
JSON.stringify([...expandedPaths]),
);
}getExpandedPaths function · typescript · L82-L84 (3 LOC)src/components/FileExplorer.tsx
export function getExpandedPaths(): string[] {
return [...expandedPaths];
}setExpandedPaths function · typescript · L92-L106 (15 LOC)src/components/FileExplorer.tsx
export function setExpandedPaths(paths: string[], roots?: string[]): void {
if (roots && roots.length > 0) {
// Remove only paths belonging to the specified roots, then add the new ones
for (const ep of [...expandedPaths]) {
if (roots.some((r) => ep === r || ep.startsWith(r + "/"))) {
expandedPaths.delete(ep);
}
}
} else {
expandedPaths.clear();
}
for (const p of paths) expandedPaths.add(p);
saveExpandedPaths();
document.dispatchEvent(new Event("rally:expanded-paths-changed"));
}fetchGitIgnored function · typescript · L133-L142 (10 LOC)src/components/FileExplorer.tsx
function fetchGitIgnored(dirPath: string) {
api.listGitignored(dirPath)
.then((names) => {
gitIgnoredCache.set(dirPath, new Set(names));
})
.catch(() => {
// Not a git repo or error — no ignored files
gitIgnoredCache.set(dirPath, new Set());
});
}notifySelectionListeners function · typescript · L148-L151 (4 LOC)src/components/FileExplorer.tsx
function notifySelectionListeners() {
for (const cb of selectionListeners) cb();
document.dispatchEvent(new Event("rally:selection-change"));
}Repobility · code-quality intelligence · https://repobility.com
subscribeSelection function · typescript · L153-L156 (4 LOC)src/components/FileExplorer.tsx
function subscribeSelection(cb: () => void) {
selectionListeners.add(cb);
return () => { selectionListeners.delete(cb); };
}toggleSelectedFilePath function · typescript · L158-L171 (14 LOC)src/components/FileExplorer.tsx
function toggleSelectedFilePath(path: string, additive: boolean) {
if (additive) {
const next = new Set(selectedFilePaths);
if (next.has(path)) {
next.delete(path);
} else {
next.add(path);
}
selectedFilePaths = next;
} else {
selectedFilePaths = new Set([path]);
}
notifySelectionListeners();
}clearSelectedFilePaths function · typescript · L173-L176 (4 LOC)src/components/FileExplorer.tsx
function clearSelectedFilePaths() {
selectedFilePaths = new Set();
notifySelectionListeners();
}useIsSelected function · typescript · L179-L184 (6 LOC)src/components/FileExplorer.tsx
function useIsSelected(path: string): boolean {
return useSyncExternalStore(
subscribeSelection,
() => selectedFilePaths.has(path),
);
}useSelectedFilePaths function · typescript · L187-L196 (10 LOC)src/components/FileExplorer.tsx
function useSelectedFilePaths() {
const [, setTick] = useState(0);
useEffect(() => {
const handler = () => setTick((t) => t + 1);
document.addEventListener("rally:selection-change", handler);
return () =>
document.removeEventListener("rally:selection-change", handler);
}, []);
return selectedFilePaths;
}subscribeDropTarget function · typescript · L204-L207 (4 LOC)src/components/FileExplorer.tsx
function subscribeDropTarget(cb: () => void) {
dropTargetListeners.add(cb);
return () => { dropTargetListeners.delete(cb); };
}setDropTarget function · typescript · L209-L213 (5 LOC)src/components/FileExplorer.tsx
function setDropTarget(path: string | null) {
if (dropTargetPath === path) return;
dropTargetPath = path;
for (const cb of dropTargetListeners) cb();
}useIsDropTarget function · typescript · L215-L220 (6 LOC)src/components/FileExplorer.tsx
function useIsDropTarget(path: string): boolean {
return useSyncExternalStore(
subscribeDropTarget,
() => dropTargetPath === path,
);
}Powered by Repobility — scan your code at https://repobility.com
subscribeInlineEdit function · typescript · L260-L263 (4 LOC)src/components/FileExplorer.tsx
function subscribeInlineEdit(cb: () => void) {
inlineEditListeners.add(cb);
return () => { inlineEditListeners.delete(cb); };
}setInlineEdit function · typescript · L265-L278 (14 LOC)src/components/FileExplorer.tsx
function setInlineEdit(state: InlineEditState) {
inlineEdit = state;
inlineEditVersion++;
// When clearing, set a brief cooldown to prevent the global Enter handler
// from immediately re-entering rename mode in the same event cycle
if (state === null) {
inlineEditCooldown = true;
setTimeout(() => {
inlineEditCooldown = false;
}, 50);
}
for (const cb of inlineEditListeners) cb();
document.dispatchEvent(new Event("rally:inline-edit"));
}useIsRenaming function · typescript · L281-L286 (6 LOC)src/components/FileExplorer.tsx
function useIsRenaming(path: string): boolean {
return useSyncExternalStore(
subscribeInlineEdit,
() => inlineEdit?.type === "rename" && inlineEdit.path === path,
);
}useIsCreatingHere function · typescript · L289-L294 (6 LOC)src/components/FileExplorer.tsx
function useIsCreatingHere(parentPath: string): boolean {
return useSyncExternalStore(
subscribeInlineEdit,
() => inlineEdit?.type === "create" && inlineEdit.parentPath === parentPath,
);
}useInlineEdit function · typescript · L297-L305 (9 LOC)src/components/FileExplorer.tsx
function useInlineEdit() {
const [, setTick] = useState(0);
useEffect(() => {
const handler = () => setTick((t) => t + 1);
document.addEventListener("rally:inline-edit", handler);
return () => document.removeEventListener("rally:inline-edit", handler);
}, []);
return inlineEdit;
}relativePath function · typescript · L416-L420 (5 LOC)src/components/FileExplorer.tsx
function relativePath(filePath: string, rootPath: string): string {
return filePath.startsWith(rootPath)
? filePath.slice(rootPath.length).replace(/^\//, "")
: filePath;
}parentDir function · typescript · L422-L424 (3 LOC)src/components/FileExplorer.tsx
function parentDir(filePath: string): string {
return filePath.substring(0, filePath.lastIndexOf("/"));
}handleClone function · typescript · L1163-L1177 (15 LOC)src/components/FileExplorer.tsx
async function handleClone() {
if (!name.trim() || !activeWorkspaceId) return;
setCloning(true);
setError("");
try {
const newPath = await api.cloneRepo(sourcePath, name.trim());
await addPathToWorkspace(activeWorkspaceId, newPath);
useWorkspaceStore.getState().openTerminalInBottom(activeWorkspaceId, newPath);
onClose();
} catch (e: any) {
setError(typeof e === "string" ? e : (e.message ?? "Clone failed"));
} finally {
setCloning(false);
}
}Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
handleContextMenu function · typescript · L1416-L1485 (70 LOC)src/components/FileExplorer.tsx
function handleContextMenu(e: React.MouseEvent) {
e.preventDefault();
const actions: Parameters<typeof showContextMenu>[0] = [
{
label: "New File",
action: () =>
setInlineEdit({ type: "create", parentPath: rootPath, isDir: false }),
},
{
label: "New Folder",
action: () =>
setInlineEdit({ type: "create", parentPath: rootPath, isDir: true }),
},
"separator",
{
label: "New Script",
action: () =>
setInlineEdit({
type: "create",
parentPath: rootPath + "/scripts",
isDir: false,
template: "#!/bin/bash\n\n",
}),
},
{
label: "New Command",
action: () =>
setInlineEdit({
type: "create",
parentPath: rootPath + "/.claude/commands",
isDir: false,
template: "# Command Name\n\nDescribe what this command does.\n",
}),
},
ChangeStatusGlyph function · typescript · L1888-L1905 (18 LOC)src/components/FileExplorer.tsx
function ChangeStatusGlyph({ status }: { status: string }) {
const color = STATUS_COLORS[status] ?? "#888";
return (
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
<text
x="8"
y="11.4"
textAnchor="middle"
fill={color}
fontSize="11.5"
fontWeight="700"
fontFamily="-apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif"
>
{status}
</text>
</svg>
);
}SectionChevron function · typescript · L1907-L1926 (20 LOC)src/components/FileExplorer.tsx
function SectionChevron({ open }: { open: boolean }) {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
aria-hidden="true"
style={{ transform: open ? "rotate(90deg)" : "none" }}
>
<path
d="M4 2.4L8 6L4 9.6"
stroke="currentColor"
strokeWidth="1.3"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}StageActionGlyph function · typescript · L1928-L1964 (37 LOC)src/components/FileExplorer.tsx
function StageActionGlyph({ label }: { label: string }) {
if (label === "Stage") {
return (
<svg
width="13"
height="13"
viewBox="0 0 13 13"
fill="none"
aria-hidden="true"
>
<path
d="M6.5 2v9M2 6.5h9"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
);
}
return (
<svg
width="13"
height="13"
viewBox="0 0 13 13"
fill="none"
aria-hidden="true"
>
<path
d="M2 6.5h9"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
);
}DiscardActionGlyph function · typescript · L1966-L1984 (19 LOC)src/components/FileExplorer.tsx
function DiscardActionGlyph() {
return (
<svg
width="13"
height="13"
viewBox="0 0 13 13"
fill="none"
aria-hidden="true"
>
<path
d="M4 3.2V6h2.8M4 6c0-2.2 1.8-4 4-4a4 4 0 1 1-3.1 6.5"
stroke="currentColor"
strokeWidth="1.35"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}stageFile function · typescript · L2158-L2170 (13 LOC)src/components/FileExplorer.tsx
async function stageFile(filePath: string) {
try {
await api.gitStageFile(rootPath, filePath);
notifyChangesUpdated();
await refresh();
} catch (e) {
addToast({
type: "warning",
title: "Stage failed",
message: String(e),
});
}
}unstageFile function · typescript · L2171-L2183 (13 LOC)src/components/FileExplorer.tsx
async function unstageFile(filePath: string) {
try {
await api.gitUnstageFile(rootPath, filePath);
notifyChangesUpdated();
await refresh();
} catch (e) {
addToast({
type: "warning",
title: "Unstage failed",
message: String(e),
});
}
}discardFile function · typescript · L2184-L2197 (14 LOC)src/components/FileExplorer.tsx
async function discardFile(filePath: string, isUntracked: boolean) {
try {
await api.gitDiscardFile(rootPath, filePath, isUntracked);
notifyChangesUpdated();
if (selectedFile === filePath) setSelectedFile(null);
await refresh();
} catch (e) {
addToast({
type: "warning",
title: "Discard failed",
message: String(e),
});
}
}Repobility · severity-and-effort ranking · https://repobility.com
handleSelect function · typescript · L2199-L2206 (8 LOC)src/components/FileExplorer.tsx
function handleSelect(
path: string,
isUntracked: boolean,
section?: "staged" | "unstaged" | "untracked",
) {
setSelectedFile(path);
onSelectFile(path, isUntracked, section);
}derivePrFileStatus function · typescript · L2286-L2291 (6 LOC)src/components/FileExplorer.tsx
function derivePrFileStatus(file: DiffFile): string {
if (file.isNew) return "A";
if (file.isDeleted) return "D";
if (file.isRenamed) return "R";
return "M";
}LayoutPresetsDropdown function · typescript · L2376-L2709 (334 LOC)src/components/FileExplorer.tsx
function LayoutPresetsDropdown({ workspaceId }: { workspaceId: string }) {
const [open, setOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [name, setName] = useState("");
const dropdownRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const presets = useWorkspaceStore((s) => {
const arr = s.flightLayoutPresets?.[workspaceId];
return Array.isArray(arr) ? arr : EMPTY_PRESETS;
});
const activePresetId = useWorkspaceStore((s) => s.activeFlightPresetId[workspaceId]);
const activePreset = presets.find((p) => p.id === activePresetId);
const [renamingId, setRenamingId] = useState<string | null>(null);
const [renameValue, setRenameValue] = useState("");
const renameRef = useRef<HTMLInputElement>(null);
const [dragIdx, setDragIdx] = useState<number | null>(null);
const [overIdx, setOverIdx] = useState<number | null>(null);
const didDragRef = useRef(false);
const [noTransition, setNoTransitiohandleGitIconClick function · typescript · L3022-L3039 (18 LOC)src/components/FileExplorer.tsx
function handleGitIconClick(rootPath: string) {
// Select this path as active
if (ws) {
const idx = ws.paths.indexOf(rootPath);
if (idx >= 0) setActivePathIndex(ws.id, idx);
}
// Toggle the unified git panel's changes tab for this repo
const state = useWorkspaceStore.getState();
if (
state.unifiedGitPanelOpen &&
state.unifiedGitPanelPath === rootPath &&
state.unifiedGitPanelTab === "changes"
) {
state.closeUnifiedGitPanel();
} else {
state.openUnifiedGitPanel(rootPath, "changes");
}
}handleSelectFile function · typescript · L3041-L3057 (17 LOC)src/components/FileExplorer.tsx
function handleSelectFile(
rootPath: string,
filePath: string,
_isUntracked: boolean,
section?: "staged" | "unstaged" | "untracked",
) {
// Set the active tab (staged vs unstaged) and scroll-to-file before opening
const store = useWorkspaceStore.getState();
if (section === "staged") {
store.setGitDiffActiveTab("staged");
} else {
store.setGitDiffActiveTab("unstaged");
}
// Set scroll-to-file so GitDiffContent can pick it up
useWorkspaceStore.setState({ gitDiffScrollToFile: filePath });
openUnifiedGitPanel(rootPath, "changes");
}handleSelectPrFile function · typescript · L3059-L3063 (5 LOC)src/components/FileExplorer.tsx
function handleSelectPrFile(rootPath: string, filePath: string) {
// Set scroll-to-file so PrReviewContent can pick it up, then open PR tab
useWorkspaceStore.setState({ prReviewScrollToFile: filePath });
openUnifiedGitPanel(rootPath, "pr");
}ChevronIcon function · typescript · L4-L21 (18 LOC)src/components/FileIcons.tsx
export function ChevronIcon({ open }: { open: boolean }) {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="currentColor"
style={{
flexShrink: 0,
color: "var(--text-dim)",
transform: open ? "rotate(90deg)" : "rotate(0deg)",
transition: "transform 0.1s ease",
}}
>
<path d="M6 4l4 4-4 4z" />
</svg>
);
}getFileTypeInfo function · typescript · L32-L72 (41 LOC)src/components/FileIcons.tsx
function getFileTypeInfo(name: string): FileTypeInfo | null {
const lower = name.toLowerCase();
if (lower.endsWith(".ts") || lower.endsWith(".tsx"))
return { label: "TS", color: "#3178C6" };
if (lower.endsWith(".js") || lower.endsWith(".jsx"))
return { label: "JS", color: "#F0DB4F" };
if (lower.endsWith(".rs")) return { label: "RS", color: "#DEA584" };
if (lower.endsWith(".py")) return { label: "PY", color: "#3572A5" };
if (lower.endsWith(".go")) return { label: "GO", color: "#00ADD8" };
if (lower.endsWith(".json")) return { label: "{ }", color: "#A8B065" };
if (lower.endsWith(".md")) return { label: "M↓", color: "#519ABA" };
if (lower.endsWith(".css") || lower.endsWith(".scss"))
return { label: "CSS", color: "#56B6C2", compact: true };
if (lower.endsWith(".html") || lower.endsWith(".htm"))
return { label: "</>", color: "#E37933" };
if (lower.endsWith(".yaml") || lower.endsWith(".yml"))
return { label: "YML", color: "#CB171E", compact: true };
Repobility · code-quality intelligence · https://repobility.com
getFileColor function · typescript · L74-L77 (4 LOC)src/components/FileIcons.tsx
function getFileColor(name: string): string {
const info = getFileTypeInfo(name);
return info?.color ?? "var(--text-dim)";
}FileTypeLabel function · typescript · L82-L110 (29 LOC)src/components/FileIcons.tsx
function FileTypeLabel({
info,
size,
}: {
info: FileTypeInfo;
size: number;
}) {
const fontSize = info.compact ? size * 0.55 : size * 0.62;
return (
<span
style={{
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
width: size,
height: size,
fontSize,
fontWeight: 800,
color: info.color,
fontFamily: "system-ui, -apple-system, sans-serif",
lineHeight: 1,
flexShrink: 0,
letterSpacing: info.compact ? -0.5 : 0,
}}
>
{info.label}
</span>
);
}FileIcon function · typescript · L115-L129 (15 LOC)src/components/FileIcons.tsx
export function FileIcon({
name,
isDir,
isOpen,
}: {
name: string;
isDir: boolean;
isOpen?: boolean;
}) {
if (isDir) return <FolderIcon open={isOpen} />;
if (isScriptFile(name)) return <TerminalPromptIcon size={16} />;
const info = getFileTypeInfo(name);
if (info) return <FileTypeLabel info={info} size={16} />;
return <DocumentIcon color="var(--text-dim)" />;
}FolderIcon function · typescript · L131-L148 (18 LOC)src/components/FileIcons.tsx
function FolderIcon({ open }: { open?: boolean }) {
// Matches icons8 folder style: rounded rect with a small smooth tab
const d = open
? "M3 4C3 3.17 3.67 2.5 4.5 2.5H8L9.5 4H12.5C13.33 4 14 4.67 14 5.5V6H4.5L3 12H12.5C13.33 12 14 11.33 14 10.5V6"
: "M3 4C3 3.17 3.67 2.5 4.5 2.5H8L9.5 4H12.5C13.33 4 14 4.67 14 5.5V11C14 11.83 13.33 12.5 12.5 12.5H4.5C3.67 12.5 3 11.83 3 11Z";
return (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" style={svgIconStyle}>
<path
d={d}
stroke="var(--text-dim)"
strokeWidth="1.3"
strokeLinejoin="round"
strokeLinecap="round"
fill="none"
/>
</svg>
);
}isScriptFile function · typescript · L150-L153 (4 LOC)src/components/FileIcons.tsx
function isScriptFile(name: string): boolean {
const lower = name.toLowerCase();
return lower.endsWith(".sh") || lower.endsWith(".bash") || lower.endsWith(".zsh");
}DocumentIcon function · typescript · L176-L189 (14 LOC)src/components/FileIcons.tsx
function DocumentIcon({ color }: { color: string }) {
return (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" style={svgIconStyle}>
<path
d="M4 1.5h5.5L13 5v9.5H4z"
stroke={color}
strokeWidth="1"
fill="none"
opacity={0.8}
/>
<path d="M9.5 1.5V5H13" stroke={color} strokeWidth="1" opacity={0.8} />
</svg>
);
}GlobeTabIcon function · typescript · L197-L205 (9 LOC)src/components/FileIcons.tsx
function GlobeTabIcon() {
return (
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" style={{ flexShrink: 0 }}>
<circle cx="8" cy="8" r="5.5" stroke="var(--text-dim)" strokeWidth="1.2" fill="none" />
<ellipse cx="8" cy="8" rx="2.8" ry="5.5" stroke="var(--text-dim)" strokeWidth="1.2" fill="none" />
<line x1="2.5" y1="8" x2="13.5" y2="8" stroke="var(--text-dim)" strokeWidth="1.2" />
</svg>
);
}PaneTabIcon function · typescript · L208-L235 (28 LOC)src/components/FileIcons.tsx
export function PaneTabIcon({
type,
fileName,
terminalTitle,
}: {
type: string;
fileName?: string;
terminalTitle?: string;
}) {
if (type === "claude" || type === "claude-launcher") return <ClaudeTabIcon />;
if (type === "terminal") {
if (terminalTitle) {
const lower = terminalTitle.toLowerCase();
if (lower === "claude" || lower.startsWith("claude "))
return <ClaudeTabIcon />;
}
return <TerminalTabIcon />;
}
if (type === "webview") return <GlobeTabIcon />;
if (type === "diff") return <DiffTabIcon />;
if (type === "editor" && fileName) {
if (isScriptFile(fileName)) return <TerminalPromptIcon size={16} />;
const info = getFileTypeInfo(fileName);
if (info) return <FileTypeLabel info={info} size={16} />;
return <SmallDocIcon color={getFileColor(fileName)} />;
}
return <SmallDocIcon color="var(--text-dim)" />;
}Powered by Repobility — scan your code at https://repobility.com
ClaudeTabIcon function · typescript · L240-L251 (12 LOC)src/components/FileIcons.tsx
function ClaudeTabIcon() {
return (
<svg
width="14"
height="14"
viewBox="-2 -1 28 26"
style={{ flexShrink: 0 }}
>
<path d={CLAUDE_PATH} fill="#D97757" fillRule="nonzero" />
</svg>
);
}TerminalTabIcon function · typescript · L253-L272 (20 LOC)src/components/FileIcons.tsx
function TerminalTabIcon() {
return (
<svg width="16" height="16" viewBox="0 0 14 14" style={{ flexShrink: 0 }}>
<path
d="M2.5 3.5L6 7L2.5 10.5"
stroke="var(--status-green)"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
/>
<path
d="M7.5 10.5H11.5"
stroke="var(--status-green)"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
);
}DiffTabIcon function · typescript · L274-L301 (28 LOC)src/components/FileIcons.tsx
function DiffTabIcon() {
return (
<svg width="16" height="16" viewBox="0 0 14 14" style={{ flexShrink: 0 }}>
<rect
x="1.5"
y="2"
width="4.5"
height="10"
rx="1"
stroke="#5ba0d0"
strokeWidth="1"
fill="none"
opacity={0.8}
/>
<rect
x="8"
y="2"
width="4.5"
height="10"
rx="1"
stroke="#e8b930"
strokeWidth="1"
fill="none"
opacity={0.8}
/>
</svg>
);
}