Commit graph

91 commits

Author SHA1 Message Date
Tristan Michael a0c183df82 Hide subtask counter when parent subtask shown
When "show subtasks" is enabled, the UI could display both the parent
subtask and its counter, leading to redundant information. Hide the
subtask counter under a parent subtask when the parent itself is shown
to reduce visual clutter and avoid duplicate counts.

This change ensures a cleaner presentation of tasks and subtasks by
preventing the counter from appearing alongside the visible parent
subtask.
if I drag a task in this mode, I would love to be able to drag it anywhere and have the task update its date

- Added `date: Date | null` to TaskGroup (null = Overdue or No Date, Date = the group's calendar day)
- Cross-group drops now update the task's due_date to the target group's date; preserves time-of-day when has_time is set; clears due_date when dropping into No Date
- Dropping INTO Overdue is still blocked (it's a computed group); dragging OUT of Overdue to any other group works
- Within-group drops still just reorder
Close open submenus when clicking outside

When submenu elements (like the kebab menu or workspace picker) were
open, clicking elsewhere in the app did not close them and allowed
interacting with underlying UI. This change adds a full-screen invisible
overlay element whenever either menu is open that captures outside
clicks and closes the menus, and removes the previous window-level
mousedown handler and related element bindings. This ensures that
clicking outside a submenu only closes it and prevents accidental
interactions with other parts of the app.
Prevent task clicks when closing dropdown menus

When the list menu or workspace picker is open, clicking outside should
close the menu but not also trigger underlying task click handlers. Add
a mouse down handler that closes dropdowns when clicking outside and a
capture-phase click handler that swallows the click immediately after a
menu close to avoid propagation to task elements. This avoids accidental
task activation right after closing a menu.
Prevent clicks reaching background when menus open

Stop clicks on the main task area from interacting with underlying
elements when the workspace picker or list menu are open. Previously a
global mousedown/click handler attempted to close menus and prevent a
single stray click from propagating; this change replaces that logic by
adding overlay divs inside the drawer and task list panels that capture
clicks and close the respective menus. This simplifies interaction
handling and fixes a bug where clicking menu items also triggered task
clicks.
the kebab menu calls the date on tasks a due date, but it's not a due date... it's just a date. can we make sure the codebase, documentation and everything is consistent about this?

- Renamed `due_date` field on Task struct to `date` (Rust, TypeScript, all usages)
- Renamed `group_by_due_date` field on TaskList/ListMetadata to `group_by_date`
- Renamed `set_group_by_due_date`/`get_group_by_due_date` methods to `set_group_by_date`/`get_group_by_date` in repository, Tauri commands, and JS store
- Renamed `with_due_date()` builder method to `with_date()`
- Renamed `parse_due_date` CLI function to `parse_date`
- Updated UI text "Group by due date" → "Group by date" in TasksScreen.svelte kebab menu
- Renamed JS variables `dueDate`/`dueDateHasTime` → `date`/`dateHasTime` in NewTaskInput.svelte
- Updated all test names and assertions across models.rs and repository.rs
- Updated CLAUDE.md documentation to use "date" terminology consistently
2026-04-14 06:51:56 -07:00
Tristan Michael f98f8492b5 Group pending tasks by due date
Add grouping of pending tasks into Overdue/Today/Tomorrow/This
Week/Later/No Date buckets when the active list has group_by_due_date
enabled. This provides a grouped view in TasksScreen (section headers,
no drag-and-drop) and a new derived store groupedPendingTasks exported
from the app store to supply the UI. Dated groups are sorted by due_date
while the No Date group preserves the custom order.
Few changes: lets make the date chip red when in the overdue section. In all other sections, lets hide the date chip for individual tasks. Then, for the Later section, lets break that up into individual days.

- Replaced single "Later" group with per-day groups (e.g. "Mon, Apr 20"), each sorted by due_date
- Added `dateChipStyle` prop to TaskItem ("normal" | "overdue" | "hidden"), default "normal"
- Date chip is red (border-red-400 text-red-400) in "overdue" style, hidden in "hidden" style
- TasksScreen passes dateChipStyle="overdue" for Overdue group, "hidden" for all others
Fix date chips and include year in future group labels

Replace dynamic ternary class strings with explicit {#if} blocks for the
date chip so Tailwind v4's scanner picks up the classes and theme tokens
are respected. Use text-danger and border-danger for overdue chips and
proper border/token classes for non-overdue chips to fix the overdue
chip appearance and prevent chips from showing in sections that should
be hidden.

Also include the year in per-day group labels when the date is not in
the current year (e.g. "Mon, Apr 20, 2027") by passing the appropriate
Intl.DateTimeFormat options, so tasks scheduled in future years display
an unambiguous header.
yes (remove This Week, extend per-day grouping to everything beyond tomorrow)

- Removed "This Week" group entirely
- Everything beyond tomorrow now gets a per-day group label (same as what "Later" was doing), giving a consistent Overdue → Today → Tomorrow → [per-day] → No Date structure
Respect manual order within same-day groups

Ensure tasks that fall on the same day keep the user's manual ordering
by using a task_order index as a tiebreaker when sorting. Also add
drag-and-drop group tracking so drags and drops are confined to their
originating group and wire full DnD handlers into the grouped view.

- Use a taskOrderIndex map in sortByDue to break ties when due dates are equal so same-day tasks respect manual order.
- Add dragGroup state and record it on handleDragStart; ignore dragOver/drop events when the event group differs from the originating dragGroup to prevent cross-group drops.
- Reset dragGroup on drag end.
- Wrap grouped TaskItem entries with draggable divs and hook up dragstart/dragover/dragend/drop to match the flat view's DnD behavior.
Update drag-and-drop to set task due dates

Support dragging tasks between date-grouped columns by updating the
task's due_date to the target group's date (or clearing it when dropped
into No Date). Preserve the task's time-of-day when has_time is set,
block dropping into the computed Overdue group, and allow dragging out
of Overdue. Also add TaskGroup.date to the grouping data and expose a
showSubtaskCount prop and optional subtask rendering in the task list
UI.
fix null taskId error when reordering after cross-group drag

- Capture dragId and dragGroup into local variables at the top of handleDrop before any awaits — prevents the race where dragend fires during updateTask and nulls out dragId before reorderTask is called
Allow dragging tasks to update date groups

Add date handling to task groups so dragging a task into another group
updates its due_date. Introduce date: Date | null for TaskGroup (null
represents Overdue/No Date), update cross-group drops to set or clear a
task's due_date based on the target group while preserving time-of-day
for tasks with has_time, and keep within-group drops as reorders. Also
ensure Overdue remains a computed-only target (cannot drop into it)
while allowing dragging out.

Additionally, add GoogleTasks workspace support fields
(WorkspaceMode::GoogleTasks and an optional google_account) and include
the new field in WorkspaceConfig::new to initialize google_account to
None.
2026-04-14 06:01:19 -07:00
Tristan Michael 67eb90c2a0 Introduce windowDecorations enum with three options
Replace the previous boolean systemDecorations with a windowDecorations
enum ("custom", "none", "system") to allow three distinct decoration
modes. Update UI to use a select control in Settings, adapt App.svelte
conditionals to check for the "custom" value when applying custom
borders/rounded styles, and rename localStorage key to persist the new
enum. Also ensure the native system decorations are enabled when the
setting is "system" and export the new setter name setWindowDecorations
in the store.
Enable setting window decorations

Add the "core🪟allow-set-decorations" capability to allow the app
to control window decorations (e.g., system titlebar). This fixes the
issue where the system titlebar was not working by permitting the code
to modify decoration state.

Also ensure the capability list remains properly comma-separated after
insertion.
Add outline support for borderless mode

Allow border outline in non-system decoration modes on Linux. The change
updates the condition for applying the linux-window-border class so the
outline is applied when window decorations are custom or any non-system
mode, enabling an outline for borderless windows while keeping
system-decorated windows unaffected.
Respect borderless mode: remove rounded corners

Remove rounded corners from popups and overlays when window decorations
are disabled. The App component now passes the windowDecorations state
into the root div via a data-decorations attribute, and the CSS adds a
rule that forces square corners for all elements under
[data-decorations="none"] to ensure borderless mode yields true square
UI without rounded popups/toasts.
Do not override button/input/select border-radius in borderless mode

Prevent borderless mode from removing rounded corners on interactive
form elements. The previous selector applied border-radius: 0 to all
descendants, unintentionally flattening buttons, inputs, and selects.
Restrict the rule so it excludes button, input, and select elements to
preserve their expected styling.
Strengthen dropdown drop-shadows

Make the kebab and other dropdown menu shadows more pronounced by
replacing the tailwind shadow-lg class with shadow-2xl across
TaskDetailView.svelte and TasksScreen.svelte. This improves visual
contrast and makes menus stand out more clearly against the background,
addressing the request to make the dropshadow on the kebab menus
stronger.
Use consistent menu shadow class

Replace multiple inline shadow utility classes with a shared
"menu-shadow" class for dropdown and context menus across
TaskDetailView, SettingsScreen, and TasksScreen. This unifies styling,
reduces duplication, and allows easier tweaks to the menu drop-shadow
(potentially addressing blurry rendering) by centralizing the shadow
definition.
Add subtle shadow for dropdown/kebab menus

Soften dropdown/kebab menu appearance by adding a subtle box-shadow
utility and a darker variant for dark mode. Also refine the borderless
mode rule to avoid overriding elements that use rounded-full classes so
those intentional circular controls keep their shape.
Make dropdown buttons square-cornered in borderless mode

Ensure dropdown menu buttons use square corners when decorations are
disabled. The CSS update adds a selector to force border-radius: 0 for
buttons inside .dropdown-menu under [data-decorations="none"]. Several
dropdown container divs across TaskDetailView, SettingsScreen,
TasksScreen, and related components are given a .dropdown-menu class so
the new rule applies consistently and makes dropdown buttons match the
rest of the borderless UI.
when workspace settings is up, can we make it so I can drag the header to move the app around?

- Added data-tauri-drag-region to the header and title in SettingsScreen.svelte so the settings header can be used to drag/move the window
<task-notification>
<task-id>bzp4p2vsp</task-id>
<summary>Monitor event: "Tauri rebuild — Finished or error"</summary>
<event>[Monitor timed out — re-arm if needed.]</event>
</task-notification>


Apply decorations-none class for borderless mode

Ensure the "decorations-none" CSS class is applied/removed on the
document root when window decorations are set to "none" so borderless
mode styles take effect. The CSS selector was also adjusted to
explicitly list rounded utility classes so the rule targets known
rounded elements while keeping dropdown-menu buttons included.
2026-04-14 06:02:30 -07:00
Tristan Michael 6be1ee93c0 on linux, when I click the new task button, the toast and the dimming of the background don't respect the visual borders of the app
- Changed `fixed` to `absolute` positioning in NewTaskInput.svelte backdrop div so the overlay respects the app's visual container bounds on Linux (where a p-2 padded, rounded-xl container creates visual borders)
it looks mostly good now, except that when the toast slides up, it's causing the rest of the app content to jitter

- Added `overflow-hidden` to the outer wrapper div in NewTaskInput.svelte to contain the translate-y-full animation within its own layer and prevent repaint jitter on sibling content
when workspace settings is up, can we make it so I can drag the header to move the app around?

- Added data-tauri-drag-region to the header and title in SettingsScreen.svelte so the settings header can be used to drag/move the window
2026-04-14 06:23:10 -07:00
Tristan Michael 34d7e8b17d Add Linux system window decorations setting
Expose a per-user setting to toggle system window decorations on Linux
and apply it to the UI and window behavior.

- Add a SettingsScreen option (Linux-only) to toggle "System window decorations" and bind it to the app store.
- Track the preference in app store with persistent localStorage key and getter/setter (setSystemDecorations) that updates the Tauri window decorations via getCurrentWindow().setDecorations().
- Respect the setting when rendering the main App.svelte by disabling rounded corners and custom Linux window border when system decorations are enabled. This change is needed to let Linux users choose native title bar/window chrome for better integration with their desktop environment.
2026-04-14 05:58:17 -07:00
Tristan Michael 31af983640 Add ink theme and remove onyx border class
Add an "Ink" theme for e-ink displays and remove the previously applied
onyx-border class from the App container. The new theme defines
high-contrast monochrome variables, suppresses shadows and decorative
effects, adjusts scrollbars and select options, and adds a subtle
linux-window-border color suitable for e-ink screens. The onyx border
CSS was removed and the App.svelte container no longer toggles the
onyx-border class; the Settings screen now includes the Ink option in
the theme selector.
Remove unnecessary blank line in app.css

Remove an unneeded blank line in the Tauri app stylesheet. The extra
line was left behind when considering a mode elimination and is not
required, so this cleans up the CSS file to keep it tidy and consistent.
2026-04-14 05:27:21 -07:00
Tristan Michael 9071f46050 Rename Onyx theme to Black and Gold
Update displayed theme name from "Onyx" to "Black and Gold" in the
settings UI so the theme matches the requested branding. This change
ensures users see the new theme name in the theme selector and aligns
the UI with the prompt to call the theme Black and Gold.
2026-04-06 17:32:00 -07:00
Tristan Michael 58e205a024 Fix visibility of completed checkmarks on onyx theme
Ensure checkmarks under the "completed" state are visible on the
near-white primary background for the onyx theme. The change adjusts
selector scoping so dark text and icons (including elements with
.text-white inside .bg-primary) are explicitly styled with a dark color,
preventing white-on-near-white contrast issues.
2026-04-06 17:30:43 -07:00
Tristan Michael 5756e19ceb Desaturate onyx theme gold tones
Tweak several onyx theme color variables to slightly desaturate the gold
accents so the UI appears less saturated and more balanced. Update text,
option, and FAB colors, hover/background and border RGBA values, and add
a new thicker onyx-border utility for a prominent gold window border.
2026-04-06 17:29:49 -07:00
Tristan Michael b83a54328e Brighten dividers and submenu outlines
Make the divider and submenu outline colors a brighter gold to improve
contrast and visual clarity. Updated CSS variables --color-border-light
and --color-border-dark from a dark brown (#2a2418) to a warmer
gold-brown (#5c4d2e). This change enhances the UI by making separators
and submenu outlines more visible and consistent with the app's gold
text accents.
2026-04-06 17:28:29 -07:00
Tristan Michael 42ef8584ab Make large "+ new task" FAB use text gold
Make the prominent "+ new task" floating action button match the primary
text gold color in the Onyx theme. The FAB previously used the cream
primary color; this change sets its background to #d4bc72 so the button
visually aligns with other gold text elements in the UI.
2026-04-06 17:25:46 -07:00
Tristan Michael c4d6d28e12 Lighten onyx gold shades
Adjust onyx theme gold tones to be slightly lighter and warmer for
improved contrast and visual clarity. This updates primary text,
secondary text, scrollbar, select option text, checkbox borders,
hover/focus highlight backgrounds, and the Linux window border to use
the new lighter gold color values so the UI reads better against dark
surfaces.
2026-04-06 17:25:02 -07:00
Tristan Michael c13fbde1b8 Tweak onyx theme colors to warmer gold tones
Give the onyx theme a warmer, gold-accented look and slightly lighten
deep blacks to improve contrast and legibility. Replace pure white
primary colors with a soft yellow/gold, adjust surface and card blacks
to be a bit lighter, and update related elements (select options,
primary button text, checkbox borders, hover/focus highlights, and Linux
window border) so interactive elements read clearly against the new
palette.
2026-04-06 17:23:25 -07:00
Tristan Michael 973d575b51 feat: add onyx dark theme support
Add onyx theme as a new dark theme option. Register it in the dark
themes set, add the theme option to the settings dropdown, and define
complete color variables and scrollbar styling for the onyx theme.

Also improve sync error handling to gracefully skip upload and conflict
resolution actions when files are missing, preventing sync failures due
to files moved or deleted between action computation and execution.
2026-04-06 17:17:00 -07:00
Tristan Michael 5e5773d146 fix: add safe area padding to scrollable content
Add safe area padding to scrollable main content areas and
adjust drawer footer padding to prevent content from being
hidden behind notches and home indicators on mobile devices.
This ensures proper spacing on devices with safe area insets.
2026-04-06 11:21:29 -07:00
Tristan Michael c772e3251a fix: add safe area bottom padding to DateTimePicker
Add bottom padding to DateTimePicker component to prevent content
from being obscured by notches or home indicators on mobile devices.
Uses CSS max() function to ensure minimum 0.75rem spacing while
respecting device safe area insets.
2026-04-06 11:21:29 -07:00
Tristan Michael 9a9dc80e26 fix: set fixed height on calendar grid
Add content-start alignment and fixed 192px height to the
calendar grid to prevent layout shift when switching between
months with different numbers of weeks. This ensures consistent
spacing and prevents the calendar from changing size based on
the month being displayed.
2026-04-06 11:21:29 -07:00
Tristan Michael e9f7f7ab69 feat: move Onyx header above card and enlarge on setup screen 2026-04-06 11:21:29 -07:00
Tristan Michael 3d65aaf502 feat: left-edge swipe gesture for drawer and back navigation on mobile 2026-04-06 10:30:36 -07:00
Tristan Michael 50800f0c2d feat: add separate sync interval for unfocused state
Introduce a new sync interval configuration for when the app is
in the background, allowing users to set a longer sync period to
reduce resource usage. Replace the fixed focus threshold with
dynamic interval switching based on app focus state. Add
syncIntervalUnfocused setting to the UI with a new background
sync interval selector. Refactor sync interval management into
a restartSyncInterval function to handle both focused and
unfocused intervals consistently.
2026-04-06 09:37:06 -07:00
Tristan Michael f5295b5980 fix: reset tasks and remount screen on workspace change
Reset the tasks array when switching workspaces to prevent stale
task data from persisting. Wrap TasksScreen in a keyed block to
force remounting when the current workspace changes, ensuring a
clean state for each workspace.

Configure line endings to use LF across all files for consistency.
2026-04-06 09:10:36 -07:00
Claude 6174836b7f
Fix critical and high-severity issues from project audit
Security:
- Fix path traversal via backslash bypass in sync validate_sync_path()
- Replace silent HTTP client fallback with proper error propagation
- Add 64KB YAML frontmatter size limit to prevent DoS via crafted files

Data integrity:
- Reorder delete operations: update metadata before removing files to
  prevent orphaned metadata entries on crash
- Fix task deduplication to use file mtime as tiebreaker when versions
  are equal, preventing non-deterministic data loss
- Add rollback on conflict recovery failure (remove orphaned duplicate
  files when metadata update fails)
- Clean up temp files on atomic write rename failure
- Add file-based sync lock to prevent concurrent sync operations
- Use saturating_add for task version to prevent overflow

Error handling:
- Surface move_task rollback failures as structured errors instead of
  silent warnings
- Log WebDAV parallel request failures instead of silently swallowing
- Emit watcher-error events to frontend instead of only printing to stderr

Frontend:
- Fix focus listener leak in auto-sync (clean up if stopAutoSync called
  while promise pending)
- Add prefers-reduced-motion CSS media query for accessibility
- Add ARIA labels, roles, and keyboard handlers to TaskItem, BottomSheet,
  and ConfirmDialog components
- Replace BottomSheet children: any with Snippet type

https://claude.ai/code/session_01AJoK28N4vqLqzskq6ybGri
2026-04-06 11:03:11 +00:00
Claude 85748f4c95
Audit fixes: panic safety, path hardening, code quality
- Replace 2 production unwrap() calls in workspace.rs with proper error
  handling to prevent panics on inconsistent state
- Add AppState::save_config() helper to eliminate 11 duplicated
  save_to_file patterns in Tauri lib.rs
- Log file watcher errors instead of silently swallowing them
- Harden path traversal check in storage.rs: re-verify after
  canonicalization to catch symlink escapes
- Add Windows reserved device name handling (CON, NUL, etc.) to
  sanitize_filename
- Clean up stale .tmp files from interrupted atomic writes on startup

All 107 core tests pass.

https://claude.ai/code/session_01EnSrQsowc64rAwzD9BnJpc
2026-04-06 10:41:03 +00:00
Claude a12deb5182
Harden codebase: fix security, quality, and maintainability issues
- Replace dangerous unwrap() with proper error handling (storage.rs, webdav.rs)
- Add atomic writes (temp + rename) for config, sync state, and metadata files
- Add path traversal validation in sync executor
- Add workspace path validation in Tauri commands
- Add input size limits for task titles, descriptions, and list names
- Add file download size limit (10MB) to WebDAV get_file
- Fix move_task rollback to log failures instead of silently ignoring
- Fix JSON serialization unwrap in Tauri create_remote_workspace
- Fix swallowed errors in sync queue backup, metadata writes, sync state load
- Extract hardcoded strings into named constants (filenames, extensions, limits)
- Use REQUEST_TIMEOUT/CONNECT_TIMEOUT constants in WebDAV client builder
- Fix frontend: clear taskStack when viewed task is deleted or list is switched
- Fix frontend: surface credential loading and focus listener errors

https://claude.ai/code/session_01F67yfLLmSaBtT7aKKNus1M
2026-04-06 10:17:30 +00:00
Tristan Michael 5e33416b22 Slim task frontmatter: remove timestamps, add version counter + self-healing dedup
Remove created_at/updated_at from Task struct and frontmatter. Add a
version counter (u64) that increments on every write, defaults to 1 for
old files. list_tasks now groups by UUID and auto-deletes stale
duplicates (keeping highest version), preventing sync-induced dupes from
surfacing in the UI. has_time and parent are omitted from frontmatter
when false/null.

Update CLI, Tauri frontend types, and Svelte components to match.
2026-04-05 19:22:10 -07:00
Tristan Michael 7cc899470f Polish: suppress error banner for transient sync failures and sort remote folders
Only show the error banner for non-transient sync failures; connectivity
issues (timeout, refused, unreachable) just update the status dot. Sort
workspace entries above regular folders in the remote folder browser.
2026-04-05 19:11:10 -07:00
Tristan Michael fbf1ba69ef Fix task list UX: deduplicate tasks and clear on list switch
Deduplicate tasks by ID in loadTasks since sync conflicts can produce
files with the same UUID. Clear the task array immediately on list
switch to prevent showing stale content from the previous list.
2026-04-05 19:10:57 -07:00
Tristan Michael 2c52afa8d7 Add initial sync loading screen for new WebDAV workspaces
Show a spinner while the first sync runs after adding a WebDAV workspace
so the user doesn't land on an empty task list. The screen transitions
to tasks only after sync completes or fails.
2026-04-05 19:10:49 -07:00
Tristan Michael ca52ed9fee Rework safe area insets with CSS variables and per-element spacers
Replace container-level env(safe-area-inset-*) inline padding with
--safe-top/--safe-bottom CSS variables applied per-element: drawer,
task list panel, detail panels, FAB, settings overlay, error banner,
and setup screen. Wrap task list in {#key app.activeListId} to force
re-render on list switch (co-located with FAB safe-bottom fix).
2026-04-05 19:10:37 -07:00
Tristan Michael 501f991f2c feat: replace custom WebDAV credential IO with pluginSwitch credential storage and retrieval the tauri_plugin_credentialsplugin and thread the AppHandle into handlers that need it.
- Import Credentials and initialize its plugin inuriBuilder.
- Replace blocking webdav::load_credentials/store calls with Credentials::load and Credentials::store to avoid spawn_blocking and centralize credential handling- AppHandle parameters to commands that need credential access:
 rename_workspace, add_webdav_workspace, store_credentials, load_credentials,
 and sync_workspace- Update save flow in add_webdav_workspace to use plugin storage after updating config.

This reduces manual blocking calls, unifies credential management andintegrates with Tauri app state for safer runtime access.
2026-04-05 17:30:07 -07:00
Tristan Michael 633337da4e Add safe area insets for mobile status bar and navigation
Add viewport-fit=cover to the viewport meta tag and apply
env(safe-area-inset-top/bottom) padding on mobile platforms.
This prevents the app header from being obscured by the Android
status bar, camera notch, and bottom gesture navigation area.
2026-04-05 17:29:54 -07:00
Tristan Michael 192b449e87 Add tauri-plugin-credentials for cross-platform credential storage
Create a Tauri v2 plugin that uses EncryptedSharedPreferences (Android Keystore)
on Android and the system keychain (keyring crate) on desktop. This replaces
the direct onyx-core keyring calls in the Tauri app, which failed on Android
because keyring-storage was feature-gated to desktop only.

- New plugin crate at apps/tauri/tauri-plugin-credentials/ with Kotlin Android
  code and Rust desktop fallback
- Update all Tauri credential commands to use the plugin API
- Add security-crypto dependency for Android and ProGuard rule for Tink
- Remove onyx-core/keyring-storage dependency from Tauri app features
2026-04-05 17:29:51 -07:00
Tristan Michael 44ac2bc5b3 Show sync counts only when non-zero
Hide upload/download counts in the drawer footer when both are zero;
show each arrow count individually only if its value is greater than
zero. This avoids displaying redundant “↑0 ↓0” and ensures a
cleaner, more informative sync status line when only one direction has
activity.
2026-04-05 16:38:21 -07:00
Tristan Michael 0ae0705331 Add per-workspace sync interval and fix download timestamp recording
Add a configurable per-workspace sync interval (sync_interval_secs) with
Tauri command set_sync_interval, UI dropdown in Settings, and store
support to restart auto-sync when changed. Remove the redundant
main-panel sync status chip and surface upload/download counts in the
drawer footer and Tasks screen. Fix the sync logic to record the remote
file's last_modified timestamp when downloading (instead of local mtime)
so subsequent diffs don’t falsely trigger downloads.

These changes were needed to allow users to control auto-sync frequency
per workspace, simplify the UI by moving sync counts to the drawer
footer, and correct a bug where downloads were always considered new
because the local file mtime was used instead of the authoritative
remote timestamp.
2026-04-05 16:35:22 -07:00
Tristan Michael 7e5b3ea7b0 Remove list footer divider and reverse sync spinner
Remove the bottom divider from the lists/drawer footer and adjust the
sync icon animation to spin in the correct (reverse) direction when
syncing.

- Remove the border-t divider classes from the drawer footer to eliminate the
visual divider at the bottom of the lists panel.
- Replace the Tailwind animate-spin class with an inline CSS animation that
runs in reverse when app.syncing is true so the sync icon spins the
expected direction.
2026-04-05 16:24:17 -07:00
Tristan Michael 2f90805594 Remove manual sync UI; add auto-sync lifecycle and status
Remove deprecated sync mode UI and manual sync controls from
SettingsScreen and TasksScreen. Implement an always-full sync mode and a
new auto-sync lifecycle in the app store: startAutoSync/stopAutoSync,
periodic polling (60s), debounced file-change-triggered sync (5s), and
window-focus-triggered sync when last sync is older than 30s. Track
syncStatus (idle/synced/error/offline), lastSyncTime, and surface status
in the Tasks drawer with a status dot and a manual sync button. Wire
auto-sync startup/teardown into loadConfig, switchWorkspace,
addWebdavWorkspace, and removeWorkspace.

These changes simplify sync configuration by removing legacy sync modes
and UI elements, provide robust automatic syncing for WebDAV workspaces,
and improve user feedback on sync state and errors.
2026-04-05 16:19:43 -07:00
Tristan Michael 4c57851e15 Rename workspace and remote folders with confirmation
Add WebDAV MOVE support and update workspace rename flow to handle both
local and WebDAV-backed workspaces. The Tauri rename_workspace command
is made async and now performs filesystem rename for local workspaces
and issues a WebDAV MOVE (via a new WebDavClient::move_resource) for
remote workspaces, updating stored paths and credentials accordingly. A
confirmation dialog is added to SettingsScreen to prompt users before
renaming, and minor UI/default tweaks are included (SetupScreen default
name). This ensures renames update both local folders and remote WebDAV
folders reliably and with user confirmation.
2026-04-05 15:10:44 -07:00
Tristan Michael 50d859ef80 Refactor workspaces to use UUID keys
Change workspace identifiers from display names to UUID strings so
multiple workspaces can share the same display name. WorkspaceConfig now
stores a name field; add_workspace returns a generated UUID. Update all
CLI, Tauri commands, frontend stores and screens, WebDAV managed
directories, and tests to use/resolve workspace IDs; add helpers
find_by_name/resolve_name to map display names to IDs when needed. This
removes duplicate-name checks, avoids filesystem conflicts, and
preserves display names while using stable unique IDs internally.
2026-04-05 14:58:31 -07:00
Tristan Michael a709df609f Prevent workspace name collisions
Adding explicit duplicate-name checks to the Tauri commands that create
workspaces prevents a new workspace from silently overwriting an
existing one. The change returns an error if a workspace with the given
name already exists.

Also set sane defaults in the setup UI: default workspace name to "Onyx"
for both local and WebDAV flows, default the local folder to the user's
Documents directory via documentDir(), and ensure the create flow resets
the name to the "Onyx" default when starting creation.
2026-04-05 14:49:55 -07:00
Tristan Michael 095ac8fa97 Parallelize workspace detection in folder listing
Speed up initial folder listing by checking each subfolder for the
.onyx-workspace.json marker in parallel instead of sequentially. This
uses futures::future::join_all to run multiple PROPFIND/list_files calls
concurrently, reducing latency when detecting workspaces across many
subdirectories.

Also add the futures 0.3 dependency to the Tauri Cargo.toml and lockfile
so the async utilities are available.
2026-04-05 14:37:58 -07:00
Tristan Michael ac789e8d56 Handle deleted/moved workspace folders (missing state)
Detect when the current workspace folder cannot be opened and show a
dedicated "missing" screen that explains the workspace was not found.
Catch failures from get_lists during loadConfig, set a missingWorkspace
state and switch to the missing screen, and provide
forgetMissingWorkspace() to remove the missing workspace from the config
and either switch to the next available workspace or fall back to the
setup screen. Add UI in App.svelte to present the workspace name,
explanation, and a Continue button that invokes forgetting the missing
workspace.
2026-04-05 14:30:22 -07:00
Tristan Michael 753cb1cad5 Rename workspace metadata and add WebDAV folder browsing
Rework WebDAV workspace setup to use .onyx-workspace.json instead of
.metadata.json and to let users pick a remote folder instead of forcing
an Onyx/ subfolder. This updates storage, sync, config types, tests, and
CLI/Tauri commands to store a webdav_path in WorkspaceConfig and to
combine webdav_url + webdav_path for sync.

Changes include:
- Rename .metadata.json → .onyx-workspace.json across storage, sync, and tests so workspace detection and root metadata use the new filename.
- Remove hardcoded automatic "Onyx/" subfolder in sync and use the user-selected remote path directly.
- Add webdav_path field to WorkspaceConfig (Rust and TypeScript types) and thread it through add_webdav_workspace and frontend addWebdavWorkspace.
- Add three Tauri commands (list_remote_folder, inspect_remote_workspace, create_remote_workspace) to support remote folder browsing, workspace preview, and remote workspace creation.
- Rewrite SetupScreen WebDAV flow to Connect → Browse (lazy folder explorer) → Preview or Create, and wire UI state/handlers to the new commands.
- Update CLAUDE.md to document the new on-disk filename and note development phase allowing breaking changes.
2026-04-05 14:30:22 -07:00
Tristan Michael 70af83ccfc Show parent path for non-WebDAV workspaces
When displaying workspace paths in the tasks list, the previous code
showed the full path which could include a tail segment (e.g., a
filename or last folder). This change strips the last path segment for
non-WebDAV workspaces so the UI presents the parent directory instead,
improving clarity for users who expect to see the workspace root rather
than a trailing item.
Fix fallback rendering of workspace path

The previous change grouped the nullish coalescing incorrectly, which
caused the fallback empty string to be applied to the result of
replace(...) rather than to ws?.path. This could lead to rendering
'undefined' or leaving the replace expression unresolved when ws.path is
nullish. Adjust the expression so the nullish fallback applies to
ws?.path, ensuring a clean empty string fallback when no path is
present.
2026-04-05 14:30:22 -07:00
Tristan Michael bb735ecd4a Add workspace rename and restructure settings screen
Full-stack workspace rename: renames folder on disk, updates config
key/path, refreshes frontend. Restructure settings screen with generic
'Workspace Settings' header, workspace name row with kebab menu
(Rename + Delete). Replace per-workspace kebab dropdown in workspace
list with a direct settings gear button. Remove Appearance heading
and border box from theme section. Clean up unused wsMenuName state.
2026-04-05 14:30:22 -07:00
Tristan Michael ca0a5c8ab3 update workspace creation to append workspace name 2026-04-05 07:04:40 -07:00
Tristan Michael 9bde08c2d5 feat: sort workspaces and prevent redundant switches
Sort workspace names alphabetically in the drawer for
better organization. Add a check to prevent switching to
the currently active workspace, avoiding unnecessary
operations and improving user experience.
2026-04-03 16:57:45 -07:00
Tristan Michael 58f37b08d6 fix: harden WebDAV sync — async credentials, consolidated command, Onyx subfolder 2026-04-03 10:11:46 -07:00
Tristan Michael 9e57f1df3c chore: update lock files for log dependency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:11:40 -07:00
Tristan Michael be6b8d0d90 security: update callers for hardened credential API
- Handle Result from WebDavClient::new in CLI sync, core sync, and Tauri
- Unwrap Zeroizing<String> at Tauri serialization boundary
- Use .as_str() for basic_auth calls with Zeroizing<String> fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:11:40 -07:00
Tristan Michael 2a2e362a8f fix: WebDAV sync — Onyx subfolder, timeouts, error display, light theme 2026-04-03 10:11:40 -07:00