Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f3b25b8
fix(migration): add NOT EXISTS guard to income quote cleanup
afadil Mar 29, 2026
750617c
refactor(import): event-driven CSV validation + improved warning mess…
afadil Mar 19, 2026
0dd880e
wip: asset review step, quote ccy resolution fixes, provider name enr…
afadil Mar 23, 2026
71b8895
fix(import): event-driven asset preview, skip-aware validation, idemp…
afadil Mar 23, 2026
d343301
fix(import): address code review findings — tests, web parity, sync, …
afadil Mar 23, 2026
7c28f21
refactor(import): replace activity_import_profiles with import_templa…
afadil Mar 24, 2026
58e7fbb
fix: popover close on action, data-grid re-render, e2e import wizard …
afadil Mar 24, 2026
95e3cdb
feat(csv-import): add ISIN support and enhance asset resolution
afadil Mar 25, 2026
d0e6184
feat(import): add Wealthsimple template, fallback column mapping, Fie…
afadil Mar 26, 2026
5ed22dd
feat(import): fallback column support, sign inference, skip activitie…
afadil Mar 26, 2026
2d83e4b
feat(import): grouped template selector, review filters, asset dedup
afadil Mar 26, 2026
7b8457e
perf(import): resolve symbols concurrently with buffer_unordered(5)
afadil Mar 26, 2026
99a873b
perf(import): concurrent candidate resolution, bump concurrency to 10…
afadil Mar 27, 2026
f7c19ff
perf(market-data): relax Yahoo rate limit — burst 10, 2000 req/min
afadil Mar 27, 2026
c867390
fix(import): resolve custom assets without exchange MIC (e.g. deliste…
afadil Mar 27, 2026
5610780
fix(import): auto-switch template on account change, include exchange…
afadil Mar 27, 2026
3df81bf
fix(import): try primary exchange suffix for all non-USD currencies
afadil Mar 27, 2026
7eb48b1
fix(tests): remove unused import in activities repository and add tes…
afadil Mar 27, 2026
46d8434
fix(import): currency-aware symbol resolution, non-blocking OpenFIGI …
afadil Mar 27, 2026
284f8f2
refactor(import): event-driven validation with subtype-aware asset re…
afadil Mar 28, 2026
69a8023
fix(import): mapping grid UX, Wealthsimple template, smart defaults
afadil Mar 28, 2026
bc4267a
feat(market-data): add Aquis Exchange (XAQE) to exchange registry
afadil Mar 28, 2026
dd6646e
feat(import): detect and transcode non-UTF-8 CSV encodings
afadil Mar 28, 2026
9aa8948
fix(account): chart marker clicks and holdings editing for broker-syn…
afadil Mar 28, 2026
b27a9c6
refactor(import): generalize import_templates into discriminated mapp…
afadil Mar 28, 2026
9e8fc67
fix(mapping-table): update button styling in mapping header cell for …
afadil Mar 28, 2026
7685a64
fix(ci): resolve all CI check failures
afadil Mar 29, 2026
2a36ff9
chore: bump version to 3.2.0 and sync addon-sdk import API signatures
afadil Mar 29, 2026
3d3c177
fix(migration): add cleanup for BROKER quotes to prevent incorrect de…
afadil Mar 29, 2026
e8252f5
fix(import): cast draft quoteMode to QuoteMode literal union
afadil Mar 29, 2026
8895015
fix(import): address code review findings and add changelog
afadil Mar 29, 2026
7abdd35
style: apply cargo fmt to activities_service.rs
afadil Mar 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Claude worktrees
.claude/

# Build outputs
dist/
coverage/
Expand Down
29 changes: 21 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [
]

[workspace.package]
version = "3.1.2"
version = "3.2.0"
edition = "2021"
license = "AGPL-3.0"

Expand Down
2 changes: 1 addition & 1 deletion addons/goal-progress-tracker/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "goal-progress-tracker-addon",
"version": "3.1.0",
"version": "3.2.0",
"description": "An addon for tracking investment progress towards target amounts with progress visualization",
"type": "module",
"main": "dist/addon.js",
Expand Down
2 changes: 1 addition & 1 deletion addons/investment-fees-tracker/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "investment-fees-tracker-addon",
"version": "3.1.0",
"version": "3.2.0",
"description": "An addon for tracking and analyzing investment fees across your portfolio",
"type": "module",
"main": "dist/addon.js",
Expand Down
2 changes: 1 addition & 1 deletion addons/swingfolio-addon/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "swingfolio-addon",
"version": "3.1.0",
"version": "3.2.0",
"description": "A simple swing stock trading tracker with performance analytics and calendar views",
"type": "module",
"main": "dist/addon.js",
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
"version": "3.1.2",
"version": "3.2.0",
"type": "module",
"scripts": {
"dev": "cross-env BUILD_TARGET=web vite",
Expand Down
130 changes: 116 additions & 14 deletions apps/frontend/src/adapters/shared/activities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Activity Commands
import { ImportType } from "@/lib/types";
import type {
Activity,
ActivityBulkMutationRequest,
Expand All @@ -8,8 +9,13 @@
ActivitySearchResponse,
ActivityUpdate,
ActivityImport,
ImportAssetCandidate,
ImportAssetPreviewItem,
ImportActivitiesResult,
ImportMappingData,
ImportTemplateData,
BrokerSyncProfileData,
SaveBrokerSyncProfileRulesRequest,
} from "@/lib/types";

import { invoke, logger } from "./platform";
Expand Down Expand Up @@ -142,7 +148,6 @@
* Import activities into the system.
* Expects activities that already passed backend check/preview resolution.
* Apply is persistence-only and rejects missing resolved symbol fields.
* Extracts accountId from the first activity for the backend call.
* Returns ImportActivitiesResult with activities, import_run_id, and summary.
*/
export const importActivities = async ({
Expand All @@ -151,12 +156,9 @@
activities: ActivityImport[];
}): Promise<ImportActivitiesResult> => {
try {
return await invoke<ImportActivitiesResult>("import_activities", {
accountId: activities[0].accountId,
activities,
});
return await invoke<ImportActivitiesResult>("import_activities", { activities });
} catch (err) {
logger.error(`Error importing activities: ${err}`);

Check warning on line 161 in apps/frontend/src/adapters/shared/activities.ts

View workflow job for this annotation

GitHub Actions / Frontend Check

Invalid type "unknown" of template literal expression
throw err;
}
};
Expand All @@ -165,39 +167,109 @@
* Check activities before import (read-only validation/preview).
* This performs read-only validation without creating assets or FX pairs.
* Asset creation happens during the actual import when user confirms.
* @param accountId - The account ID to import activities into
* @param activities - The activities to validate
*/
export const checkActivitiesImport = async ({
accountId,
activities,
}: {
accountId: string;
activities: ActivityImport[];
}): Promise<ActivityImport[]> => {
try {
return await invoke<ActivityImport[]>("check_activities_import", {
accountId,
activities,
});
return await invoke<ActivityImport[]>("check_activities_import", { activities });
} catch (err) {
logger.error(`Error checking activities import: ${err}`);

Check warning on line 180 in apps/frontend/src/adapters/shared/activities.ts

View workflow job for this annotation

GitHub Actions / Frontend Check

Invalid type "unknown" of template literal expression
throw err;
}
};

export const listImportTemplates = async (): Promise<ImportTemplateData[]> => {
try {
return await invoke<ImportTemplateData[]>("list_import_templates");
} catch (err) {
logger.error("Error listing import templates.");
throw err;
}
};

export const getImportTemplate = async (id: string): Promise<ImportTemplateData> => {
try {
return await invoke<ImportTemplateData>("get_import_template", { id });
} catch (err) {
logger.error("Error fetching import template.");
throw err;
}
};

export const saveImportTemplate = async (
template: ImportTemplateData,
): Promise<ImportTemplateData> => {
try {
return await invoke<ImportTemplateData>("save_import_template", { template });
} catch (err) {
logger.error("Error saving import template.");
throw err;
}
};

export const deleteImportTemplate = async (id: string): Promise<void> => {
try {
await invoke<void>("delete_import_template", { id });
} catch (err) {
logger.error("Error deleting import template.");
throw err;
}
};

/**
* Preview which assets would be created or matched for a set of import candidates.
*/
export const previewImportAssets = async ({
candidates,
}: {
candidates: ImportAssetCandidate[];
}): Promise<ImportAssetPreviewItem[]> => {
try {
return await invoke<ImportAssetPreviewItem[]>("preview_import_assets", { candidates });
} catch (err) {
logger.error(`Error previewing import assets: ${err}`);

Check warning on line 234 in apps/frontend/src/adapters/shared/activities.ts

View workflow job for this annotation

GitHub Actions / Frontend Check

Invalid type "unknown" of template literal expression
throw err;
}
};

/**
* Get the import mapping configuration for an account.
*/
export const getAccountImportMapping = async (accountId: string): Promise<ImportMappingData> => {
export const getAccountImportMapping = async (
accountId: string,
contextKind: string = ImportType.ACTIVITY,
): Promise<ImportMappingData> => {
try {
return await invoke<ImportMappingData>("get_account_import_mapping", { accountId });
return await invoke<ImportMappingData>("get_account_import_mapping", {
accountId,
contextKind,
});
} catch (err) {
logger.error("Error fetching mapping.");
throw err;
}
};

/**
* Link an account to an existing import template.
*/
export const linkAccountTemplate = async (
accountId: string,
templateId: string,
contextKind: string = ImportType.ACTIVITY,
): Promise<void> => {
try {
await invoke<void>("link_account_template", { accountId, templateId, contextKind });
} catch (err) {
logger.error("Error linking account to template.");
throw err;
}
};

/**
* Save the import mapping configuration for an account.
*/
Expand Down Expand Up @@ -226,3 +298,33 @@
throw err;
}
};

// ============================================================================
// Broker Sync Profile Commands
// ============================================================================

export const getBrokerSyncProfile = async (
accountId: string,
sourceSystem: string,
): Promise<BrokerSyncProfileData> => {
try {
return await invoke<BrokerSyncProfileData>("get_broker_sync_profile", {
accountId,
sourceSystem,
});
} catch (err) {
logger.error("Error fetching broker sync profile.");
throw err;
}
};

export const saveBrokerSyncProfileRules = async (
request: SaveBrokerSyncProfileRulesRequest,
): Promise<BrokerSyncProfileData> => {
try {
return await invoke<BrokerSyncProfileData>("save_broker_sync_profile_rules", { request });
} catch (err) {
logger.error("Error saving broker sync profile rules.");
throw err;
}
};
Loading
Loading