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.
Fix ComboBox bindings showing Avalonia.Controls.ComboBoxItem as text
Details
GitHub Sync: The project picker state was missing an error message
display, so GraphQL errors were silently swallowed. Added error
TextBlock and improved the auto-fetch catch to surface the error.
The SyncDirection ComboBox used ComboBoxItem wrappers with
SelectedItem bound to a string — replaced with x:String items.
Also normalize corrupted SyncDirection values on load.
Settings Overlay: Same ComboBoxItem binding bug on StatusCategory,
FieldType, and RuleTriggerType dropdowns. Replaced with ItemsSource
+ SelectedValueBinding + DisplayMemberBinding pattern using static
KeyValuePair arrays in the ViewModel.
Get notified about new releases