| @@ -94,8 +94,40 @@ | ||
| 94 | 94 | return openstation_apps_registry()->get( $id ); |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | 97 | /** |
| 98 | + * The tabs of the window in charge of an admin menu, if any. | |
| 99 | + * | |
| 100 | + * A window that declares `App::menu( $slug, … )` answers for that | |
| 101 | + * menu whenever its gate says so — the per-user opt-in that decides | |
| 102 | + * between the native window and the classic screen. The dock builds | |
| 103 | + * that menu's submenu from this list, so the rows the user sees and | |
| 104 | + * the tabs the window shows are one list by construction. | |
| 105 | + * | |
| 106 | + * Returns an empty array when no window declares the menu, when the | |
| 107 | + * gate is off, or when this user may not use the window at all. | |
| 108 | + * | |
| 109 | + * @param string $menu_slug Admin menu slug, e.g. `users.php`. | |
| 110 | + * @return array<int,array<string,string>> Ordered `id` + `label` pairs. | |
| 111 | + */ | |
| 112 | +function openstation_app_menu_tabs( $menu_slug ) { | |
| 113 | + $menu_slug = (string) $menu_slug; | |
| 114 | + if ( '' === $menu_slug ) { | |
| 115 | + return array(); | |
| 116 | + } | |
| 117 | + foreach ( openstation_apps_registry()->all() as $app ) { | |
| 118 | + if ( $app->menu_slug() !== $menu_slug ) { | |
| 119 | + continue; | |
| 120 | + } | |
| 121 | + if ( ! $app->menu_owns_dock() || ! $app->allows( openstation_apps_os() ) ) { | |
| 122 | + return array(); | |
| 123 | + } | |
| 124 | + return $app->menu_tabs(); | |
| 125 | + } | |
| 126 | + return array(); | |
| 127 | +} | |
| 128 | + | |
| 129 | +/** | |
| 98 | 130 | * The whole window as a value: manifest, state after `mount`, body |
| 99 | 131 | * HTML and effects — what a host calls to render an app somewhere |
| 100 | 132 | * other than the desktop (a REST consumer, a CLI, a test). |
| 101 | 133 | * |
| @@ -344,8 +376,37 @@ | ||
| 344 | 376 | ); |
| 345 | 377 | } |
| 346 | 378 | |
| 347 | 379 | /** |
| 380 | + * The wp-admin pages a window answers for while it is the one in | |
| 381 | + * charge of its menu, as `array( 'id' => <tab>, 'page' => <slug> )`. | |
| 382 | + * | |
| 383 | + * The shell routes those URLs to the window wherever they are | |
| 384 | + * clicked, not only from the dock: a link inside another window, the | |
| 385 | + * admin bar's "+ New", a workspace's launch list. Empty when no menu | |
| 386 | + * is declared or the opt-in is off, and re-sent on the menu refresh | |
| 387 | + * that flipping the opt-in spends. | |
| 388 | + * | |
| 389 | + * @param App $app The app. | |
| 390 | + * @return array<int,array<string,string>> | |
| 391 | + */ | |
| 392 | +function openstation_apps_menu_pages( App $app ) { | |
| 393 | + if ( ! $app->menu_owns_dock() ) { | |
| 394 | + return array(); | |
| 395 | + } | |
| 396 | + $pages = array(); | |
| 397 | + foreach ( $app->menu_tabs() as $tab ) { | |
| 398 | + if ( '' !== $tab['page'] ) { | |
| 399 | + $pages[] = array( | |
| 400 | + 'id' => $tab['id'], | |
| 401 | + 'page' => $tab['page'], | |
| 402 | + ); | |
| 403 | + } | |
| 404 | + } | |
| 405 | + return $pages; | |
| 406 | +} | |
| 407 | + | |
| 408 | +/** | |
| 348 | 409 | * The static template the shell clones on open: a root the runtime |
| 349 | 410 | * mounts into, showing a spinner until the first render lands. One |
| 350 | 411 | * per view — the main body and each tab panel get their own. |
| 351 | 412 | * |
| @@ -430,8 +491,10 @@ | ||
| 430 | 491 | 'nav_kind' => $manifest['nav_kind'], |
| 431 | 492 | 'dock_order' => $manifest['dock_order'], |
| 432 | 493 | 'placeable' => $manifest['placeable'], |
| 433 | 494 | 'autofocus' => $manifest['autofocus'], |
| 495 | + 'admin' => isset( $manifest['admin'] ) ? $manifest['admin'] : 'site', | |
| 496 | + 'menu_pages' => openstation_apps_menu_pages( $app ), | |
| 434 | 497 | 'config' => openstation_apps_client_config( $manifest, $bundle, $app ), |
| 435 | 498 | ); |
| 436 | 499 | |
| 437 | 500 | /** |