Adding things¶
A new page¶
- Create
frontend/js/views/thing.jsexporting{ search: null, async render(root, ctx) {…} }. Copy the shape oftracks.js. - Add
{ path: '/library/:libraryId/thing', view: thing, title: 'Thing' }toviews/routes.js. - Add a link in
nessie-sidebar.js(thelink(path, label, icon)helper), and addtop: trueto the route so phones don't show Back on it.
A new server call¶
- Add a route in the right
app/api/*_routes.py, with Pydantic models inapp/schemas/. Adddependencies=[Admin]if only admins should use it. - Put the queries in
app/repositories/and anything larger inapp/services/. Commit in the route. - Add one function to
frontend/js/api.js. Views never build URLs themselves. - Write a test in
tests/.clientanddb_sessionfixtures are available, and a test's database work is rolled back afterwards.
A new component¶
Create components/nessie-thing.js extending NessieElement and call define('nessie-thing', …). Import it in main.js. Take data through properties and report through emit().
A chart¶
Settings → Stats (views/settings/stats.js) has the pattern to copy. columns() draws a column chart as plain HTML in the theme's --nessie-chart colour: one tab stop, arrow keys between columns, a tooltip on hover and focus, and "Show as a table". Every theme defines --nessie-chart in themes.css, each checked for 3:1 contrast against its background. Use it for chart marks, not --bs-primary, which is too faint in the light theme.
A new mix rule¶
Rules live in app/services/mix_rules.py. Add the field to Rules, then:
- clear it in
tidy(); - add its words to
describe(); - add its condition to
conditions(); - add it to a
GROUPSentry, so the preview can suggest dropping it.
In the editor, add a control and a SUMMARIES line to views/mix-editor.js. load() treats a rule that saved mixes don't have yet as no rule.
A new Settings tab¶
Create a module in views/settings/ with the same { render(root, ctx) } shape and add it to SECTIONS in settings/index.js. For a server setting that the UI may edit, add it to app/core/editable_settings.py. Settings → Server builds its form from that list.
A new permission¶
Copy can_request: a column on users (with a migration), a field on Person and a property on Identity that's true for admins, a group setting kept in step in _signed_in(), a require_… dependency in app/api/auth.py, the field on ProfileOut, MeOut, ProfileIn and ProfileUpdate, a switch in the profile dialogs, and a can…() helper in identity.js that falls back to is_admin for older servers.
Words on screen¶
Use the terms people know from other apps. Name settings by what they do ("Enable Lidarr", "Disable online metadata retrieval"), use the standard verbs (request, retrieve, download, transfer, refresh metadata), and name the other system involved ("Requested “Kid A” from Lidarr"). Help text says what happens in one or two short sentences. Error toasts say what failed ("Couldn't delete the playlist.") and then give the server's reason.
A database change¶
Edit the model in app/models/, run alembic revision --autogenerate -m "…", read the file it writes, then test it with alembic upgrade head.