Add a backend command the page calls
Purpose
Add one new backend command that the page calls as window.playPets.<name>(). The example name is centerFriend (moves a friend to the middle of the yard); when you add a real one, pick a name that says what it does. The full path a command travels is in data flows 1 and 2 of Architecture: PlayPets app.
Prerequisites
- You finished Set up a development environment and run the app, and
npm testandnpm run test:e2epass. - You read the backend locks standard and the i18n standard. Commands run on a blocking thread, not on the main thread. Each handler takes the app state lock itself with
lock(state), and does slow work (network, dialogs, the keychain) without holding it.
Steps
- Add one row to the
COMMANDStable insrc-tauri/src/commands.rs. The row names the command (the page's method), says who may ask for it (mainfor the yard window,overlayif the desktop windows need it too,test_onlyfor the e2e scenario), and gives what it does. The bridge script, the check of which window may call what, and the dispatch all come from this table. Read arguments withc.text(i),c.arg(i)andc.float(i).
rust
static COMMANDS: &[Command] = &[
// …
main("centerFriend", |c| center_friend(c.app, &c.state, c.text(0))),
];- Write the handler in the same file (or in the module that owns the area). A handler that changes the state goes through
commit: it takes the lock, runs your change, then saves and notifies every window once (a change that could not be saved still stands and is shown, and the error is returned).
rust
fn center_friend(app: &AppHandle, state: &State<Shared>, id: &str) -> Result<Value, String> {
commit(app, state, |d| {
let pet = d.pets.iter_mut().find(|p| p.id == id).ok_or_else(|| i18n::t("error.friend_missing"))?;
pet.x = 0.5;
pet.y = 0.5;
Ok(Value::Null)
})
}If there is a new error sentence, add a row at the same position in every table under
src-tauri/src/i18n/(ko.rs,en.rs,ja.rs,zh_hans.rs). If an existing key (error.friend_missing) works, skip this step.Call it from the page. On failure
callthrows, andguardshows that sentence as a notice.
js
import { $, call, guard, selected } from '../core/state.js';
$('center-button').onclick = guard(() => call('centerFriend', selected));- Move the parts with rules (position math and so on) into pure functions and add tests to
mod testsin the same file. If people see the flow, add a calling line to the scenario intests/e2e.mjsand a check line to its expected list.each_command_is_named_once…incommands::testschecks the table (a name listed twice, what the overlay may ask for).
Verification
bash
npm test
npm run lint
npm run test:e2e- All three commands pass. If you skip the key in step 3, the Rust test
i18n::tests::every_key_asked_for_is_in_the_tablefails. - Run the app and press the button: the friend moves to the middle of the yard (
changednotified every window), and it is still there after you restart the app (persistsaved it).
Troubleshooting
| Symptom | Cause |
|---|---|
playPets.centerFriend is not a function on the page | The row from step 1 is missing, or it is test_only |
Calling it gives "That can't be done here. Reopen the app." (error.not_allowed) | You called it from the desktop window and the row says main (use overlay) |
| The app freezes | The handler waits on the main thread or slow work while holding the lock. Check it against the locks standard again |