| @@ -88,9 +88,8 @@ | ||
| 88 | 88 | wp_enqueue_style( 'os-windows' ); |
| 89 | 89 | wp_enqueue_style( 'os-window-overview' ); |
| 90 | 90 | wp_enqueue_style( 'os-dock' ); |
| 91 | 91 | wp_enqueue_style( 'os-dock-peek' ); |
| 92 | - wp_enqueue_style( 'os-notch' ); | |
| 93 | 92 | wp_enqueue_style( 'os-workspaces' ); |
| 94 | 93 | wp_enqueue_style( 'os-shortcuts' ); |
| 95 | 94 | wp_enqueue_style( 'os-openstation-layout' ); |
| 96 | 95 | wp_enqueue_style( 'os-files' ); |
| @@ -346,8 +345,16 @@ | ||
| 346 | 345 | : array(); |
| 347 | 346 | $server_file_openers = function_exists( 'openstation_build_file_openers_payload' ) |
| 348 | 347 | ? openstation_build_file_openers_payload() |
| 349 | 348 | : array(); |
| 349 | + // Entries in the menu payload carry dependency handles; their | |
| 350 | + // payloads ride once in `scriptDepPayloads` (GH#892). The file | |
| 351 | + // lists stay whole: no sync module reads them on the client, and | |
| 352 | + // compacting them here was the only write to the map after the | |
| 353 | + // menu payload froze its own, so a refresh could not match it. | |
| 354 | + $script_dep_payloads = isset( $menu_payload['scriptDepPayloads'] ) | |
| 355 | + ? (array) $menu_payload['scriptDepPayloads'] | |
| 356 | + : array(); | |
| 350 | 357 | $user_file_associations = function_exists( 'openstation_get_user_file_associations' ) |
| 351 | 358 | ? openstation_get_user_file_associations( get_current_user_id() ) |
| 352 | 359 | : array(); |
| 353 | 360 | $server_wallpaper_menu_items = function_exists( 'openstation_build_wallpaper_menu_items' ) |
| @@ -502,9 +509,14 @@ | ||
| 502 | 509 | * @type bool $fromPortal Whether the shell was reached via the portal. |
| 503 | 510 | * @type bool $fromPortalIntent Whether the portal redirect resolved from an explicit `?target=…` (user navigation intent) rather than the session's focused window or the default-window fallback. Distinguishes a bare `/openstation/` visit from a portal-redirected admin-bar click so the shell can honour the URL the user actually asked for. |
| 504 | 511 | * @type array $seenIntros Slugs of one-time announcements the user has dismissed (e.g. `['openstation-rebrand']`). |
| 505 | 512 | * @type string $seenIntrosUrl REST endpoint for the seen-intros surface — POST `/seen` to mark, DELETE the base to reset. |
| 513 | + * @type bool $shellTour Whether this site offers the first-boot shell tour (`openstation_show_shell_tour`). Whether this user already had it is `seenIntros` containing `shell-tour`. | |
| 514 | + * @type string $shellTourBundleUrl URL of the lazy shell-tour bundle, injected on first use. | |
| 515 | + * @type array $firstRun `{ installedAt, firstEnabledAt, enabledAt }`, epoch seconds, 0 when unknown — the first-run stamps, read-only. | |
| 506 | 516 | * @type bool $rebrandNotice Whether to offer this user the one-off announcement explaining the rename from Desktop Mode to OpenStation. True only when migration 5 flagged this user as a Desktop Mode user from before the rename AND they haven't dismissed the `openstation-rebrand` intro. Only ever present in the shell config, so the announcement never reaches the classic admin. |
| 517 | + * @type array|null $usageFeedback What the one-time usage feedback prompt needs (`restUrl`), or `null` when this user is not owed it: the feature is off, they have had OpenStation on for fewer than seven days by the `openstation_enabled_at` stamp, or they already answered or dismissed the `usage-feedback` intro. Carries no user data. | |
| 518 | + * @type string $usageFeedbackBundleUrl URL of the lazy `usage-feedback` bundle, the form the prompt opens. | |
| 507 | 519 | * } |
| 508 | 520 | */ |
| 509 | 521 | $config = apply_filters( |
| 510 | 522 | 'openstation_shell_config', |
| @@ -561,8 +573,11 @@ | ||
| 561 | 573 | 'serverDesktopThemes' => $server_desktop_themes, |
| 562 | 574 | 'desktopIcons' => $desktop_icons, |
| 563 | 575 | 'serverFileTypes' => $server_file_types, |
| 564 | 576 | 'serverFileOpeners' => $server_file_openers, |
| 577 | + // Handle => dependency payload for every `scriptDeps` list in | |
| 578 | + // this config; see `openstation_compact_script_deps()`. | |
| 579 | + 'scriptDepPayloads' => (object) $script_dep_payloads, | |
| 565 | 580 | 'userFileAssociations' => $user_file_associations, |
| 566 | 581 | 'filesUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/files' ) ), |
| 567 | 582 | // Pinned-notes REST base (`includes/notes/rest.php`). The |
| 568 | 583 | // notes layer boots only when this is present. |
| @@ -706,8 +721,26 @@ | ||
| 706 | 721 | // announcement yet. Same value that gated `os-announce` |
| 707 | 722 | // above; the dialog cannot paint without that stylesheet, so |
| 708 | 723 | // the two must not diverge. |
| 709 | 724 | 'rebrandNotice' => $show_rebrand_notice, |
| 725 | + // The first-boot shell tour: whether this site offers it | |
| 726 | + // (the `openstation_show_shell_tour` filter), and the lazy | |
| 727 | + // bundle that runs it. Whether THIS user already had it is | |
| 728 | + // `seenIntros` containing `shell-tour`; the shell reads that | |
| 729 | + // itself so a reset can replay the tour without a new boot. | |
| 730 | + 'shellTour' => openstation_should_offer_shell_tour( get_current_user_id() ), | |
| 731 | + 'shellTourBundleUrl' => $lazy_bundle_url( 'shell-tour' ), | |
| 732 | + // The first-run stamps, read-only, epoch seconds (0 when | |
| 733 | + // unknown): when the plugin was installed, when anyone first | |
| 734 | + // enabled it, and when this user did. See | |
| 735 | + // `includes/first-run/stamps.php`. | |
| 736 | + 'firstRun' => openstation_first_run_config( get_current_user_id() ), | |
| 737 | + // Null for everyone but a user who has had OpenStation on | |
| 738 | + // long enough and has not answered yet; the gate lives in | |
| 739 | + // `includes/feedback/usage.php`. The form is a lazy bundle | |
| 740 | + // fetched only when the user says yes to the prompt. | |
| 741 | + 'usageFeedback' => function_exists( 'openstation_usage_feedback_config' ) ? openstation_usage_feedback_config() : null, | |
| 742 | + 'usageFeedbackBundleUrl' => $lazy_bundle_url( 'usage-feedback' ), | |
| 710 | 743 | 'aiSearchUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/ai/search' ) ), |
| 711 | 744 | // AI assistant availability + per-user toggle. Drives whether the |
| 712 | 745 | // Cmd+K palette and admin-bar icon appear, and the setup placeholder. |
| 713 | 746 | 'aiAssistant' => function_exists( 'openstation_ai_assistant_config' ) |
| @@ -721,34 +754,8 @@ | ||
| 721 | 754 | // Site-wide games kill switch (Extended options). Exposed to |
| 722 | 755 | // every user — the shell skips the challenges Heartbeat |
| 723 | 756 | // channel when the framework is off. |
| 724 | 757 | 'gamesEnabled' => openstation_games_enabled(), |
| 725 | - // Comments-window AI moderation toggle — surfaced at the | |
| 726 | - // shell level so the OS Settings → Features tab can render | |
| 727 | - // the toggle without depending on the Comments window | |
| 728 | - // being registered for this user. URL is the same | |
| 729 | - // endpoint the comments-window config exposes; state is | |
| 730 | - // `null` for non-admins (the UI hides the row entirely). | |
| 731 | - 'commentsAiUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/comments/ai-settings' ) ), | |
| 732 | - // Non-null only for admins on a site where the Core AI stack is | |
| 733 | - // present. Comment scoring routes through the AI Client (WP 7.0+), | |
| 734 | - // so on older WordPress the whole row is hidden — same as the | |
| 735 | - // assistant toggle — rather than shown disabled pointing at a | |
| 736 | - // Settings → Connectors screen that doesn't exist there. | |
| 737 | - 'commentsAi' => ( | |
| 738 | - current_user_can( 'manage_options' ) | |
| 739 | - && function_exists( 'openstation_ai_is_available' ) | |
| 740 | - && openstation_ai_is_available() | |
| 741 | - ) | |
| 742 | - ? array( | |
| 743 | - 'enabled' => function_exists( 'openstation_comments_ai_is_enabled' ) | |
| 744 | - ? openstation_comments_ai_is_enabled() | |
| 745 | - : false, | |
| 746 | - 'providerConfigured' => function_exists( 'openstation_comments_ai_provider_configured' ) | |
| 747 | - ? openstation_comments_ai_provider_configured() | |
| 748 | - : false, | |
| 749 | - ) | |
| 750 | - : null, | |
| 751 | 758 | 'currentUserIsAdmin' => current_user_can( 'manage_options' ), |
| 752 | 759 | // Null on single-site installs; its `networkAdmin` null |
| 753 | 760 | // without `manage_network`, which is what keeps the dock |
| 754 | 761 | // tile from registering. |