diff --git a/packages/cps-global-preview/src/App.tsx b/packages/cps-global-preview/src/App.tsx index fc97a3aae..472a1937a 100644 --- a/packages/cps-global-preview/src/App.tsx +++ b/packages/cps-global-preview/src/App.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from "react"; +import { useState, useEffect, useCallback, useRef, type ReactNode } from "react"; import type { AuthHint, Notification, Preview } from "cps-global-configuration"; const STATE_ENDPOINT = "/global-components/state/preview"; @@ -161,6 +161,16 @@ const FEATURES: Feature[] = [ type FeatureKey = Feature["key"]; +// A section heading that is its own #anchor, so sections can be linked to directly. +// Ids are prefixed "section-" to stay clear of the form inputs' ids. +const SectionHeading = ({ id, className, children }: { id: string; className: string; children: ReactNode }) => ( +

+ + {children} + +

+); + type StatusType = "info" | "error" | "success"; export function App() { @@ -175,6 +185,7 @@ export function App() { const [authHint, setAuthHint] = useState(null); const [sidInput, setSidInput] = useState(""); const [osTarget, setOsTarget] = useState(null); + const scrolledToHash = useRef(false); const showStatus = useCallback((message: string, type: StatusType) => { setStatus({ message, type }); @@ -273,10 +284,24 @@ export function App() { loadOsTarget(); }, [loadOsTarget]); + // Sections render after async loads (the OutSystems host one only once its + // status arrives), so the browser's own jump to the #anchor on load misses them. + // Jump once, as soon as the target exists. + useEffect(() => { + if (scrolledToHash.current || !window.location.hash) { + return; + } + const target = document.getElementById(decodeURIComponent(window.location.hash.slice(1))); + if (target) { + scrolledToHash.current = true; + target.scrollIntoView(); + } + }, [loading, osTarget, notificationsResult, authHint]); + // Leaves the page: the set route writes the cookie in Edge, flips the tab to IE // mode to write IE mode's copy, then brings the tab back here. const handleOsTargetChange = (host: string) => { - const query = new URLSearchParams({ env: ENV, host, return: window.location.pathname + window.location.search }); + const query = new URLSearchParams({ env: ENV, host, return: window.location.pathname + window.location.search + "#section-os-host" }); window.location.assign(`${OS_TARGET_SET_ENDPOINT}?${query}`); }; @@ -444,7 +469,7 @@ export function App() {
-

Features

+ Features
{FEATURES.map( @@ -612,7 +637,7 @@ export function App() {
-

Notifications

+ Notifications
@@ -653,7 +678,11 @@ export function App() { Clear dismissed notifications -

Deployed notifications

+

+ + Deployed notifications + +

Read-only view of notification.json loaded from blob storage for the {ENV} environment. Edit the source file to change @@ -755,7 +784,7 @@ export function App() {

-

Auth hint

+ Auth hint

Overwrite the lastKnownSid stored against your auth-hint cookie. @@ -814,7 +843,7 @@ export function App() {

-

OutSystems host

+ OutSystems host

Which OutSystems host the proxied CMS C-button and the menu send you @@ -847,7 +876,7 @@ export function App() {

-

Override mode

+ Override mode