Skip to content

feat(native): auto-generated UI for Configurable settings via inventory registry#232

Closed
cooper (czxtm) wants to merge 2 commits into
05-28-apply_suggestions_from_code_reviewfrom
cm/derive-settings-ui
Closed

feat(native): auto-generated UI for Configurable settings via inventory registry#232
cooper (czxtm) wants to merge 2 commits into
05-28-apply_suggestions_from_code_reviewfrom
cm/derive-settings-ui

Conversation

@czxtm
Copy link
Copy Markdown
Member

Summary

Test Plan

Docs

  • Docs updated (companion PR in darkmatter/nixmac-web: #___)
  • No docs update needed

cooper (czxtm) and others added 2 commits May 28, 2026 15:13
…ry registry

Adding a new field to a Configurable struct now automatically appears in
the Tuning section of the Developer settings tab — no frontend changes
required. Schema metadata (label, type, range, defaults, help text) is
emitted by the derive and consumed by a generic <AutoConfigField> React
component.

How it works:

1. The configurable runtime crate gains schema types (ConfigurableSchema,
   ConfigField, FieldType, EnumVariant) that flow to TS via specta. A
   type-erased RegisteredConfig holds fn pointers per struct; the derive
   submits one to a global inventory at compile time.

2. The derive parses an expanded attribute grammar:
     #[config(
         store_path_fn = ...,
         display_name = "Evolution",
         description = "...",
     )]
     pub struct EvolutionLimits {
         #[config(
             default = 25,
             key = "maxIterations",
             label = "Max iterations",
             range = 1..=200,
             help = "API calls before stopping",
         )]
         pub max_iterations: usize,
     }

   FieldType is inferred from the Rust type: numeric primitives become
   Number{min,max}, bool becomes Boolean, String becomes String{multiline}.
   Any field annotated with #[config(options = ["a", "b"])] becomes an
   Enum regardless of its Rust type — labels are humanized from the
   variant values.

3. Each struct's derive generates:
     - load<R>(app)              — read all fields with defaults
     - schema<R>(app)            — full schema + current values
     - set_field<R>(app, k, v)   — type-checked single-field write
     - Wry-monomorphic shims for the fn pointers in RegisteredConfig

4. Two Tauri commands wrap the registry:
     - dev_configs_list          — walks inventory, returns Vec<Schema>
     - dev_config_set            — dispatches by struct name to set_field

5. <AutoConfigField> renders the right control per FieldType.kind:
   number → <Input type="number" min/max>, boolean → <Switch>,
   string → <Input> (or <Textarea> when multiline), enum → <Select>.
   Help text becomes a tooltip on an info icon.

6. <AutoTuningSection> calls dev_configs_list once, renders a section
   per registered struct, and writes via dev_config_set. Replaces the
   ~85 lines of hand-written Tuning JSX in developer-tab.tsx with
   <AutoTuningSection />.

Type-checking on set: the generated set_field round-trips the incoming
JSON value through the declared Rust type before writing. An out-of-range
or wrong-type value surfaces as an Error in the UI inline beneath the
field rather than corrupting the store.

Storybook compatibility: AutoTuningSection treats a null response from
invoke as "no registered configs" (Tauri commands aren't real in
storybook), so the snapshot still renders cleanly.

Closes: nixmac-93p

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member Author

cooper (czxtm) commented May 28, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • automerge - adds this PR to the back of the merge queue
  • urgent - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions
Copy link
Copy Markdown
Contributor

Fails
🚫

Your ## Test Plan section is empty. Describe the steps a reviewer should take to verify this change.

🚫

New UI components were added without a Storybook story. Add a sibling *.stories.tsx file:

  • apps/native/src/components/widget/settings/auto-config-field.tsx
  • apps/native/src/components/widget/settings/auto-tuning-section.tsx
🚫

New Rust modules were added without tests. Add a #[cfg(test)] mod tests { … } block or a file under apps/native/src-tauri/tests/:

  • apps/native/src-tauri/src/commands/dev_configs.rs
🚫

This PR touches behavior-sensitive code that is documented in darkmatter/nixmac-web. Please either:

  • Open a companion docs PR and check Docs updated in the PR description, or
  • Check No docs update needed if the change doesn't affect user-facing behavior.
Warnings
⚠️ Please assign this PR to someone (usually yourself).
⚠️ ❗ Big PR (1101 lines changed). Consider splitting it into smaller, focused changes.

📋 PR Overview

Lines changed 1101 (+909 / -192)
Files 3 added, 13 modified, 0 deleted
Draft / WIP no
Has Test Plan yes
New UI components yes (2)
New Storybook stories no
New Rust modules yes (1)
New TS source files yes (2)
New tests no
package.json touched no
Cargo.toml touched yes
Infra / CI touched no

🔬 Coverage

Report Lines Statements Functions Branches
apps/native/coverage/coverage-summary.json 17.8% 17.8% 30.7% 54.1%

Generated by 🚫 dangerJS against 457c568

@czxtm
Copy link
Copy Markdown
Member Author

Superseded by the rebuilt Graphite stack starting at #244 and ending at #255.

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