Configurable macro#201
Conversation
Both imports were only referenced inside JSX comments, so tsc flagged them (TS6133/TS6192) and broke the build check on main since bd658af. The env.ts BooleanFromString errors mentioned in the issue do not reproduce: apps/native resolves effect to 3.21.0 (transitive) which still exports BooleanFromString. Only the root workspace pulls effect@4.0.0-beta.62, but env.ts lives under apps/native. Closes nixmac-62s.
The repo's bun.lock pins effect@4.0.0-beta.62 (no transitive effect@3.x). 4.0 removed Schema.BooleanFromString — which env.ts was using — so a fresh `bun install --frozen-lockfile` (what CI does) produces a tree where the import fails to compile. The earlier "doesn't reproduce locally" diagnosis on nixmac-62s was misled by a stale symlink at apps/native/node_modules/effect pointing into node_modules/.bun/effect@3.21.0/ left over from an older install run. Locally tsc resolved against the stale 3.x version, where BooleanFromString still exists. Migration: - Replace `Schema.BooleanFromString` with `Schema.Literals(["true", "false"])` (4.0's plural array form; 3.x had variadic `Schema.Literal(...)` — these are not interchangeable). - Coerce the validated string to `boolean | undefined` in code so the exported settings type matches the old BooleanFromString shape and downstream consumers (utils.ts:19's `!== true` check) don't need to change. - Drop the auto-derived `Schema.Schema.Type<typeof Settings>` because the runtime shape we expose (with the string→bool coercion) differs from the decoded shape. Strict parsing is preserved: any value other than "true"/"false" still fails at decode time, same as the original. Note: existing local installs with a stale apps/native/node_modules/effect symlink will need `bun install` to refresh — the stale 3.x effect doesn't have `Schema.Literals` (plural). One-time cost; matches CI from then on. Refs nixmac-62s.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Previous commit 0895711 accidentally included unresolved 'Updated upstream / Stashed changes' markers from a botched git stash pop. Re-exporting via bd export produces the correct merged state including nixmac-k8d as the fourth nixmac-srn blocker.
* feat(ci): nightly develop→main release with minor version bump
Adds a GitHub Actions cron (09:00 UTC daily) that merges develop into
main and tags a vMAJ.(MIN+1).0 release. Exits silently when develop has
no new commits vs main.
The actual ship work is delegated to build.yaml's existing `tag` mode —
the nightly job just produces the merge commit and the tag, then atomically
pushes both. compute-version.sh gets a small defensive edit: when HEAD is
already tagged with a v* tag, `release` mode is demoted to `branch` so the
main-push event doesn't trigger a duplicate (patch-bumped) ship alongside
the tag-push event.
Prerequisites for the cron to push successfully:
- RELEASE_BOT_TOKEN secret (PAT with bypass), OR
- repo ruleset bypass for github-actions[bot] on main
Without either, `git push --atomic` fails on the protected main branch.
Workflow falls back to GITHUB_TOKEN so cron + script wiring can be tested
before bypass is granted.
Files:
- .github/workflows/nightly-release.yaml (new)
- ops/scripts/release/nightly-release.sh (new; supports DRY_RUN=1)
- ops/scripts/release/compute-version.sh (tag-aware release-mode skip)
* feat(ci): scope nightly release trigger to native build affecteds
Replace the simple "any commit on develop" trigger with the no-turbo
equivalent of `turbo run build --affected --filter=native`. Releases now
fire only when develop has changes inside the native workspace, its
transitive workspace deps (currently @nixmac/ui), or global build inputs
(root package.json, bun.lock, root tsconfig, Cargo.toml/lock).
This skips nights where develop only got CI/docs/release-script changes
so a minor version isn't burned on commits that wouldn't ship anything
different to users.
Adds ops/scripts/release/affected-paths.mjs which dynamically resolves
the affected path set by reading the root workspaces config and walking
workspace:* deps — no hardcoded list to maintain when new packages
appear.
Verified locally:
- Real diff (apps/native/*, Cargo.lock, etc.): release
- Synthetic diff (ops/, .github/, docs/, *.md): skip
- Synthetic diff (bun.lock only): release (global input)
* fix(ci): address Copilot review feedback on nightly-release
- next_minor_version: filter to stable vMAJ.MIN.PATCH only so disposable
-test.N tags (used by build.yaml for signing rehearsals) can't pollute
the bump base
- Remote tag existence check: use `git ls-remote --exit-code` with an
exact ref pattern instead of `grep -q "${tag}"`, which would false-
positive when a longer tag like v1.2.0-test.1 contains the candidate
as a substring
- Docstring: align step 2 with actual behavior (logs a one-liner then
exits 0, not strictly silent)
- Workflow: add concurrency group so a scheduled run + manual dispatch
can't race on the same next-tag computation. cancel-in-progress=false
to avoid aborting a half-completed merge+tag mid-flight
* docs(ci): align skip-message wording with affected-paths policy
Copilot follow-up: three places still described the skip condition as
"no new commits vs main" or "skip silently". The actual policy is the
affected-paths filter (no-turbo equivalent of
`turbo run build --affected --filter=native`), which can return false
even when develop has commits — they just don't touch the native build
graph.
- should_release docstring: "skip silently" → "skip (caller logs reason)"
- main() skip log: "develop has no new work" → "no changes affect the
native build graph"
- workflow header: "no new commits vs main" → explanation of the
affected-paths filter and what kinds of develop activity will no-op
No behavior change.
* fix(ci): nightly-release cwd-independence and ..→... range
Copilot follow-up. Two real bugs:
1. The script claimed cwd-independence via REPO_ROOT but only used it for
the affected-paths.mjs invocation. Every git command and the
`node -p require('./package.json')` fallback ran relative to the
caller's cwd, so invoking the script from anywhere other than the
repo root would fail. main() now `cd`s into REPO_ROOT before doing
any work, which makes the cwd-independence claim actually true.
2. should_release used `git diff origin/main..origin/develop` (two-dot
range), which is tip-to-tip. If main has a hotfix not on develop,
two-dot treats it as a develop-side deletion and flags it as a
change — falsely triggering a release every night until the hotfix
gets merged back. Three-dot (`origin/main...origin/develop`) diffs
from the merge-base, so only commits new on develop are counted.
Verified locally: running the script from /tmp now produces the same
dry-run plan as running from the repo root. Two-dot vs three-dot on
current origin/main vs origin/develop differs by one file, confirming
there is currently a hotfix-style commit on main that the old check
would have erroneously counted.
* docs/fix(ci): nightly-release token fallback + optional-env docstring
Copilot follow-up:
1. Workflow checkout's token fallback used `secrets.GITHUB_TOKEN` as the
`||` second operand. While that *does* work in normal expression
contexts (it's GitHub's documented way to reference the auto-injected
token), the `github.token` context form is more reliable in fallback
positions and `if:` evaluations. Switched to
`secrets.RELEASE_BOT_TOKEN || github.token` for that defensive reason.
2. Header docstring claimed GIT_USER_NAME / GIT_USER_EMAIL were "Required
env" but the code uses `if [[ -n "${VAR:-}" ]]` guards and silently
skips git config when unset. They're actually optional CI overrides
that fall back to the caller's existing git config — fine for local
rehearsals, expected to be set in CI for bot-identity attribution.
Updated the comment to match the actual code.
No behavior change.
* fix(ci): defensive Copilot follow-ups on nightly-release
1. DRY_RUN expression now gates on `github.event_name == 'workflow_dispatch'`
before reading `inputs.dry_run`. The `inputs.*` context is only
populated for dispatch events; gating ensures scheduled cron runs
always get '0' regardless of how GitHub resolves missing-input refs.
2. compute-version.sh tag-skip regex now anchored with `$` so disposable
`v0.22.0-test.N` tags (used for signing/notarization rehearsals)
don't suppress legitimate `main`-push releases. Test tags don't ship
(publish/R2/Linear steps in build.yaml skip them), so main-push must
still bump+ship normally if such a tag happens to be at HEAD.
Verified: `v1.2.3` matches the regex (correctly skips release mode),
`v1.2.3-test.1` does not match (correctly does not suppress).
3. affected-paths.mjs now normalizes `package.json#workspaces` to handle
both the npm/bun array form and the Yarn object form
(`{ packages: [...] }`). nixmac uses the array form today; supporting
both is cheap future-proofing if the repo ever switches package
manager.
* docs/fix(ci): nightly-release docstring + unconditional fetch
Copilot follow-up:
1. Header step 4 said "Fast-forward / no-ff merge" but the implementation
always uses `git merge --no-ff`. Updated the comment to match the
actual behavior (always produces a merge commit so the release
boundary stays visible in git log --first-parent).
2. `git fetch` was DRY_RUN-gated, but should_release and
next_minor_version both query local refs (origin/main..origin/develop
diff + `git tag --list` for the latest stable). On a stale checkout
the dry-run could compute a wrong next version or false-positive
"nothing to release". Unwrap the fetch from `run` so it always
executes — fetch is read-only from the project's perspective (only
updates local origin/* refs), so unconditional execution is safe and
makes dry-run output reflect real remote state.
Verified: the unconditional fetch pulled a fresh v0.23.2 tag on this
run that the local checkout didn't have, validating the fix on its
first execution.
* fix(native): fix Chromatic Storybook
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix(native): env.ts — drop version-skewed Schema.Literal for plain String
PR #195 build broke at TS2554 ("Expected 1 arguments, but got 2") after
80a19c6 reverted NIX_INSTALLED_OVERRIDE from `Schema.Literals([...])` to
`Schema.Literal(...)` (variadic). The problem: `Schema.Literal`'s signature
is fundamentally version-skewed —
effect 3.x: `Literal<L>(...values: L)` variadic, multi-value
effect 4.0-beta: `Literal<L>(value: L)` single value only,
use `Literals([...])` for sets
So neither form source-compiles in both:
- `Schema.Literal("true", "false")` works in 3.x, fails 4.0 (this PR)
- `Schema.Literals(["true", "false"])` works in 4.0, fails 3.x (Chromatic)
The repo's lockfile pins effect 4.0-beta, so tsc sees that — but the
Chromatic/storybook test environment can resolve 3.x via workspace
symlink hoisting, which is why 80a19c6 picked the 3.x form to fix
Chromatic and broke the build instead.
Fix: validate with plain `Schema.String` (signature is identical across
versions) and coerce to boolean in code via
`raw.NIX_INSTALLED_OVERRIDE === "true" ? true : undefined`. The only
downstream consumer is `settings.NIX_INSTALLED_OVERRIDE !== true` in
widget/utils.ts, which treats any non-"true" value as functionally
false — so silent acceptance of unexpected strings is observationally
equivalent to coercing them to undefined. We lose schema-level
"must be 'true' or 'false'" strictness; we gain working CI on both
the build and Chromatic paths.
Verified against both effect@3.21.0 and effect@4.0.0-beta.62 symlinks
in isolation: no TS2554, no missing-Literals errors.
* fix(ci): nightly-release DRY_RUN final-message clarity
Copilot follow-up: the final `echo "Released ${tag}"` ran unconditionally,
so workflow_dispatch dry-runs printed "Released v0.24.0" even though the
merge/tag/push steps were only echoed. Now branches on DRY_RUN: prints
"Dry run complete — would have released ${tag}" in dry mode, "Released
${tag}" in real mode. Behavior preserved; just the operator-facing log
line distinguishes the two modes.
Did not touch the `local changed paths file path` declaration in
should_release — Copilots claim that `path` is unused is incorrect.
`path` is the inner loops read variable on line 85 and is used in the
path-matching comparisons on lines 87, 89, 91, and 92.
* fix(ci): nightly-release working-tree guard + setup-node pin
Copilot follow-up:
1. Add a clean-working-tree guard before the destructive `git reset --hard
origin/${MAIN_BRANCH}`. Local accidental invocations would otherwise
silently obliterate uncommitted work. CI runners start clean by
construction so the guard never fires in CI; DRY_RUN=1 bypasses it
since dry-mode does not mutate the tree. Error path prints
`git status --short` so the operator can see what would have been lost.
2. Add an actions/setup-node@v6 step pinned to node-version: 20 (matching
build.yaml's convention). The release script invokes node for
affected-paths.mjs and the package.json version fallback in
next_minor_version. Without an explicit pin the cron would depend on
whatever node the ubuntu-latest runner image ships, which is not stable
across image updates.
Verified: bash -n passes, dry-run still works, guard simulation triggers
correctly on dirty tree and stays out of the way in DRY_RUN=1.
---------
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
… (PoC)
Introduces a proc-macro that eliminates the 6-file boilerplate currently
required for every store-backed setting. A new knob today touches:
storage/store.rs (getter+setter), shared_types/prefs.rs (UiPrefs +
UiPrefsUpdate fields), commands/ui_prefs.rs (read+write branches), TS
bindings, and UI forms — ~25 LOC across 6 files. With this derive, a new
knob is one struct field.
PoC scope — EvolutionLimits only:
#[derive(Configurable)]
#[config(store_path = "settings.json")]
pub struct EvolutionLimits {
#[config(default = 25, key = "maxIterations")]
pub max_iterations: usize,
#[config(default = 5, key = "maxBuildAttempts")]
pub max_build_attempts: usize,
}
The derive generates `EvolutionLimits::load(app) -> Result<Self>` that
reads each field from tauri-plugin-store with the per-field default
fallback. Reads happen on every call, so edits via dev settings take
effect on next agent run (hot-reload).
Two new workspace crates:
- configurable/ — runtime trait + read_field() helper
- configurable-derive/ — proc-macro
Bug fix included: evolve/mod.rs:1467 was logging
DEFAULT_MAX_BUILD_ATTEMPTS (the const) instead of the configured value
— exactly the drift this derive is designed to prevent. Threaded
max_build_attempts into process_tool_result().
UiPrefs / UiPrefsUpdate / ui_set_prefs left untouched on purpose — full
migration is tracked under nixmac-e53 with one sub-issue per category.
Closes: nixmac-8ka
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📋 PR Overview
🔬 Coverage
|
There was a problem hiding this comment.
Pull request overview
Adds a proof-of-concept Rust #[derive(Configurable)] proc-macro (plus small runtime helper crate) to simplify reading hot-reloadable developer settings from tauri-plugin-store, and migrates the evolution loop’s iteration/build-attempt limits to use it.
Changes:
- Introduces two new workspace crates:
configurable(runtime helper + derive re-export) andconfigurable-derive(proc-macro generatingStruct::load(app)). - Migrates evolution limits (
max_iterations,max_build_attempts) to a newEvolutionLimitsstruct loaded fromsettings.json, and threads the configuredmax_build_attemptsinto build-check logging/control flow. - Updates workspace/native Cargo manifests and lockfile to include the new crates; closes the related beads issue.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Cargo.toml | Adds new workspace members for the macro + runtime crates. |
| Cargo.lock | Records the new crates and their dependencies in the lockfile. |
| apps/native/src-tauri/src/evolve/mod.rs | Loads EvolutionLimits via the new derive and threads max_build_attempts into processing/logging. |
| apps/native/src-tauri/src/evolve/config.rs | Defines EvolutionLimits annotated with #[derive(Configurable)] and store keys/defaults. |
| apps/native/src-tauri/configurable/src/lib.rs | Adds runtime helper read_field() and re-exports the derive. |
| apps/native/src-tauri/configurable/Cargo.toml | Declares the new runtime crate and dependencies. |
| apps/native/src-tauri/configurable-derive/src/lib.rs | Implements the Configurable derive that generates a load() method. |
| apps/native/src-tauri/configurable-derive/Cargo.toml | Declares the new proc-macro crate and dependencies. |
| apps/native/src-tauri/Cargo.toml | Adds the new configurable path dependency to the native Tauri crate. |
| .beads/issues.jsonl | Marks nixmac-8ka as closed and adds follow-up migration issues. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| //! Configurable — store-backed dev settings without per-knob boilerplate. | ||
| //! | ||
| //! Derive `Configurable` on a struct to generate a `load(app)` method that reads | ||
| //! each field from `tauri-plugin-store`, falling back to the per-field default. | ||
| //! Edits made by the user via the dev-settings UI (which writes to the same | ||
| //! store keys) are picked up on the next `load(app)` call — i.e. hot-reload. | ||
| //! |
The Tuning section is a new home for behavior knobs that grow over time as
more Configurable structs are migrated. Starts with the same two settings
(max iterations, max build attempts) that were previously hidden inside
the AI Models tab — moved here because they're not about models.
The Backup & Restore section adds:
- Export settings.json — opens a save dialog and writes a filtered copy
of the plugin-store. By default legacy plain-text API keys
(openrouterApiKey, openaiApiKey, vllmApiKey) are stripped. A checkbox
opts into including them for full backups.
- Import settings.json — opens an open dialog, validates the file as a
JSON object, then REPLACES the entire store with the file contents.
A confirmation dialog warns that absent keys (including API keys, if
the export was sanitized) will be cleared.
Both sections are gated by developerMode, inherited from the Developer
tab itself.
Backend:
- commands/settings_io.rs with settings_export(include_secrets: bool)
and settings_import() Tauri commands, both gated on developer mode
- shared_types/settings_io.rs with ExportResult / ImportResult (specta
generates the matching TS types automatically)
Frontend:
- ai-models-tab.tsx: Evolution Limits subsection removed; max iterations
and max build attempts props dropped
- settings-dialog.tsx: matching cleanup of unused form fields and the
form.Field wrappers that fed AiModelsTab
- developer-tab.tsx: two new sections; loads tuning values via direct
tauriAPI.ui.getPrefs() rather than the form, keeping the storybook
story self-contained
- Snapshots updated for ai-models-tab and developer-tab
Closes: nixmac-cqb
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…settings.json) EvolutionLimits (max iterations, max build attempts) now persists in <config_dir>/.nixmac/settings.json instead of the OS app data directory. Because the config dir is the user's nix-darwin repo and already syncs via git, these settings ride along across machines without an explicit backup/restore step. Per-device settings (developerMode, pinnedVersion, updateChannel, model cache, prompt history) stay in the OS app data dir where they belong. How it works: - New storage::configurable_scope module exposes repo_store_path(app), which returns the absolute path to .nixmac/settings.json and lazily creates the directory plus a short README.md the first time it's called. - configurable-derive learns #[config(store_path_fn = <path>)]: instead of a hard-coded string, the generated load() method calls a resolver function each time. Keeps the derive decoupled from nixmac — any consumer can plug in their own path resolver. - EvolutionLimits opts into the new mode via store_path_fn. - store::get_max_iterations / set_max_iterations and the max_build_attempts pair now read/write the repo store, with a best-effort migration from the legacy local store on first read so existing users don't see their values reset to defaults. Falls back to defaults if config_dir isn't set yet (during onboarding). - Tuning UI section copy clarifies that values sync via the repo. The Backup & Restore section copy clarifies that repo-scoped values are versioned by git, not included in the local export. Also includes the user's separate rename of "vLLM / LiteLLM" → "OpenAI Compatible" in ai-models-tab.tsx and api-keys-tab.tsx. Closes: nixmac-gr3 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| const next = Number.parseInt(raw, 10); | ||
| if (Number.isNaN(next)) return; | ||
| setMaxIterations(next); | ||
| try { | ||
| await tauriAPI.ui.setPrefs({ maxIterations: next }); |
| const next = Number.parseInt(raw, 10); | ||
| if (Number.isNaN(next)) return; | ||
| setMaxBuildAttempts(next); | ||
| try { | ||
| await tauriAPI.ui.setPrefs({ maxBuildAttempts: next }); |
| config::EvolutionLimits { | ||
| max_iterations: 25, | ||
| max_build_attempts: 5, | ||
| } |
| let value = get_repo_store(app) | ||
| .ok() | ||
| .and_then(|s| s.get("maxBuildAttempts")) | ||
| .and_then(|v| serde_json::from_value::<usize>(v).ok()) | ||
| .unwrap_or(5); |
# Conflicts: # .beads/issues.jsonl
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…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>
Juanpe Bolívar (arximboldi)
left a comment
There was a problem hiding this comment.
The overall idea of having ways to easily declare customization points that show up in the UI is cool, nice stuff.
First, this is a massive PR that it's a bit tricky to review. I would have loved to see it split in three parts:
- The Configurable and auto-UI infrastructure.
- The saving of settings.json in the config folder.
- The new theme.
Going into the code itself, I see a big missed opportunity to start moving in the direction I suggest in my architecture review document. This would set the groundwork to eventually move all the preferences into Configurable infrastructure. This would imply:
- Storing the configurable in
tauri::Stateinstead ofstore. - By doing that, we already remove a lot of code, since there is no need to marshall the configurable into/outo the store, since Serde can do that for us (and will give us versioning, etc.)
- Adding an update channel to update the UI (via a regular API based on events, as described in the architecture review)
- Using the an auto-updated zustand store (or store slice) as way to transparently interface between the UI and Rust.
The details on how to do this are already broadly in the architecture review document. If you don't have time to do this, perhaps Cas Linden (@CasLinden) can pick this up, as I know he wanted to get familiarity with the architecture and start implementing it in various parts of the application.
| /// Copies a key from the legacy local store into the repo store the first | ||
| /// time a repo-scoped getter runs (post-upgrade migration). No-op once the | ||
| /// key already exists in the repo store. | ||
| fn migrate_repo_key<R: Runtime>(app: &AppHandle<R>, key: &str) -> Result<()> { | ||
| let repo = get_repo_store(app)?; | ||
| if repo.get(key).is_some() { | ||
| return Ok(()); | ||
| } | ||
| let local = get_store(app)?; | ||
| if let Some(value) = local.get(key) { | ||
| repo.set(key, value); | ||
| repo.save()?; | ||
| } | ||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
Not sure we should worry about "legacy" at this level since we haven't released yet, there's some risk of just acummulating lots of unneeded code. Eventually, we should think about versioning of various files (including settings.json) but this should be done using the versioning infrastructure of the serialization infrastructure (e.g. Serde.) Related to the general comment on moving away from tauri::store.
| useEffect(() => { | ||
| refresh(); | ||
| }, [refresh]); |
There was a problem hiding this comment.
refresh is not used anywhere else if I'm understanding correctly, so the body could be brought in here
|
|
||
| const commit = async (next: unknown) => { | ||
| const previous = value; | ||
| setValue(next); |
There was a problem hiding this comment.
This seems to be the only place where we update the UI, there's no event driven to update the UI from changes from RS. This is risky.
|
Juanpe Bolívar (@arximboldi) agreed this PR got too big after I decided the channel between rust/js should be more strict - I'll split them up. Regarding |
Summary
This PR implements the ability to make any parameter configurable via the settings UI by simply adding derive macro (
Configurable). The above is achieved with just a few lines added:It also adds an import/export button that will contain these configurable values. This enables two important features:
.nixmac/settings.json, then a user can sync their nixmac settings between machines as well!Test Plan
cargo test --manifest-path apps/native/src-tauri/Cargo.toml settings_iocargo test --manifest-path apps/native/src-tauri/Cargo.toml dev_configscargo test --manifest-path apps/native/src-tauri/Cargo.toml configurable_scopecargo test --manifest-path apps/native/src-tauri/Cargo.toml default_matches_configured_field_defaultsbunx vitest run --project=storybook src/components/widget/settings/auto-config-field.stories.tsx src/components/widget/settings/auto-tuning-section.stories.tsxSettings/AutoConfigFieldandSettings/AutoTuningSection.Docs