commits
The view-mode switcher offered overview vs. split, but the diff panel is
core to the desktop client, so the overview-only branch was dead weight.
Drop the mode concept entirely (atom, type, persisted layout field on
both TS and Rust sides, navigation hook view-mode coupling, and the
1/2 keyboard shortcuts) and always render the split layout.
Move the workspace switcher, revision search, and sync into the
revisions sidebar so the AppHeader can go away. The macOS title bar
handles window dragging now that the in-app drag region is gone.
Drop the StatusBar — its theme toggle now lives as Light/Dark/System
entries under the new Appearance group in the command palette. The
shortcut help button is redundant since the ? key already opens the
help dialog. Closest-bookmark BFS and the working-copy status query
were only feeding the StatusBar, so they go too.
Empty state keeps just the workspace switcher above the EmptyState card.
Refactor revision diff and changed-file payloads out of TanStack DB collections and into TanStack Query resources:
- replace unified diff/change DB collections with Query-backed hooks in useRevisionData
- use canonical query keys for revision diff and revision changed-file payloads
- keep batch IPC prefetching, but write fetched payloads directly into Query cache
- update DiffPanel to consume diff payloads from the same Query key it retries/refetches
- remove obsolete per-revision and unified diff/change collection modules and exports
- keep watcher invalidation focused on Query prefixes plus operation/revision collections
- update data-loading tests to assert Query-cache prefetch behavior instead of collection creation
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
- cd apps/desktop && bun run build
Refactor revision mutation helpers to use TanStack DB createOptimisticAction transactions for edit/new/abandon/describe/squash/rebase flows while preserving the existing public @/db API.
Details:
- Keep the preallocated change-id pool for instant jj new rows.
- Move optimistic row edits/deletes/inserts into synchronous action onMutate handlers.
- Refetch the revisions collection before transaction persistence completes so optimistic state can be safely reconciled with authoritative jj data.
- Continue tracking in-flight mutation IDs so repository watcher events do not stomp optimistic state.
- Reconcile returned jj operation IDs with the first-class operations collection and preserve undo toasts.
- Keep compatibility with existing lightweight mutation tests while production collections use native TanStack DB transaction methods.
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
- cd apps/desktop && bun run build
- Add a TanStack DB operations collection keyed by jj operation id, with cached per-repository collection instances and an empty fallback collection.
- Add operation invalidation/reconciliation helpers so mutation results can refresh operation-log state around returned operation_id values.
- Wire repository watcher invalidation and revision/sync mutation success paths through operation reconciliation.
- Move the OperationsLog dialog from direct TanStack Query use to the new operations collection while preserving refresh and undo behavior.
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
Split the monolithic frontend db.ts into focused data modules while preserving the public @/db barrel API:
- data/query-client.ts owns the shared TanStack Query client.
- data/mutation-tracker.ts owns in-flight mutation tracking.
- data/change-id-pool.ts owns preallocated jj change IDs.
- data/watchers.ts owns repository watcher ref-counting and query invalidation.
- data/actions/repo-actions.ts owns repository sync behavior.
- data/collections/* owns TanStack DB collections for repositories, revisions, revision changes, revision diffs, commit recency, and unified diff/change records.
- data/prefetch.ts owns revision diff/change prefetch helpers.
No call sites were changed; existing imports continue to use @/db, which now re-exports from the new module structure.
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
Upgrade the TanStack data stack to the latest versions identified during planning:
- @tanstack/db 0.5.15 -> 0.6.5
- @tanstack/react-db 0.1.59 -> 0.1.83
- @tanstack/query-db-collection 1.0.11 -> 1.0.36
- @tanstack/react-query 5.90.12 -> 5.100.5
- @tanstack/query-core 5.90.12 -> 5.100.5
This keeps the current data-layer behavior unchanged while moving the dependency baseline forward for the upcoming TanStack DB refactor. bun.lock was regenerated with Bun after updating apps/desktop/package.json.
Also clean up the existing frontend lint blockers so the upgraded baseline validates cleanly:
- Format files that Biome reported as stale.
- Add explicit lint suppressions for intentional tracing console output, mount-only scroll restoration, debounced effects, and local UI state cases covered by project ast-grep rules.
- Fix accessibility warnings around unsupported aria-label usage and the settings checkbox label.
- Apply the mock layout const cleanup.
Validation:
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run test
- cd apps/desktop && bun run build
Add an InlineEditor wrapper around CodeMirror 6 with two visual
variants:
- transparent: looks like plain text, border on focus, saves on blur
if content changed
- bordered: autoFocus + select-all on mount, modal-style border, used
for compact pop-up editing
Both bind Cmd/Ctrl+Enter to save and Escape to revert+blur. The editor
stops keydown bubbling so the global keymap doesn't fire while the user
is typing.
Used in two places:
- RevisionRow's inline edit mode (replaces the textarea)
- RevisionHeader in the diff panel (replaces the chevron-expand readonly
block; the field is now always editable except for immutable
revisions)
Plumb onDescribe through DiffPanel/PrerenderedDiffPanel so the header
can write back. RevisionRow keeps a lastSavedDescRef so the saved text
shows immediately, ahead of the collection update round-trip.
useKeyboard's input-focus guard now also skips contenteditable elements
(CodeMirror uses contenteditable), factored into a shared
isEditableElementFocused() helper.
Adds @codemirror/{commands,language,state,view} and codemirror.
- Add EmptyState welcome card with quick-start guidance (open repo, j/k nav, ? shortcuts)
- Add ? hint badge in StatusBar that opens keyboard shortcuts help
- Wrap AppHeader sync/search buttons with Tooltip components showing shortcuts
- Organize CommandPalette into Repository/Tools/App groups with shortcut hints
- Add missing d (describe) and a (abandon) shortcuts to KeyboardShortcutsHelp
- Fix shortcut key labels for consistency (⌘ K, ⌘ ,)
Remove all disabled lineage/dimming calculations from 3 frontend files:
- db.ts: removed LineageRecord interface, commented collection, disabled invalidation
- useRevisionData.ts: removed createLineageLoader, lineageLoaders cache, getLineageLoader
- revision-graph/index.tsx: removed all DISABLED comments and commented-out lineage blocks
Backend lineage commands (tauri-commands.ts) kept for potential re-enablement.
Stub functions (useLineage, prefetchLineage, flushLineage) retained as clean no-ops.
cmdk doesn't support controlled search state, so to debounce filtering:
1. Disable cmdk's built-in filter with shouldFilter={false}
2. Use useDeferredValue to defer the search value
3. Do our own filtering/sorting in useMemo with the deferred value
This allows the input to remain responsive while filtering is deferred.
- Rename AceJump.tsx → Search.tsx and update component name/props
- Rename aceJumpOpenAtom → searchOpenAtom in atoms.ts
- Rename inlineJumpQueryAtom → aceJumpQueryAtom (this is the actual AceJump feature)
- Update all imports and usages in AppShell.tsx and revision-graph/index.tsx
- Update KeyboardShortcutsHelp descriptions
- Add 150ms debounce to search input to prevent lag while typing
- Update TAT-sjxoqgfa issue title to reference Search instead of AceJump
- Add MutationResult type returning operation_id from all mutations
- Add Operation type for operation log entries
- Add list_operations() and undo_operation() using jj-lib op revert
- Add Undo button to abandon toast that reverts the operation
- Export getOperations() and undoOperation() Tauri commands
- Add sonner package and Toaster component with macOS-native styling
- Show success toasts for edit, new, and abandon operations
- Style toasts with translucent background, backdrop blur, themed colors
- Add useFocusWithin hook using focusin/focusout events
- Remove focusPanelAtom from atoms.ts
- Update useDiffPanelKeyboard to use hasFocus prop and call .focus() for panel switching
- Update useRevisionGraphNavigation to use hasFocus prop and call .focus() for panel switching
- Update FileList to accept hasFocus prop instead of reading from atom
- Update RevisionRow to remove manual setFocusPanel calls
- Update DiffPanel and RevisionGraph to use useFocusWithin with tabIndex={-1}
- Update AppShell to create and pass panel refs for cross-panel focus transfer
This simplifies focus management by relying on native browser focus instead of manual state tracking.
Refactor DiffPanel to use a split-pane layout for better file navigation:
- Add FileList component with tree/flat view toggle and search filtering
- Add SingleFileDiff component for isolated file diff rendering
- Left panel shows changed files with status icons (added/modified/deleted)
- Right panel shows diff for selected file
- Tree view collapses single-child directories (e.g., apps/desktop/src)
- Keyboard navigation (j/k, arrows) in file list
- Per-file diff style toggle (unified/split) in toolbar
- Make RevisionHeader commit body collapsible
- Add sticky header styling for diff sections
- Auto-select first file when revision changes
- Display total additions/deletions summary
Add comprehensive skills for Claude to reference when working with Tauri:
- Project setup and configuration
- Frontend integration (Vite, Next.js, Nuxt, SvelteKit, Qwik)
- IPC and events communication
- Plugin development
- Security (capabilities, permissions, CSP, scopes)
- Deployment (macOS, Linux, GitHub Actions)
- Debugging and testing
- Binary optimization
- Add zoomHotkeysEnabled to main window config
- Add core:webview:allow-set-webview-zoom permission
- AceJump: use useDeferredValue for filtering debounce, simplify state reset
- ChangedFilesList: convert FileRow to use button element for better a11y
- KeyboardShortcutsHelp: increase dialog width, improve layout
- vite.config: add agentation plugin
Add focusPanelAtom to track which panel has focus in split view mode.
- l/ArrowRight in revision graph moves focus to diff panel
- h/ArrowLeft in diff panel moves focus back to revisions
- j/k navigation in diff panel cycles through changed files
- Visual ring indicator shows which panel has focus
Also adds hoveredStackIdAtom for coordinated stack edge highlighting.
When expanding a collapsed stack, edges were incorrectly still rendered as
dotted because revisions could match two overlapping conditions:
- Part of an expanded stack (should take priority)
- Top of a collapsed nested stack (was incorrectly winning)
The fix checks expanded stack membership first, then applies collapsed stack
logic only if the revision is not in an expanded stack. This ensures edges
within expanded stacks render as solid lines.
Add data-* attributes to various components for easier testing and debugging:
- ChangedFilesList: data-focused, data-checked, data-file-path
- DiffPanel: data-selected, data-file-path
- RevisionGraph: data-focused, data-selected, data-checked, data-expanded,
data-change-id on revision cards; data-focused, data-stack-id on stacks
Add support for optimistic UI updates when creating new revisions:
- Add generate_change_ids Tauri command to pre-allocate change IDs from jj-lib
- Add change ID pool in db.ts that pre-fetches IDs and refills when running low
- Update jjNew to accept optional pre-allocated change ID
- newRevision now creates optimistic revision immediately, reverts on failure
- Add ensureChangeIdPool/ensureRepositories for router preloading
- Update mocks to support the new flow
The ResizableHandle component relied on data-[panel-group-direction=vertical]
selectors which don't work because react-resizable-panels doesn't propagate
the direction attribute to child components.
Add explicit orientation prop to ResizableHandle and pass it from AppShell
based on isNarrowScreen state. The vertical handle now renders with proper
height (h-2) and visible background.
Remove the stack view (s shortcut) feature for now, to be reimplemented later.
- Remove stackViewChangeIdAtom from atoms.ts
- Delete StackIndicator.tsx component
- Remove stack view related code from AppShell.tsx
- Remove customRevset parameter from db.ts collections
- Simplify abandonRevision function signature
- Remove s shortcut from KeyboardShortcutsHelp
Reorder branches so that edges from branch commits to their trunk merge-base
don't visually cross through unrelated branches. Branches are now sorted by:
1. Working copy's branch always first
2. Trunk merge-base position (earlier = first)
3. Recency (most recently touched first)
4. Change ID (stable tiebreaker)
Also simplifies DiffPanel component and updates atoms.
- Add multi-select support with checkboxes for revision graph
- Improve collapsed stack UI with stacked card animation
- Add ast-grep rules (migrate from .grit files)
- Add no-direct-tauri-mutations lint rule
- Add livestore Tauri adapter and sync infrastructure
- Refactor db.ts to use collections with prefetching
- Add checkbox UI component
- Improve browser-only mocks for dev mode
- Various UI polish and cleanup
The view-mode switcher offered overview vs. split, but the diff panel is
core to the desktop client, so the overview-only branch was dead weight.
Drop the mode concept entirely (atom, type, persisted layout field on
both TS and Rust sides, navigation hook view-mode coupling, and the
1/2 keyboard shortcuts) and always render the split layout.
Move the workspace switcher, revision search, and sync into the
revisions sidebar so the AppHeader can go away. The macOS title bar
handles window dragging now that the in-app drag region is gone.
Drop the StatusBar — its theme toggle now lives as Light/Dark/System
entries under the new Appearance group in the command palette. The
shortcut help button is redundant since the ? key already opens the
help dialog. Closest-bookmark BFS and the working-copy status query
were only feeding the StatusBar, so they go too.
Empty state keeps just the workspace switcher above the EmptyState card.
Refactor revision diff and changed-file payloads out of TanStack DB collections and into TanStack Query resources:
- replace unified diff/change DB collections with Query-backed hooks in useRevisionData
- use canonical query keys for revision diff and revision changed-file payloads
- keep batch IPC prefetching, but write fetched payloads directly into Query cache
- update DiffPanel to consume diff payloads from the same Query key it retries/refetches
- remove obsolete per-revision and unified diff/change collection modules and exports
- keep watcher invalidation focused on Query prefixes plus operation/revision collections
- update data-loading tests to assert Query-cache prefetch behavior instead of collection creation
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
- cd apps/desktop && bun run build
Refactor revision mutation helpers to use TanStack DB createOptimisticAction transactions for edit/new/abandon/describe/squash/rebase flows while preserving the existing public @/db API.
Details:
- Keep the preallocated change-id pool for instant jj new rows.
- Move optimistic row edits/deletes/inserts into synchronous action onMutate handlers.
- Refetch the revisions collection before transaction persistence completes so optimistic state can be safely reconciled with authoritative jj data.
- Continue tracking in-flight mutation IDs so repository watcher events do not stomp optimistic state.
- Reconcile returned jj operation IDs with the first-class operations collection and preserve undo toasts.
- Keep compatibility with existing lightweight mutation tests while production collections use native TanStack DB transaction methods.
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
- cd apps/desktop && bun run build
- Add a TanStack DB operations collection keyed by jj operation id, with cached per-repository collection instances and an empty fallback collection.
- Add operation invalidation/reconciliation helpers so mutation results can refresh operation-log state around returned operation_id values.
- Wire repository watcher invalidation and revision/sync mutation success paths through operation reconciliation.
- Move the OperationsLog dialog from direct TanStack Query use to the new operations collection while preserving refresh and undo behavior.
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
Split the monolithic frontend db.ts into focused data modules while preserving the public @/db barrel API:
- data/query-client.ts owns the shared TanStack Query client.
- data/mutation-tracker.ts owns in-flight mutation tracking.
- data/change-id-pool.ts owns preallocated jj change IDs.
- data/watchers.ts owns repository watcher ref-counting and query invalidation.
- data/actions/repo-actions.ts owns repository sync behavior.
- data/collections/* owns TanStack DB collections for repositories, revisions, revision changes, revision diffs, commit recency, and unified diff/change records.
- data/prefetch.ts owns revision diff/change prefetch helpers.
No call sites were changed; existing imports continue to use @/db, which now re-exports from the new module structure.
Validation:
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run test
Upgrade the TanStack data stack to the latest versions identified during planning:
- @tanstack/db 0.5.15 -> 0.6.5
- @tanstack/react-db 0.1.59 -> 0.1.83
- @tanstack/query-db-collection 1.0.11 -> 1.0.36
- @tanstack/react-query 5.90.12 -> 5.100.5
- @tanstack/query-core 5.90.12 -> 5.100.5
This keeps the current data-layer behavior unchanged while moving the dependency baseline forward for the upcoming TanStack DB refactor. bun.lock was regenerated with Bun after updating apps/desktop/package.json.
Also clean up the existing frontend lint blockers so the upgraded baseline validates cleanly:
- Format files that Biome reported as stale.
- Add explicit lint suppressions for intentional tracing console output, mount-only scroll restoration, debounced effects, and local UI state cases covered by project ast-grep rules.
- Fix accessibility warnings around unsupported aria-label usage and the settings checkbox label.
- Apply the mock layout const cleanup.
Validation:
- cd apps/desktop && bun run lint
- cd apps/desktop && bun run typecheck
- cd apps/desktop && bun run test
- cd apps/desktop && bun run build
Add an InlineEditor wrapper around CodeMirror 6 with two visual
variants:
- transparent: looks like plain text, border on focus, saves on blur
if content changed
- bordered: autoFocus + select-all on mount, modal-style border, used
for compact pop-up editing
Both bind Cmd/Ctrl+Enter to save and Escape to revert+blur. The editor
stops keydown bubbling so the global keymap doesn't fire while the user
is typing.
Used in two places:
- RevisionRow's inline edit mode (replaces the textarea)
- RevisionHeader in the diff panel (replaces the chevron-expand readonly
block; the field is now always editable except for immutable
revisions)
Plumb onDescribe through DiffPanel/PrerenderedDiffPanel so the header
can write back. RevisionRow keeps a lastSavedDescRef so the saved text
shows immediately, ahead of the collection update round-trip.
useKeyboard's input-focus guard now also skips contenteditable elements
(CodeMirror uses contenteditable), factored into a shared
isEditableElementFocused() helper.
Adds @codemirror/{commands,language,state,view} and codemirror.
- Add EmptyState welcome card with quick-start guidance (open repo, j/k nav, ? shortcuts)
- Add ? hint badge in StatusBar that opens keyboard shortcuts help
- Wrap AppHeader sync/search buttons with Tooltip components showing shortcuts
- Organize CommandPalette into Repository/Tools/App groups with shortcut hints
- Add missing d (describe) and a (abandon) shortcuts to KeyboardShortcutsHelp
- Fix shortcut key labels for consistency (⌘ K, ⌘ ,)
Remove all disabled lineage/dimming calculations from 3 frontend files:
- db.ts: removed LineageRecord interface, commented collection, disabled invalidation
- useRevisionData.ts: removed createLineageLoader, lineageLoaders cache, getLineageLoader
- revision-graph/index.tsx: removed all DISABLED comments and commented-out lineage blocks
Backend lineage commands (tauri-commands.ts) kept for potential re-enablement.
Stub functions (useLineage, prefetchLineage, flushLineage) retained as clean no-ops.
cmdk doesn't support controlled search state, so to debounce filtering:
1. Disable cmdk's built-in filter with shouldFilter={false}
2. Use useDeferredValue to defer the search value
3. Do our own filtering/sorting in useMemo with the deferred value
This allows the input to remain responsive while filtering is deferred.
- Rename AceJump.tsx → Search.tsx and update component name/props
- Rename aceJumpOpenAtom → searchOpenAtom in atoms.ts
- Rename inlineJumpQueryAtom → aceJumpQueryAtom (this is the actual AceJump feature)
- Update all imports and usages in AppShell.tsx and revision-graph/index.tsx
- Update KeyboardShortcutsHelp descriptions
- Add 150ms debounce to search input to prevent lag while typing
- Update TAT-sjxoqgfa issue title to reference Search instead of AceJump
- Add MutationResult type returning operation_id from all mutations
- Add Operation type for operation log entries
- Add list_operations() and undo_operation() using jj-lib op revert
- Add Undo button to abandon toast that reverts the operation
- Export getOperations() and undoOperation() Tauri commands
- Add useFocusWithin hook using focusin/focusout events
- Remove focusPanelAtom from atoms.ts
- Update useDiffPanelKeyboard to use hasFocus prop and call .focus() for panel switching
- Update useRevisionGraphNavigation to use hasFocus prop and call .focus() for panel switching
- Update FileList to accept hasFocus prop instead of reading from atom
- Update RevisionRow to remove manual setFocusPanel calls
- Update DiffPanel and RevisionGraph to use useFocusWithin with tabIndex={-1}
- Update AppShell to create and pass panel refs for cross-panel focus transfer
This simplifies focus management by relying on native browser focus instead of manual state tracking.
Refactor DiffPanel to use a split-pane layout for better file navigation:
- Add FileList component with tree/flat view toggle and search filtering
- Add SingleFileDiff component for isolated file diff rendering
- Left panel shows changed files with status icons (added/modified/deleted)
- Right panel shows diff for selected file
- Tree view collapses single-child directories (e.g., apps/desktop/src)
- Keyboard navigation (j/k, arrows) in file list
- Per-file diff style toggle (unified/split) in toolbar
- Make RevisionHeader commit body collapsible
- Add sticky header styling for diff sections
- Auto-select first file when revision changes
- Display total additions/deletions summary
Add comprehensive skills for Claude to reference when working with Tauri:
- Project setup and configuration
- Frontend integration (Vite, Next.js, Nuxt, SvelteKit, Qwik)
- IPC and events communication
- Plugin development
- Security (capabilities, permissions, CSP, scopes)
- Deployment (macOS, Linux, GitHub Actions)
- Debugging and testing
- Binary optimization
Add focusPanelAtom to track which panel has focus in split view mode.
- l/ArrowRight in revision graph moves focus to diff panel
- h/ArrowLeft in diff panel moves focus back to revisions
- j/k navigation in diff panel cycles through changed files
- Visual ring indicator shows which panel has focus
Also adds hoveredStackIdAtom for coordinated stack edge highlighting.
When expanding a collapsed stack, edges were incorrectly still rendered as
dotted because revisions could match two overlapping conditions:
- Part of an expanded stack (should take priority)
- Top of a collapsed nested stack (was incorrectly winning)
The fix checks expanded stack membership first, then applies collapsed stack
logic only if the revision is not in an expanded stack. This ensures edges
within expanded stacks render as solid lines.
Add data-* attributes to various components for easier testing and debugging:
- ChangedFilesList: data-focused, data-checked, data-file-path
- DiffPanel: data-selected, data-file-path
- RevisionGraph: data-focused, data-selected, data-checked, data-expanded,
data-change-id on revision cards; data-focused, data-stack-id on stacks
Add support for optimistic UI updates when creating new revisions:
- Add generate_change_ids Tauri command to pre-allocate change IDs from jj-lib
- Add change ID pool in db.ts that pre-fetches IDs and refills when running low
- Update jjNew to accept optional pre-allocated change ID
- newRevision now creates optimistic revision immediately, reverts on failure
- Add ensureChangeIdPool/ensureRepositories for router preloading
- Update mocks to support the new flow
The ResizableHandle component relied on data-[panel-group-direction=vertical]
selectors which don't work because react-resizable-panels doesn't propagate
the direction attribute to child components.
Add explicit orientation prop to ResizableHandle and pass it from AppShell
based on isNarrowScreen state. The vertical handle now renders with proper
height (h-2) and visible background.
Remove the stack view (s shortcut) feature for now, to be reimplemented later.
- Remove stackViewChangeIdAtom from atoms.ts
- Delete StackIndicator.tsx component
- Remove stack view related code from AppShell.tsx
- Remove customRevset parameter from db.ts collections
- Simplify abandonRevision function signature
- Remove s shortcut from KeyboardShortcutsHelp
Reorder branches so that edges from branch commits to their trunk merge-base
don't visually cross through unrelated branches. Branches are now sorted by:
1. Working copy's branch always first
2. Trunk merge-base position (earlier = first)
3. Recency (most recently touched first)
4. Change ID (stable tiebreaker)
Also simplifies DiffPanel component and updates atoms.
- Add multi-select support with checkboxes for revision graph
- Improve collapsed stack UI with stacked card animation
- Add ast-grep rules (migrate from .grit files)
- Add no-direct-tauri-mutations lint rule
- Add livestore Tauri adapter and sync infrastructure
- Refactor db.ts to use collections with prefetching
- Add checkbox UI component
- Improve browser-only mocks for dev mode
- Various UI polish and cleanup