0.50.0: Admin Table Filters and Extensible Tenant Guards
Version 0.50.0 is out. This release focuses on the admin area and on extension points: select filters for admin tables, a tenant guard you can add your own checks to, and a fix so service interceptors reach forked contexts.
Select filters on admin tables
renderTable now accepts a filters option. Each filter is a { name, options } entry, and the table renders it as a select beside the search box in a new toolbar row.
- The current value is read from
this.params[name], falling back to the first option. - Changing a select reloads the table frame with the new value and goes back to the first page.
- Pagination links and the search box keep the active filter values.
The filter value is not applied to your query for you. Read it from this.params and use it when you build the table's rows, mirroring the same first-option default:
export default {
async render(){
const { access = 'public' } = this.params;
return this.renderTable(
this.database.posts.where({ access }).orderBy('title').paginate(this.params.page),
{
search: ['title'],
filters: [
{
name: 'access',
options: [
{ value: 'public', label: 'Public' },
{ value: 'free', label: 'Members only' },
{ value: 'paid', label: 'Paid members only' }
]
}
],
columns: ['title']
}
);
}
};None of the built-in admin tables use a filter yet, so this is for tables you add in your own packages.
Add your own checks to the tenant guard
The multi-tenant package's guard view used to do its tenant lookup and redirect directly inside render(). It now registers that logic as a render hook from meta(), and render() runs the hook chain, stopping at the first hook that returns a response.
Because views with the same name from different packages are merged, your package can ship its own guard view that adds a hook to the same chain:
export default {
meta(){
this.addHook('render', async function(){
if(this.params._url.hostname.endsWith('.internal')){
return [404, { 'content-type': 'text/plain' }, ['Not found']];
}
});
}
};Hooks run in the order their packages were loaded. Return nothing to let the request carry on to the next hook, or return a response to stop it there.
Service interceptors now reach forked contexts
this.serviceManager.intercept(name, fn) swaps a service for the current context, which is mostly useful in tests. Before this release a forked context did not copy its parent's interceptors, so a service resolved inside a rendered view or a command run from that context saw the real implementation. Forked contexts now inherit their parent's interceptors, so an interceptor registered in a test also applies to anything rendered or run beneath it.
Upgrading
Bump your packages to 0.50.0, or run npx blognami@latest for a new project. There are no migrations or configuration changes. The built-in admin tables look the same as before, so to see the release working add a filters option to one of your own renderTable calls and check that a select appears next to the search box. If you use the multi-tenant package, an optional next step is to move any host checks you have patched into the guard over to a render hook.