({
folderPath,
folderId,
onCommitted,
onCancel,
}: CommitWorkspaceProps)
| 220 | } |
| 221 | |
| 222 | export function CommitWorkspace({ |
| 223 | folderPath, |
| 224 | folderId, |
| 225 | onCommitted, |
| 226 | onCancel, |
| 227 | }: CommitWorkspaceProps) { |
| 228 | const t = useTranslations("Folder.commitDialog") |
| 229 | const tCommon = useTranslations("Folder.common") |
| 230 | const { withCredentialRetry } = useGitCredential() |
| 231 | const [entries, setEntries] = useState<GitStatusEntry[]>([]) |
| 232 | const containerRef = useRef<HTMLDivElement>(null) |
| 233 | const [containerWidth, setContainerWidth] = useState(0) |
| 234 | const [selected, setSelected] = useState<Set<string>>(new Set()) |
| 235 | const [diffOriginal, setDiffOriginal] = useState("") |
| 236 | const [diffModified, setDiffModified] = useState("") |
| 237 | const [diffLanguage, setDiffLanguage] = useState("plaintext") |
| 238 | const [diffFile, setDiffFile] = useState<string | null>(null) |
| 239 | const messageRef = useRef("") |
| 240 | const [hasMessage, setHasMessage] = useState(false) |
| 241 | const [messageInputKey, setMessageInputKey] = useState(0) |
| 242 | const [loadingStatus, setLoadingStatus] = useState(false) |
| 243 | const [loadingDiff, setLoadingDiff] = useState(false) |
| 244 | const [committing, setCommitting] = useState(false) |
| 245 | const [error, setError] = useState<string | null>(null) |
| 246 | const [untrackedOpen, setUntrackedOpen] = useState(false) |
| 247 | const [expandedTrackedDirs, setExpandedTrackedDirs] = useState<Set<string>>( |
| 248 | new Set() |
| 249 | ) |
| 250 | const [expandedUntrackedDirs, setExpandedUntrackedDirs] = useState< |
| 251 | Set<string> |
| 252 | >(new Set()) |
| 253 | const [confirm, setConfirm] = useState<ConfirmState>(CONFIRM_INITIAL) |
| 254 | |
| 255 | // Use refs to track mutable values without causing callback recreation |
| 256 | const diffFileRef = useRef(diffFile) |
| 257 | diffFileRef.current = diffFile |
| 258 | const entriesRef = useRef(entries) |
| 259 | entriesRef.current = entries |
| 260 | |
| 261 | const folderName = useMemo(() => { |
| 262 | const parts = folderPath.replace(/[/\\]+$/, "").split(/[/\\]/) |
| 263 | return parts[parts.length - 1] || folderPath |
| 264 | }, [folderPath]) |
| 265 | |
| 266 | const trackedEntries = useMemo( |
| 267 | () => entries.filter((entry) => entry.status !== UNTRACKED_STATUS), |
| 268 | [entries] |
| 269 | ) |
| 270 | const untrackedEntries = useMemo( |
| 271 | () => entries.filter((entry) => entry.status === UNTRACKED_STATUS), |
| 272 | [entries] |
| 273 | ) |
| 274 | const trackedTree = useMemo( |
| 275 | () => buildFileTree(trackedEntries), |
| 276 | [trackedEntries] |
| 277 | ) |
| 278 | const untrackedTree = useMemo( |
| 279 | () => buildFileTree(untrackedEntries), |
nothing calls this directly
no test coverage detected