give :section back — the splat took it from fifteen plugins
`/<route>` and `/<route>/:section` are what every plugin has always had, and fifteen of them read useParams().section. Replacing the pair with a splat took that parameter away from all of them at once: the screens still mounted and every one lost its selection, which is worse than a 404 because nothing says so. The splat stays, for depth. React-router ranks a static or dynamic segment above it, so a plugin with one segment gets `section` again and only deeper paths fall through. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -101,24 +101,31 @@ export function App() {
|
||||
{/* One route per SCREEN, not per plugin — `screenId` is the key, because a plugin with two
|
||||
screens (caldav: Calendar and Contacts) contributes two entries sharing one `appName`. */}
|
||||
{/*
|
||||
A SPLAT, so the whole subtree is the plugin's.
|
||||
Three routes, and the third is the only new one.
|
||||
|
||||
It was a pair — the bare route and `/:section` — which gave a plugin exactly one segment and
|
||||
made the platform the author of what it meant. Anything deeper had to go in the query
|
||||
string, and `/fofos-admin/layout/header` was not expressible at all.
|
||||
`/<route>` and `/<route>/:section` are what every plugin has always had, and fifteen of
|
||||
them read `useParams().section`. A splat ALONE replaced that for a day and took the
|
||||
parameter away from all of them at once — the screens still mounted and every one of them
|
||||
lost its selection, which is a worse failure than a 404 because nothing says so.
|
||||
|
||||
A splat matches zero segments too, so this is one route where there were two, and the
|
||||
plugin reads its own position off the location. Routing inside a plugin is the plugin's,
|
||||
which is the same line `mountPrefix` already draws around its API: the platform owns where
|
||||
a plugin STARTS and nothing after it.
|
||||
The splat is added for depth rather than instead of them: `/fofos-admin/layout/header` was
|
||||
not expressible before, and a plugin that wants its own subtree reads the location.
|
||||
React-router ranks a static or dynamic segment above a splat, so a plugin with one segment
|
||||
still gets `section` and only deeper paths fall through.
|
||||
*/}
|
||||
{installedPlugins.map((plugin) => (
|
||||
{installedPlugins.flatMap((plugin) => [
|
||||
<Route key={plugin.screenId} path={plugin.route} element={<Dashboard.PluginScreen {...plugin} />} />,
|
||||
<Route
|
||||
key={plugin.screenId}
|
||||
key={`${plugin.screenId}-section`}
|
||||
path={`${plugin.route}/:section`}
|
||||
element={<Dashboard.PluginScreen {...plugin} />}
|
||||
/>,
|
||||
<Route
|
||||
key={`${plugin.screenId}-deep`}
|
||||
path={`${plugin.route}/*`}
|
||||
element={<Dashboard.PluginScreen {...plugin} />}
|
||||
/>
|
||||
))}
|
||||
/>,
|
||||
])}
|
||||
<Route path="/system-monitor" element={<Dashboard.SystemMonitorScreen />} />
|
||||
<Route path="/system-monitor/:scope" element={<Dashboard.SystemMonitorScreen />} />
|
||||
{/* TEMPORARY / EXPERIMENTAL — offline file transfer over animated QR codes */}
|
||||
|
||||
Reference in New Issue
Block a user