// Times Square notebook execution system integration patterns. Use this skill when working with Times Square pages, implementing SSE updates, handling URL parameters, setting up GitHub PR previews, or working with the Times Square API. Covers context providers, data fetching hooks, mock API endpoints, and page routing patterns.
| name | times-square-integration |
| description | Times Square notebook execution system integration patterns. Use this skill when working with Times Square pages, implementing SSE updates, handling URL parameters, setting up GitHub PR previews, or working with the Times Square API. Covers context providers, data fetching hooks, mock API endpoints, and page routing patterns. |
Times Square is a notebook execution system integrated into the squareone app for displaying computational notebooks.
Manages URL-based state for Times Square pages.
import { TimesSquareUrlParametersContext } from '../contexts/TimesSquareUrlParametersContext';
// Provider setup (usually in page)
<TimesSquareUrlParametersContext.Provider value={urlParams}>
<TimesSquarePage />
</TimesSquareUrlParametersContext.Provider>
// Usage in components
const { getParameter, setParameter } = useContext(TimesSquareUrlParametersContext);
const value = getParameter('myParam');
setParameter('myParam', 'newValue');
Manages real-time SSE (Server-Sent Events) updates.
import { TimesSquareHtmlEventsContext } from '../contexts/TimesSquareHtmlEventsContext';
// Provider setup
<TimesSquareHtmlEventsContext.Provider value={eventSource}>
<TimesSquarePage />
</TimesSquareHtmlEventsContext.Provider>
// Usage
const events = useContext(TimesSquareHtmlEventsContext);
// events provides real-time updates from notebook execution
Custom hook for fetching Times Square page data.
import { useTimesSquarePage } from '../hooks/useTimesSquarePage';
function MyComponent({ pageSlug }) {
const { data, error, isLoading } = useTimesSquarePage(pageSlug);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{data.displayName}</div>;
}
Pattern uses SWR for caching and revalidation.
/times-square/{page-slug}
/times-square/github-pr/{owner}/{repo}/{commit}
Example:
/times-square/github-pr/lsst-sqre/times-square-demo/abc123
Mock API endpoints in development (/pages/api/dev/times-square/):
GET /times-square/api/v1/pages - List pagesGET /times-square/api/v1/pages/:page - Page metadataGET /times-square/api/v1/pages/:page/html - Rendered HTMLGET /times-square/api/v1/pages/:page/htmlstatus - Execution statusGET /times-square/api/v1/pages/:page/htmlevents - SSE endpointFor local development without Times Square backend:
// pages/api/dev/times-square/v1/pages/[page]/html.ts
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { page } = req.query;
// Return mock HTML
res.status(200).json({
html: '<div>Mock Times Square page</div>',
parameters: {},
});
}
import { GetServerSideProps } from 'next';
import { useTimesSquarePage } from '../hooks/useTimesSquarePage';
import { TimesSquareUrlParametersContext } from '../contexts/TimesSquareUrlParametersContext';
import { loadAppConfig } from '../lib/config/loader';
type Props = {
pageSlug: string;
};
export default function TimesSquarePage({ pageSlug }: Props) {
const { data, error, isLoading } = useTimesSquarePage(pageSlug);
if (isLoading) return <div>Loading notebook...</div>;
if (error) return <div>Error loading notebook</div>;
return (
<div>
<h1>{data.displayName}</h1>
<div dangerouslySetInnerHTML={{ __html: data.html }} />
</div>
);
}
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const appConfig = await loadAppConfig();
const pageSlug = context.params?.page as string;
return {
props: {
appConfig,
pageSlug,
},
};
};
function TimesSquareLivePage({ pageSlug }) {
const [eventSource, setEventSource] = useState(null);
useEffect(() => {
const es = new EventSource(
`/times-square/api/v1/pages/${pageSlug}/htmlevents`
);
es.onmessage = (event) => {
const data = JSON.parse(event.data);
// Handle real-time updates
console.log('New data:', data);
};
setEventSource(es);
return () => es.close();
}, [pageSlug]);
return (
<TimesSquareHtmlEventsContext.Provider value={eventSource}>
{/* Page content */}
</TimesSquareHtmlEventsContext.Provider>
);
}
Times Square URL configured in AppConfig:
# squareone.config.yaml
timesSquareUrl: 'http://localhost:3000/times-square/api' # Dev
# timesSquareUrl: 'https://data.lsst.cloud/times-square/api' # Prod
Access in components:
import { useAppConfig } from '../contexts/AppConfigContext';
const config = useAppConfig();
const timesSquareUrl = config.timesSquareUrl;