Skip to content

Adds offline news and improves post extraction - #215

Merged
fboucher merged 33 commits into
mainfrom
v-next
Oct 25, 2026
Merged

fboucher merged 33 commits into
mainfrom
v-next

Conversation

@fboucher

Copy link
Copy Markdown
Owner

Summary

This update introduces an offline-capable news and updates feed to the MAUI application's home page and enhances the API's post extraction endpoint to prevent duplicate entries for the same URL.

Motivation

The changes aim to provide users with a consistent product news experience, even when offline, by caching updates locally. Additionally, they address an issue where the same post could be saved multiple times, leading to data duplication and an inconsistent user experience, particularly with quick add functionality and prerendering scenarios.

Changes

  • Offline News & Updates:
    • Introduces a NewsFeedService in the MAUI app to fetch, cache, and display product news from a markdown file on GitHub.
    • Enables offline access by downloading markdown content and any referenced images, embedding images as base64 data URLs in the rendered HTML.
    • Includes HTML sanitization to enhance security by filtering potentially unsafe links and image sources.
    • Integrates the news feed refresh mechanism into the background synchronization process to ensure timely updates.
    • Adds a new docs/news.md file to serve as the source for the news feed content.
  • Duplicate Post Prevention:
    • The API's extractPostDetails endpoint now checks for existing posts by URL before performing a new extraction and save operation. If a post with the same URL is found, the existing post is returned, preventing duplicates.
    • The QuickAdd component in the Blazor application is updated to handle prerendering effectively, ensuring that post details are extracted and saved only once across prerendered and interactive component lifecycles.

Tests

  • API: New tests verify that calling extractPostDetails multiple times for the same URL results in a single stored post and returns the existing one. Dedicated tests for the new GetPostByUrl data storage method are also included.
  • Blazor App: Tests confirm that the QuickAdd component saves a post only once when prerendered and then rendered interactively, and correctly shows progress without saving during prerendering.
  • MAUI App: Extensive tests for NewsFeedService cover caching behavior, offline rendering, image embedding, HTML sanitization, and graceful failure handling. The SyncService tests now also verify the news feed refresh.

  • Bug fixes
  • New features
  • Breaking changes
  • Performance improvements
  • Documentation updates
  • Security enhancements
  • Test coverage
  • Build system or CI/CD updates

fboucher-os and others added 30 commits August 8, 2026 08:34
…or (issue #92) (#183)

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>
… in blob storage (#185)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
…d remove ILocalHtmlCache (#186)

* feat: implement async background post content extraction to save HTML in blob storage

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache
…on (#187)

* feat: configure protected Azure Function Parser API and key propagation

* bump: version to 1.4.0

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
# Conflicts:
#	src/NoteBookmark.BlazorApp.Tests/Tests/PostsTests.cs
#	src/NoteBookmark.BlazorApp/Program.cs
#	src/NoteBookmark.SharedUI/Components/Pages/Posts.razor
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…controls (#192)

* chore: bump version to 1.4.2

* feat: show detailed sync progress messages and progress bar on Posts page

* feat: add back button and text size slider at both top and bottom of reader page
Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
* feat: add MAUI storage tab for offline posts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: refine MAUI storage controls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: highlight storage actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… workflow (#204) (#205)

* v1.4.3 - Enhances MAUI sync, local storage, and reader (#202)

* fix(#173): use Id ?? RowKey for checking and opening offline post HTML (#179)

* feat(#176): add sync progress bar and status updates for downloading offline post text (#180)

* should have done that long ago

* fix: resolve Android MAUI app crash when opening URLs (issue #177) (#181)

* feat: add up/down reordering for categories and notes in summary editor (issue #92) (#183)

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>

* feat: add text size slider and fix text wrapping on offline reader page (issue #178) (#182)

* bumb version

* feat: implement async background post content extraction to save HTML in blob storage (#185)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache (#186)

* feat: implement async background post content extraction to save HTML in blob storage

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache

* feat: configure protected Azure Function Parser API and key propagation (#187)

* feat: configure protected Azure Function Parser API and key propagation

* bump: version to 1.4.0

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* update missing env variable

* fix

* chore: bump version to 1.4.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(#190): update actions/cache to v5 for Node.js 24 compatibility in OpenCode triage workflow (#191)

* Update version to 1.4.2, add sync progress tracking, and reader page controls (#192)

* chore: bump version to 1.4.2

* feat: show detailed sync progress messages and progress bar on Posts page

* feat: add back button and text size slider at both top and bottom of reader page

* ci: include version in android apk filename (#193)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* Fix document sync stuck and improve sync progress and offline fallback (fixes #196) (#199)

* fix: constrain reader text size slider and add step buttons (fixes #195) (#198)

* feat: Add markdown saving for reading notes and bump version to 1.4.3

* feat: add MAUI storage tab (#200)

* feat: add MAUI storage tab for offline posts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: refine MAUI storage controls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: highlight storage actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump application version to 1.4.3 (#201)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(ci): prevent timeout and rate limits in opencode daily triage (#204)

---------

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…let (#203) (#207)

* v1.4.3 - Enhances MAUI sync, local storage, and reader (#202)

* fix(#173): use Id ?? RowKey for checking and opening offline post HTML (#179)

* feat(#176): add sync progress bar and status updates for downloading offline post text (#180)

* should have done that long ago

* fix: resolve Android MAUI app crash when opening URLs (issue #177) (#181)

* feat: add up/down reordering for categories and notes in summary editor (issue #92) (#183)

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>

* feat: add text size slider and fix text wrapping on offline reader page (issue #178) (#182)

* bumb version

* feat: implement async background post content extraction to save HTML in blob storage (#185)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache (#186)

* feat: implement async background post content extraction to save HTML in blob storage

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache

* feat: configure protected Azure Function Parser API and key propagation (#187)

* feat: configure protected Azure Function Parser API and key propagation

* bump: version to 1.4.0

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* update missing env variable

* fix

* chore: bump version to 1.4.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(#190): update actions/cache to v5 for Node.js 24 compatibility in OpenCode triage workflow (#191)

* Update version to 1.4.2, add sync progress tracking, and reader page controls (#192)

* chore: bump version to 1.4.2

* feat: show detailed sync progress messages and progress bar on Posts page

* feat: add back button and text size slider at both top and bottom of reader page

* ci: include version in android apk filename (#193)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* Fix document sync stuck and improve sync progress and offline fallback (fixes #196) (#199)

* fix: constrain reader text size slider and add step buttons (fixes #195) (#198)

* feat: Add markdown saving for reading notes and bump version to 1.4.3

* feat: add MAUI storage tab (#200)

* feat: add MAUI storage tab for offline posts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: refine MAUI storage controls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: highlight storage actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump application version to 1.4.3 (#201)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fixes CI timeout and rate limits in triage workflow (#206)

* fix(#173): use Id ?? RowKey for checking and opening offline post HTML (#179)

* feat(#176): add sync progress bar and status updates for downloading offline post text (#180)

* should have done that long ago

* fix: resolve Android MAUI app crash when opening URLs (issue #177) (#181)

* feat: add up/down reordering for categories and notes in summary editor (issue #92) (#183)

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>

* feat: add text size slider and fix text wrapping on offline reader page (issue #178) (#182)

* bumb version

* feat: implement async background post content extraction to save HTML in blob storage (#185)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache (#186)

* feat: implement async background post content extraction to save HTML in blob storage

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache

* feat: configure protected Azure Function Parser API and key propagation (#187)

* feat: configure protected Azure Function Parser API and key propagation

* bump: version to 1.4.0

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* update missing env variable

* fix

* chore: bump version to 1.4.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(#190): update actions/cache to v5 for Node.js 24 compatibility in OpenCode triage workflow (#191)

* Update version to 1.4.2, add sync progress tracking, and reader page controls (#192)

* chore: bump version to 1.4.2

* feat: show detailed sync progress messages and progress bar on Posts page

* feat: add back button and text size slider at both top and bottom of reader page

* ci: include version in android apk filename (#193)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* Fix document sync stuck and improve sync progress and offline fallback (fixes #196) (#199)

* fix: constrain reader text size slider and add step buttons (fixes #195) (#198)

* feat: Add markdown saving for reading notes and bump version to 1.4.3

* feat: add MAUI storage tab (#200)

* feat: add MAUI storage tab for offline posts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: refine MAUI storage controls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: highlight storage actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump application version to 1.4.3 (#201)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(ci): fix timeout and rate limit failures in OpenCode Daily Triage workflow (#204) (#205)

* v1.4.3 - Enhances MAUI sync, local storage, and reader (#202)

* fix(#173): use Id ?? RowKey for checking and opening offline post HTML (#179)

* feat(#176): add sync progress bar and status updates for downloading offline post text (#180)

* should have done that long ago

* fix: resolve Android MAUI app crash when opening URLs (issue #177) (#181)

* feat: add up/down reordering for categories and notes in summary editor (issue #92) (#183)

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>

* feat: add text size slider and fix text wrapping on offline reader page (issue #178) (#182)

* bumb version

* feat: implement async background post content extraction to save HTML in blob storage (#185)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache (#186)

* feat: implement async background post content extraction to save HTML in blob storage

* feat: improve sync html download, always display read post button, and remove ILocalHtmlCache

* feat: configure protected Azure Function Parser API and key propagation (#187)

* feat: configure protected Azure Function Parser API and key propagation

* bump: version to 1.4.0

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* update missing env variable

* fix

* chore: bump version to 1.4.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(#190): update actions/cache to v5 for Node.js 24 compatibility in OpenCode triage workflow (#191)

* Update version to 1.4.2, add sync progress tracking, and reader page controls (#192)

* chore: bump version to 1.4.2

* feat: show detailed sync progress messages and progress bar on Posts page

* feat: add back button and text size slider at both top and bottom of reader page

* ci: include version in android apk filename (#193)

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>

* Fix document sync stuck and improve sync progress and offline fallback (fixes #196) (#199)

* fix: constrain reader text size slider and add step buttons (fixes #195) (#198)

* feat: Add markdown saving for reading notes and bump version to 1.4.3

* feat: add MAUI storage tab (#200)

* feat: add MAUI storage tab for offline posts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: refine MAUI storage controls

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: highlight storage actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump application version to 1.4.3 (#201)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(ci): prevent timeout and rate limits in opencode daily triage (#204)

---------

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: fboucher-os <fboucheros+github@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(ui): add browser bookmarklet support for saving URLs (#203)

* feat(ui): add dedicated quickadd popup and MinimalLayout for bookmarklet (#203)

---------

Co-authored-by: Frank Boucher <2404846+fboucher@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Speed up MAUI sync: delta pull, batched saves, off-UI-thread (#208)

- Pull only posts modified since the last sync; detect server deletions
  with a new lightweight GET api/posts/ids endpoint (falls back to the
  full list on first sync or on servers without the endpoint).
- Save pulled posts in one SQLite transaction and remove deleted posts
  in one batch.
- Fetch full details for unread posts with at most 5 concurrent requests.
- Run sync on the thread pool and throttle progress events to ~250 ms.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kq68qA7Jv7puAF3Kc6GSFY

* Restore CRLF line endings in LocalDataService and PostNoteClient

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kq68qA7Jv7puAF3Kc6GSFY

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts from squash-merged v1.4.3 content on main by keeping
v-next's versions; main's src tree was identical to v-next at 9d76219.
Keeps main's disabled schedule in opencode-triage.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fboucher and others added 2 commits October 4, 2026 09:39
The Quick Add page is rendered with InteractiveServer and prerendering, so
two component instances ran OnParametersSetAsync and each called
ExtractPostDetailsAndSave, which mints a new RowKey per call.

- QuickAdd skips the save while prerendering (RendererInfo.IsInteractive)
  and shows the progress spinner; the interactive render does the save.
- The extractPostDetails endpoint returns the existing post when one is
  already stored for the URL, so repeat requests never add a duplicate.


Claude-Session: https://claude.ai/code/session_014Yup1wuZFURs47VNTrAK7g

Co-authored-by: Claude <noreply@anthropic.com>
* Add offline news feed to home page

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review feedback on the news feed

- Register NewsFeedService once as a singleton through an explicit
  factory, so DI no longer has to pick between two constructors and
  sync and the home page share a single refresh lock and cache.
- Discover and rewrite images from Markdig's parse tree instead of a
  regex, which adds reference-style images and paths with parentheses
  and ignores image syntax inside code blocks.
- Raise FeedUpdated after a successful refresh and reload the home
  page feed when it fires, so content downloaded by sync shows up
  without navigating away.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjU7ggv2Jnx9sqVXACepgC

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Resolve add/add conflicts in QuickAdd.razor and QuickAddTests.cs by keeping
the v-next versions, which already contain main's squashed v1.4.4 changes
plus the prerender double-save fix (#211).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NMPHkFaCRSv16LTKQVCRJX
@github-actions

Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Health
NoteBookmark.AIServices 97% 64% ✔
NoteBookmark.Api 89% 80% ✔
NoteBookmark.BlazorApp 4% 10% ❌
NoteBookmark.Domain 93% 76% ✔
NoteBookmark.ServiceDefaults 96% 75% ✔
NoteBookmark.SharedUI 26% 33% ❌
Summary 58% (1172 / 2016) 51% (346 / 681) ❌

@fboucher
fboucher marked this pull request as ready for review October 25, 2026 15:15
@fboucher
fboucher merged commit 1874c9c into main Oct 25, 2026
2 checks passed
@fboucher fboucher moved this from Merged to Done in Open Source Workbench Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants