Skip to content

Add desktop import connectors to Apps page#6364

Merged
kodjima33 merged 2 commits into
mainfrom
codex/apps-imports-ui-prototype
Apr 6, 2026
Merged

Add desktop import connectors to Apps page#6364
kodjima33 merged 2 commits into
mainfrom
codex/apps-imports-ui-prototype

Conversation

@kodjima33
Copy link
Copy Markdown
Collaborator

Summary\n- add an Imports section to the desktop Apps page for Calendar, Email, Local files, Apple Notes, ChatGPT, and Claude\n- wire connector cards to working import flows with stateful Connected/Update actions and branded icons\n- add Apple Notes folder fallback and keep Create App/Category controls visually neutral\n\n## Testing\n- cd desktop/Desktop && swift test --filter OnboardingFlowTests\n- cd desktop && ./run.sh --yolo

@kodjima33 kodjima33 merged commit 4edb356 into main Apr 6, 2026
1 check passed
@kodjima33 kodjima33 deleted the codex/apps-imports-ui-prototype branch April 6, 2026 19:48
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 6, 2026

Greptile Summary

Adds an Imports section to the desktop Apps page wiring six connector cards (Calendar, Gmail, Local Files, Apple Notes, ChatGPT, Claude) to existing import services with stateful Connected/Update actions and branded icons. All findings are P2 style items that do not affect the primary import flows.

Confidence Score: 5/5

Safe to merge — all findings are P2 style items with no impact on import correctness or user data

Three P2 findings (locale-sensitive number parsing, dead switch block, un-annotated static cache) are style improvements only; no P0 or P1 defects found in the new import connector flows

AppsPage.swift (importedMemoriesCount locale safety) and ConnectorBrandIcon.swift (static cache annotation)

Important Files Changed

Filename Overview
desktop/Desktop/Sources/MainWindow/Pages/AppsPage.swift Adds ImportsSection, ImportConnectorStatusStore, and ImportConnectorSheet; fragile locale-sensitive memory-count parsing and a dead switch in importAppleNotes are minor cleanup items
desktop/Desktop/Sources/ConnectorBrandIcon.swift New ConnectorBrandIcon view with app-icon resolution and bundled PNG fallback; static cache var lacks @mainactor annotation
desktop/Desktop/Sources/AppleNotesReaderService.swift Adds folder-fallback resolution for locating NoteStore.sqlite across sandboxed paths; logic is correct
desktop/Desktop/Sources/OnboardingMemoryLogImportService.swift New actor for importing ChatGPT/Claude memory exports via JSON extraction and memory creation; straightforward implementation
desktop/Desktop/Sources/MainWindow/DesktopHomeView.swift Minor change to pass appState into AppsPage to enable local-files rescan support

Sequence Diagram

sequenceDiagram
    participant U as User
    participant AP as AppsPage
    participant SS as ImportConnectorStatusStore
    participant SH as ImportConnectorSheet
    participant SVC as Import Service
    participant API as APIClient

    U->>AP: Opens Apps page
    AP->>SS: snapshot(for: connector)
    SS-->>AP: Snapshot(isConnected, actionTitle, metricText)
    U->>AP: Taps connector card
    AP->>SH: Present ImportConnectorSheet
    U->>SH: Taps primary action button
    SH->>SVC: importCalendar() / importGmail() / importAppleNotes() / importMemoryLog()
    SVC->>API: createMemory(content:tags:source:)
    API-->>SVC: Memory saved
    SVC-->>SH: (memories, profileSummary)
    SH->>SS: markImported(connectorID:memories:)
    SS->>SS: Persist count to UserDefaults
    SH-->>U: Show status message
Loading

Comments Outside Diff (1)

  1. desktop/Desktop/Sources/ConnectorBrandIcon.swift, line 55 (link)

    P2 Mutable static cache lacks actor isolation

    private static var cache carries no actor annotation. While in practice it is only written from ConnectorBrandIcon.body (implicitly @MainActor), Swift's strict concurrency checking (-strict-concurrency=complete) would flag this as a potential data race. Annotating it @MainActor makes the intent explicit and forward-compatible.

Reviews (1): Last reviewed commit: "Merge main into apps imports branch" | Re-trigger Greptile

Comment on lines +1099 to +1104
private func importedMemoriesCount(from statusMessage: String?) -> Int? {
guard let statusMessage else { return nil }
let values = statusMessage
.split(whereSeparator: { !$0.isNumber })
.compactMap { Int($0) }
return values.last
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Locale-sensitive number parsing

Int.formatted() respects the device locale — on locales with a non-ASCII thousands separator (French "1 234", German "1.234"), split(whereSeparator: { !$0.isNumber }) fragments the number and .last returns the trailing segment rather than the full value. A status string of "saved 1.234 memories" would persist 234 to UserDefaults instead of 1234, causing connector cards to display the wrong imported-memory count.

Suggested change
private func importedMemoriesCount(from statusMessage: String?) -> Int? {
guard let statusMessage else { return nil }
let values = statusMessage
.split(whereSeparator: { !$0.isNumber })
.compactMap { Int($0) }
return values.last
private func importedMemoriesCount(from statusMessage: String?) -> Int? {
guard let statusMessage else { return nil }
// Avoid locale-formatted separators splitting "1,234" into ["1", "234"].
// The memory count is the last all-digit token in every status message.
let tokens = statusMessage.components(separatedBy: .whitespaces)
return tokens.last(where: { $0.allSatisfy(\.isNumber) }).flatMap { Int($0) }
}

Comment on lines +832 to +837
} catch let error as AppleNotesReaderError {
switch error {
case .storeNotFound, .storeUnavailable:
break
}
let granted = await selectAppleNotesFolder()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Dead switch block is a no-op

Both arms of this exhaustive switch just break, so execution always falls through to selectAppleNotesFolder() regardless of which AppleNotesReaderError was thrown. The block adds no runtime effect and could mislead anyone who adds a new case to AppleNotesReaderError expecting per-case differentiation here.

Suggested change
} catch let error as AppleNotesReaderError {
switch error {
case .storeNotFound, .storeUnavailable:
break
}
let granted = await selectAppleNotesFolder()
} catch let error as AppleNotesReaderError {
let granted = await selectAppleNotesFolder()

Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
## Summary\n- add an Imports section to the desktop Apps page for
Calendar, Email, Local files, Apple Notes, ChatGPT, and Claude\n- wire
connector cards to working import flows with stateful Connected/Update
actions and branded icons\n- add Apple Notes folder fallback and keep
Create App/Category controls visually neutral\n\n## Testing\n- cd
desktop/Desktop && swift test --filter OnboardingFlowTests\n- cd desktop
&& ./run.sh --yolo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant