Skip to content

Add adaptive guided tours to the new UI - #2506

Draft
niemyjski wants to merge 63 commits into
mainfrom
feature/ui-guided-tours-review
Draft

Add adaptive guided tours to the new UI#2506
niemyjski wants to merge 63 commits into
mainfrom
feature/ui-guided-tours-review

Conversation

@niemyjski

@niemyjski niemyjski commented Aug 20, 2026

Copy link
Copy Markdown
Member

What changed

Adds five contextual guides to the Svelte UI, accessible from Help and the command palette. Guides cover navigation, project setup, saved views, error investigation, and Exie.

  • Stores first completion and invitation acknowledgment dates in a typed ProductTourState on the user. The self-only PUT /api/v2/users/me/product-tours/{tourName}/record operation validates ProductTourNames.All and uses the existing user load/save pattern.

  • Keeps active steps in memory. Reload ends an unfinished guide; users can restart it from Help. Finishing or dismissing exits locally even if saving fails or remains pending. Guide dismissal does not record completion.

  • Uses the existing feature-usage submission path for completed/dismissed actions. Removes the custom reporting UI, aggregation endpoint, version tracking, and session-storage layer.

  • Uses generated API types, typed route identifiers, and ordinary user-query invalidation. Preserves the shared-filter hydration fix and its regression coverage.

  • Opens Change Plan directly from the Exie announcement’s Upgrade Plan action, preselects the required tier, and refreshes access after a successful change.

  • Enforces blank lines between control-flow blocks in TypeScript and explicit class-member visibility; the visibility cleanup preserves emitted JavaScript.

Verification

  • Solution build: 0 warnings/errors.
  • Backend endpoint and serializer tests: 21 passed.
  • Frontend unit suite: 821 passed, including direct upgrade routing, disabled-billing fallback, and identity transitions.
  • Frontend validation and production build passed.
  • Local Playwright checks cover acknowledgment across reload, fresh replay after reload, Escape without completion, completion refetching, and saved-view success with failed preference persistence. Desktop/mobile welcome and saved-view screenshots inspected. The upgrade CTA was also checked before/after in the local browser with access/plan fixtures: it opens Change Plan with the required tier selected, without submitting billing changes.

Compatibility

Replacement for #2458, reverted by #2505. The API and stored shape replace the previous version of this PR. Before deployment, confirm whether a reverted-tour deployment persisted the old status/version shape; that deployment/data history remains unverified. Remains draft and unmerged.

@niemyjski
niemyjski marked this pull request as draft August 20, 2026 14:45
@niemyjski niemyjski self-assigned this Aug 25, 2026
@niemyjski
niemyjski force-pushed the feature/ui-guided-tours-review branch 7 times, most recently from b22a86a to db17534 Compare September 3, 2026 03:45
@niemyjski
niemyjski force-pushed the feature/ui-guided-tours-review branch from c3d3fb5 to 9546c7f Compare September 4, 2026 19:33
Comment thread src/Exceptionless.Core/Models/Data/ProductTourProgress.cs Outdated
Comment thread src/Exceptionless.Core/Models/Data/ProductTours.cs Outdated
Comment thread src/Exceptionless.Core/Models/User.cs Outdated
Comment thread src/Exceptionless.Core/Repositories/Interfaces/IEventRepository.cs Outdated
Comment thread src/Exceptionless.Core/Repositories/EventRepository.cs Outdated
Comment thread src/Exceptionless.Core/Repositories/ProductTourUsageResult.cs Outdated
Comment thread src/Exceptionless.Core/Repositories/UserRepository.cs Outdated
Comment thread src/Exceptionless.Web/Api/Endpoints/AdminEndpoints.cs Outdated
Comment thread src/Exceptionless.Web/Api/Endpoints/AdminEndpoints.cs Outdated
Comment thread src/Exceptionless.Web/Api/Endpoints/UserEndpoints.cs Outdated
@niemyjski
niemyjski force-pushed the feature/ui-guided-tours-review branch from 1233eba to 97a1a43 Compare September 5, 2026 16:19
Comment thread src/Exceptionless.Web/Api/Endpoints/UserEndpoints.cs Outdated
Comment thread src/Exceptionless.Web/Api/Handlers/AdminHandler.cs Outdated
Comment thread src/Exceptionless.Web/Api/Handlers/ProductTourActivityHandler.cs Outdated
Comment thread src/Exceptionless.Web/Api/Handlers/ProductTourActivityHandler.cs Outdated
Comment thread src/Exceptionless.Web/Api/Handlers/ProductTourActivityHandler.cs Outdated
Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/product-tours/api.svelte.ts Outdated
Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/product-tours/catalog.ts Outdated
@niemyjski
niemyjski force-pushed the feature/ui-guided-tours-review branch 2 times, most recently from 97c915f to 81599b4 Compare September 5, 2026 18:42
@niemyjski

niemyjski commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

Guided-tour review update — September 8

Head: e58ee7774, based on main 5aeca2d89. All 58 inline review threads have replies and are resolved.

This pass

  • Fixed retained-history cutoff to UTC midnight, matching cleanup. A failing repository regression proved the prior query omitted valid events earlier on the first retained day.
  • Reused Exceptionless date comparison helpers and made the future-only empty-range check distinct from invalid input validation.
  • Added the chart slider's Up/Down behavior and boundary coverage. Invitation-only historical Started activity now correctly produces an empty state instead of an all-zero chart.
  • Reused the shared DateTime component for tooltip/table labels, with explicit UTC options and regression coverage preserving every existing default formatting option.
  • Deleted product-tour-usage.ts, its mode union, and browser calendar arithmetic. The picker passes a standard time expression through; the backend resolves dates with DateTimeRange and Elasticsearch selects buckets. Existing start/end callers remain supported. Added server-side rolling/month, February/leap-year, year-boundary, exact event-boundary, and invalid/mixed-filter tests. Updated the prior review reply, which had only moved the conversion rather than removing it.
  • Removed duplicated invitation visibility and successful-save handling from the host, reducing it by 24 lines without a new state layer. The existing identity, storage-denial, and retry guards remain.
  • Corrected the JSON fixture annotation to the existing /* language=json */ convention.
  • Corrected the cache response path: after reading fresh stored progress, refresh both user-ID and email cache entries through the existing repository cache writer. Removed the Cache(false) call and the earlier justification for bypassing refresh. A regression failed before this correction and now verifies two cache hits, no additional misses, and updated progress through both lookup paths.
  • Reproduced first-organization checkpoint loss during both organization refresh and project creation. The route-only timing change was insufficient: organization query updates can change context before the mutation returns. The host now binds the same user's unscoped setup checkpoint to their first organization on the setup route, preserving the current step and existing identity-switch clearing. Added deterministic browser coverage holding both requests. Ordinary setup submission and the shared organization mutation are unchanged.
  • Reproduced deserialization failure for legacy string-valued tour statuses from the earlier merged implementation. Added storage/cache-only compatibility decoding with numeric writes, preserving the strict numeric API input and unchanged OpenAPI schema. The atomic update recognizes legacy completed status and cannot downgrade it. New historical JSON and repository/API regressions cover decoding, current-user loading, numeric output, and precedence. Earlier coverage omitted historical string-valued records.

Reviewed suggestions intentionally not applied

  • Non-nullable request status: retained [Required] on the nullable input so explicit null reaches semantic validation and returns the requested 422 rather than changing binding to 400. Added separate omitted-status and explicit-null tests. Persisted status remains a non-nullable numeric enum; no storage or generated-contract changes were needed.

Verification

  • Release backend build: zero warnings/errors.
  • Full backend suite on the current head: 3,004 passed, three intentional skips, including legacy string progress, server date filtering, cache hits, concurrent progress updates, missing users, and omitted/null status validation. OpenAPI snapshot verified; generated client models remain unchanged.
  • Full frontend suite: 844 passed (four obsolete client date-calculation cases removed and covered server-side). Svelte check: zero errors/warnings. Formatting, ESLint, and production build passed.
  • Luna high independent final pass: 87 focused tests passed; zero type errors/warnings. Independently confirmed the host refactor's gating and successful-only activity behavior.
  • Final rendered browser pass: 15/15 passed against the updated localhost API, covering first-organization creation, all affected tour flows, real API range comparisons, keyboard chart controls/tooltips, mobile, reduced motion, storage denial, invitation retry, identity isolation, and light/dark layouts. Synthetic screenshots remain explicitly labeled. An intermediate run overlapped build-triggered Vite reloads and failed two invitation cases; the final run was sequenced after build completion and passed without changing timeouts or weakening assertions.
  • One initial browser comparison mismatched a period's response and displayed totals; a traced rerun passed. Strengthened response matching to require the selected range's parameters rather than accepting any usage response. The full affected suite then passed with traces; no application delay or relaxed count assertion was added.
  • Hosted checks are running on the current head. The PR remains ready for review as requested. No merge, release, or deployment performed.

The first-day retention and Up/Down failures were missing boundary cases in earlier tests, now covered. Existing dependency advisories on main remain unchanged; this pass adds no dependencies.

@niemyjski
niemyjski force-pushed the feature/ui-guided-tours-review branch 4 times, most recently from 57cb577 to bf2c3ea Compare September 6, 2026 03:01
Comment thread tests/Exceptionless.Tests/Serializer/Models/UserSerializerTests.cs Outdated

Copilot AI left a comment

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.

🔵 Needs a closer look

Broad cross-stack changes and unresolved moderate findings require final human review.

Review details

Files not reviewed (1)

  • src/Exceptionless.Web/ClientApp/package-lock.json: Generated file

Suppressed comments (2)

src/Exceptionless.Web/ClientApp/src/lib/features/admin/components/product-tour-activity.svelte:47

  • For invitations, started is intentionally not rendered, but it still contributes to total. A period containing only historical prompt-start telemetry therefore shows a chart and zero-valued Shown/Accepted/Dismissed series instead of the empty state. Compute the total from the displayed keys.
    const total = $derived(tour.shown + tour.started + tour.completed + tour.dismissed);

src/Exceptionless.Web/Models/User/UpdateProductTourProgress.cs:10

  • Status is required by validation but nullable in the OpenAPI contract. Consequently the generated client declares status?: null | ProductTourStatus, even though either form receives a 422 response. Make the request contract non-nullable while preserving missing-value validation, and update the handler accordingly.
  • Files reviewed: 103/106 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread src/Exceptionless.Core/Repositories/EventRepository.cs Outdated
@niemyjski
niemyjski marked this pull request as ready for review September 8, 2026 12:43
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-09T02:48:36.961564Z f992143 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2ef1ac827

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Exceptionless.Core/Repositories/UserRepository.cs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8bba742ea7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5b45ad1a00

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Exceptionless.Core/Models/Data/ProductTourProgress.cs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 77755fff07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +9 to +12
public enum ProductTourStatus
{
Completed = 1,
Dismissed = 2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore decoding of legacy string tour statuses

Users whose documents were written during the earlier merged-and-reverted tour implementation can still have product_tours.*.status stored as "dismissed" or "completed", but this enum now accepts only numeric JSON, causing deserialization of the entire user document to fail. Fresh evidence in this target is that the later simplification removed ProductTourStatusConverter and its legacy regression tests, undoing the fix acknowledged in the existing thread; retain backward-compatible reading while continuing to write the numeric API/storage format.

AGENTS.md reference: AGENTS.md:L72-L75

Useful? React with 👍 / 👎.


await PatchAsync(userId, patch, options => options.Cache());

var user = await GetByIdAsync(userId, options => options.Cache());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refresh the user cache from an authoritative read

When an authentication read that started before PatchAsync repopulates the old user after the patch invalidates its cache entries, this cache-enabled read can return that stale document and leave both ID and email lookups stale, so a completed or dismissed tour can reappear. Fresh evidence in this target is that it again uses GetByIdAsync(...Cache()) and has removed the authoritative read plus AddDocumentsToCacheAsync refresh that the existing thread identified as its fix.

AGENTS.md reference: AGENTS.md:L72-L75

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f275caae14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +91 to +92
if (current != null && (current.version > params.version ||
(current.version == params.version && (current.status == params.completedStatus || current.status == params.status)))) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve legacy completed status in the atomic patch

When a legacy record has status: "completed" and the user later dismisses a restarted guide at the same version, this predicate compares the stored string only with numeric enum values, falls through to the update branch, and overwrites the completion with Dismissed. Restoring the legacy deserializer identified in the existing review is insufficient because the script operates directly on the persisted source; also recognize the legacy "completed" value here or normalize it before applying completion precedence.

AGENTS.md reference: AGENTS.md:L72-L75

Useful? React with 👍 / 👎.

@niemyjski
niemyjski marked this pull request as draft September 9, 2026 15:39
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Complexity Health
Exceptionless.Insulation 37% 35% 286
Exceptionless.Web 85% 70% 8149
Exceptionless.Core 76% 68% 10498
Exceptionless.AppHost 38% 41% 147
Summary 79% (26374 / 33407) 68% (12235 / 18047) 19080

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants