Skip to content

fix: share internal boot state across onboarding#1920

Merged
elibosley merged 2 commits intomainfrom
codex/share-internal-boot-state
Mar 16, 2026
Merged

fix: share internal boot state across onboarding#1920
elibosley merged 2 commits intomainfrom
codex/share-internal-boot-state

Conversation

@elibosley
Copy link
Member

@elibosley elibosley commented Mar 16, 2026

Summary

  • extract a shared internal boot state service that uses the same backend detection as the notification flow
  • expose that state through vars and use it to hide/block onboarding internal boot setup when the system is still booted from flash but internal boot is already configured
  • keep registration aligned with the same state while preserving the existing client-side fallback

Validation

  • pnpm lint in api/
  • pnpm type-check in api/
  • pnpm lint in web/
  • pnpm type-check in web/
  • targeted vitest coverage for onboarding, vars, notification, and registration flows

Summary by CodeRabbit

  • New Features

    • Detects if the system is booted from flash with internal boot already configured and surfaces this state.
    • Onboarding blocks re-configuration when internal boot is already enabled.
  • Improvements

    • Boot state is tracked and exposed across the UI and API for more accurate UI decisions.
    • Onboarding step visibility and the boot transfer button logic have been tightened and simplified.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 79db950d-7762-4a62-b5a7-13cd0479c7a7

📥 Commits

Reviewing files that changed from the base of the PR and between c9abf6f and 560da92.

📒 Files selected for processing (6)
  • api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.spec.ts
  • api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.ts
  • api/src/unraid-api/graph/resolvers/vars/vars.resolver.spec.ts
  • api/src/unraid-api/graph/resolvers/vars/vars.resolver.ts
  • web/__test__/store/server.test.ts
  • web/src/store/server.ts

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


Walkthrough

Adds a new boolean Vars field bootedFromFlashWithInternalBootSetup, a backend InternalBootStateService to determine that state (uses ArrayService + DisksService), updates onboarding and notification flows to respect it, and surfaces the field through GraphQL to frontend UI and store logic which hide/disable internal-boot configuration when appropriate.

Changes

Cohort / File(s) Summary
GraphQL Schema
api/generated-schema.graphql
Added bootedFromFlashWithInternalBootSetup: Boolean to Vars.
Internal boot state service & module
api/src/unraid-api/graph/resolvers/disks/internal-boot-state.service.ts, api/src/unraid-api/graph/resolvers/disks/disks.module.ts
New InternalBootStateService (depends on ArrayService, DisksService) with methods to determine boot-from-flash + internal-boot setup; exported from DisksModule.
Notification service updates
api/src/unraid-api/graph/resolvers/disks/internal-boot-notification.service.ts, api/src/unraid-api/graph/resolvers/disks/internal-boot-notification.service.spec.ts
Replaced DisksService usage with InternalBootStateService and updated method calls and tests to the new boolean-check API.
Onboarding changes & tests
api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.ts, api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.spec.ts
Injected InternalBootStateService into onboarding service; short-circuits internal-boot pool creation when already configured; tests updated/added to cover that path.
Vars resolver & model
api/src/unraid-api/graph/resolvers/vars/vars.model.ts, api/src/unraid-api/graph/resolvers/vars/vars.resolver.ts, api/src/unraid-api/graph/resolvers/vars/vars.resolver.spec.ts
Added optional field to Vars model; VarsResolver now fetches boot state via InternalBootStateService (with try/catch) and includes it in responses; tests adjusted to mock service and log on lookup failure.
Frontend GraphQL & types
web/src/composables/gql/graphql.ts, web/src/composables/gql/gql.ts, web/src/store/server.fragment.ts
Extended client GraphQL types and document literals to include bootedFromFlashWithInternalBootSetup in Vars for relevant queries (GetInternalBootContext, GetInternalBootStepVisibility, ServerState).
Frontend store & types
web/src/store/server.ts, web/types/server.ts, web/__test__/store/server.test.ts
Added bootedFromFlashWithInternalBootSetup to Server type and store; internal ref reportedBootedFromFlashWithInternalBootSetup and computed with fallback implemented; hydration and tests updated.
Frontend UI & tests
web/src/components/Onboarding/OnboardingModal.vue, web/src/components/Onboarding/steps/OnboardingInternalBootStep.vue, web/src/components/Registration.standalone.vue, web/src/components/Onboarding/graphql/*, web/__test__/components/Onboarding/*
UI now hides/disables internal-boot configuration when flag is true; eligibility logic updated; queries and tests adapted to pass/expect bootedFromFlashWithInternalBootSetup (tests for true/false/null cases added/modified).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as "UI / Client"
  participant Resolver as "VarsResolver"
  participant Service as "InternalBootStateService"
  participant Array as "ArrayService"
  participant Disks as "DisksService"

  UI->>Resolver: query vars
  Resolver->>Service: getBootedFromFlashWithInternalBootSetup()
  Service->>Array: getArray() / read boot disk
  Array-->>Service: bootDisk info
  Service->>Disks: getInternalBootDevices(bootDisk) (if FLASH)
  Disks-->>Service: devices[]
  Service-->>Resolver: boolean bootedFromFlashWithInternalBootSetup
  Resolver-->>UI: vars { ..., bootedFromFlashWithInternalBootSetup }
  UI->>UI: hide/disable internal-boot step (if true)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I sniff the flash, a secret found,
A tiny flag that keeps steps down,
We guard the pool, we skip the dance,
A quiet hop avoids mischance. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: extracting and sharing internal boot state detection logic across onboarding flows and notification systems.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/share-internal-boot-state
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use oxc to improve the quality of JavaScript and TypeScript code reviews.

Add a configuration file to your project to customize how CodeRabbit runs oxc.

Copy link

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

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: c9abf6f218

ℹ️ 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 +24 to +25
const bootedFromFlashWithInternalBootSetup =
await this.internalBootStateService.getBootedFromFlashWithInternalBootSetup();

Choose a reason for hiding this comment

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

P1 Badge Handle internal-boot probe failures in vars resolver

vars() now blocks on internalBootStateService.getBootedFromFlashWithInternalBootSetup(), but this probe can throw (it reaches DisksService.getInternalBootDevices(), which calls disk discovery methods that are not guarded for all failures). Because there is no try/catch or fallback here, a transient disk-inspection error will fail the entire vars query (and serverState queries that include vars) instead of returning the existing vars payload.

Useful? React with 👍 / 👎.

};
}

if (await this.isBootedFromFlashWithInternalBootSetup()) {

Choose a reason for hiding this comment

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

P1 Badge Keep preflight boot-state check inside mutation error path

The new isBootedFromFlashWithInternalBootSetup() check runs before the method’s try/catch, so if internal-boot state lookup throws (for example while reading array/disk state), createInternalBootPool() rejects with a GraphQL error instead of returning the structured OnboardingInternalBootResult failure response this mutation otherwise guarantees.

Useful? React with 👍 / 👎.

@codecov
Copy link

codecov bot commented Mar 16, 2026

Codecov Report

❌ Patch coverage is 85.26316% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.04%. Comparing base (2daceab) to head (560da92).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...aph/resolvers/disks/internal-boot-state.service.ts 52.17% 11 Missing ⚠️
.../src/unraid-api/graph/resolvers/vars/vars.model.ts 0.00% 2 Missing ⚠️
web/src/store/server.ts 90.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1920      +/-   ##
==========================================
+ Coverage   50.99%   51.04%   +0.05%     
==========================================
  Files        1024     1025       +1     
  Lines       70569    70640      +71     
  Branches     7717     7738      +21     
==========================================
+ Hits        35985    36061      +76     
+ Misses      34458    34453       -5     
  Partials      126      126              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.spec.ts`:
- Around line 243-247: The test is asserting the full error string which couples
it to wording; instead assert behavior and a meaningful substring: keep checking
result for ok: false and code: 3 (e.g., via toMatchObject or separate expects
against result) and replace the exact-string check on result.output with a
substring assertion (e.g., expect(result.output).toContain('boot is already
configured') or 'internal boot'), referencing the test variable result in
onboarding-internal-boot.service.spec.ts.

In
`@api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.ts`:
- Around line 351-357: The current pre-check calls
this.isBootedFromFlashWithInternalBootSetup() outside the surrounding try/catch
so any error from that lookup can escape and crash the mutation; move the
boot-state lookup into the guarded path by invoking
this.isBootedFromFlashWithInternalBootSetup() inside the existing try/catch (or
wrap it in its own try/catch) and return the same { ok:false, code:3, output:...
} response on a successful check while ensuring any thrown error is caught and
handled by the function's error handling.

In `@api/src/unraid-api/graph/resolvers/vars/vars.resolver.ts`:
- Around line 24-30: The vars() resolver currently awaits
internalBootStateService.getBootedFromFlashWithInternalBootSetup() which can
throw and cause the whole vars query to fail; wrap that call in a try/catch
inside vars() and on error set a safe default (e.g., null or false) for
bootedFromFlashWithInternalBootSetup and optionally log the error, then continue
returning the merged object (id: 'vars', ...(getters.emhttp().var ?? {}),
bootedFromFlashWithInternalBootSetup) so failures in internalBootStateService do
not surface as fatal resolver errors.

In `@web/src/store/server.ts`:
- Around line 1072-1074: The current guard using "typeof
data?.bootedFromFlashWithInternalBootSetup !== 'undefined'" prevents clearing
stale reportedBootedFromFlashWithInternalBootSetup values; change the check to
use "'bootedFromFlashWithInternalBootSetup' in data" and when that property
exists assign reportedBootedFromFlashWithInternalBootSetup.value =
data.bootedFromFlashWithInternalBootSetup so the value can be set to
undefined/false by mutateServerStateFromApi mapping; update the code around the
existing reportedBootedFromFlashWithInternalBootSetup assignment in server.ts
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a76466e7-5467-4496-b5a1-3e9733144beb

📥 Commits

Reviewing files that changed from the base of the PR and between 2daceab and c9abf6f.

📒 Files selected for processing (22)
  • api/generated-schema.graphql
  • api/src/unraid-api/graph/resolvers/disks/disks.module.ts
  • api/src/unraid-api/graph/resolvers/disks/internal-boot-notification.service.spec.ts
  • api/src/unraid-api/graph/resolvers/disks/internal-boot-notification.service.ts
  • api/src/unraid-api/graph/resolvers/disks/internal-boot-state.service.ts
  • api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.spec.ts
  • api/src/unraid-api/graph/resolvers/onboarding/onboarding-internal-boot.service.ts
  • api/src/unraid-api/graph/resolvers/vars/vars.model.ts
  • api/src/unraid-api/graph/resolvers/vars/vars.resolver.spec.ts
  • api/src/unraid-api/graph/resolvers/vars/vars.resolver.ts
  • web/__test__/components/Onboarding/OnboardingInternalBootStep.test.ts
  • web/__test__/components/Onboarding/OnboardingModal.test.ts
  • web/src/components/Onboarding/OnboardingModal.vue
  • web/src/components/Onboarding/graphql/getInternalBootContext.query.ts
  • web/src/components/Onboarding/graphql/getInternalBootStepVisibility.query.ts
  • web/src/components/Onboarding/steps/OnboardingInternalBootStep.vue
  • web/src/components/Registration.standalone.vue
  • web/src/composables/gql/gql.ts
  • web/src/composables/gql/graphql.ts
  • web/src/store/server.fragment.ts
  • web/src/store/server.ts
  • web/types/server.ts

@elibosley
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions
Copy link
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL:

https://preview.dl.unraid.net/unraid-api/tag/PR1920/dynamix.unraid.net.plg

@elibosley elibosley changed the title Share internal boot state across onboarding and notifications fix: share internal boot state across onboarding Mar 16, 2026
@elibosley elibosley merged commit f9b293f into main Mar 16, 2026
12 checks passed
@elibosley elibosley deleted the codex/share-internal-boot-state branch March 16, 2026 15:13
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