Push tasks to GitHub Projects on assignment
Details
Add bidirectional GitHub Projects v2 sync for project assignment:
when a task is assigned to a PrivStack project linked to a GitHub
Project, it now appears on the GitHub board. Unassigning removes it.
Two scenarios on assign:
- If the task is already a GitHub issue, add it to the project via
the addProjectV2ItemById GraphQL mutation.
- If the task is local-only, create a GitHub issue first (in a repo
matching the project's org/user from configured issue sources),
then add the new issue to the project.
On unassign: remove the item from the GitHub Project via the
deleteProjectV2Item mutation. The issue itself is not deleted.
Changes:
- GitHubIssue model: add NodeId from REST API node_id field
- GitHubIssueFieldMapper: persist github_node_id in custom fields
during issue sync for later use in project mutations
- TaskItem: add GitHubNodeId convenience accessor
- GitHubProjectApiClient: add AddItemToProjectAsync and
RemoveItemFromProjectAsync GraphQL mutations
- GitHubProjectSyncService: add PushTaskToProjectAsync and
RemoveTaskFromProjectAsync with issue creation fallback and
node_id resolution; inject IGitHubIssueApiClient and
GitHubIssueSourceService for repo resolution
- TasksViewModel.Projects: hook FireGitHubProjectSync into
AssignTaskToProject, BulkAssignToProject, and
ApplyProjectEditorResultAsync (fire-and-forget with error toast)
- TasksPlugin: share GitHubIssueApiClient instance between issue
sync and project sync services
Fix tasks showing Jan 1, 0001 for UpdatedAt timestamp
Details
API-created tasks (via IApiProvider) were missing updated_at in the
create payload because the caller (fix-bugs skill, external API)
doesn't include timestamps. The Rust backend auto-sets created_at
but not updated_at, leaving it as DateTimeOffset.MinValue.
- HandleCreateTaskAsync: inject created_at and updated_at if missing
- HandleUpdateTaskAsync: always set updated_at to now on PATCH
- UtcToLocalConverter: return null for MinValue dates so the detail
panel shows blank instead of "Jan 1, 0001 12:00 AM"
Fix SafeHtmlLabel crash: cannot InvalidateVisual during render pass
Details
Remove InvalidateVisual() from the catch block — Avalonia throws
if a visual is invalidated during an active render pass. The
compositor will naturally re-render on the next frame without it.
Unify Tasks toolbar sizing to match ThemedDropdown Compact variant
Details
All toolbar controls now use consistent Compact sizing:
- Font: ThemeFontSizeXsSm (12px) everywhere (was ThemeFontSizeSm/13px
on project row, mixed elsewhere)
- Padding: 8,6 on all ComboBoxes, buttons, toggles (was 12,6 / 10,6 /
missing on filter ComboBoxes)
- CornerRadius: ThemeRadiusSm (6px) on all controls (was ThemeRadiusXs)
- VerticalAlignment=Center on all elements for proper row alignment
Also changed right-side filter WrapPanel to a horizontal StackPanel
with consistent Spacing="8" to eliminate the per-item margin hacks
(Margin="0,0,12,4") that caused uneven spacing.
Stop firing update checks when API is unreachable
Details
After 2 consecutive network failures (timeout, HTTP error, DNS
failure), the auto-update timer skips further checks instead of
burning 15 seconds on a doomed request each cycle. The counter
resets automatically when the API responds successfully.
Manual "Check for updates" always resets the backoff and fires
regardless, so the user can always retry.
Get notified about new releases