UNPKG

@airplane/views

Version:

A React library for building Airplane views. Views components are optimized in style and functionality to produce internal apps that are easy to build and maintain.

229 lines (228 loc) 7.36 kB
import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useState, useEffect } from "react"; import { VIEWS_GET, WEB_HOST_GET, TASKS_GET_METADATA } from "../client/endpoints.js"; import { AIRPLANE_ENV_SLUG } from "../client/env.js"; import { Fetcher } from "../client/fetcher.js"; import { sendViewMessage } from "../message/sendViewMessage.js"; const useRouter = () => { const queryClient = useQueryClient(); const viewParams = useQueryParamsFromHash(); const getViewURL = useCallback(async (viewSlug, queryParams) => { const fetcher = new Fetcher(); const [viewData, webHost] = await Promise.all([queryClient.fetchQuery([VIEWS_GET, viewSlug], async () => { return await fetcher.get(VIEWS_GET, { slug: viewSlug }); }), queryClient.fetchQuery([WEB_HOST_GET], async () => { return await fetcher.get(WEB_HOST_GET, {}); })]); if (queryParams === void 0) { queryParams = new URLSearchParams(); } if (viewData == null ? void 0 : viewData.isLocal) { const studioQueryParams = new URLSearchParams(queryParams); studioQueryParams.append("view", viewSlug); return `${webHost}/studio?${studioQueryParams}`; } return `${webHost}/views/${viewData.id}?${queryParams}`; }, [queryClient]); const getTaskURL = useCallback(async (taskSlug, queryParams) => { const fetcher = new Fetcher(); const [taskMetadata, webHost] = await Promise.all([queryClient.fetchQuery([TASKS_GET_METADATA, taskSlug], async () => { return await fetcher.get(TASKS_GET_METADATA, { slug: taskSlug }); }), queryClient.fetchQuery([WEB_HOST_GET], async () => { return await fetcher.get(WEB_HOST_GET, {}); })]); if (queryParams === void 0) { queryParams = new URLSearchParams(); } if (taskMetadata == null ? void 0 : taskMetadata.isLocal) { const studioQueryParams = new URLSearchParams(queryParams); studioQueryParams.append("task", taskSlug); return `${webHost}/studio?${studioQueryParams}`; } return `${webHost}/tasks/${taskMetadata.id}?${queryParams}`; }, [queryClient]); const getRunURL = useCallback(async (runID, queryParams) => { const fetcher = new Fetcher(); const webHost = await queryClient.fetchQuery([WEB_HOST_GET], async () => { return await fetcher.get(WEB_HOST_GET, {}); }); if (queryParams === void 0) { queryParams = new URLSearchParams(); } if (isLocalDevRunID(runID)) { const studioQueryParams = new URLSearchParams(queryParams); studioQueryParams.append("run", runID); return `${webHost}/studio?${studioQueryParams}`; } else if (isRemoteRunID(runID)) { return `${webHost}/runs/${runID}?${queryParams}`; } else throw new Error("Run ID is not local or remote."); }, [queryClient]); const getHref = useCallback(({ view, task, runID, params }) => { const queryParams = new URLSearchParams(coerceParamsType(params)); if (AIRPLANE_ENV_SLUG) { queryParams.append("__env", AIRPLANE_ENV_SLUG); } propagateQueryParam(queryParams, "__airplane_host"); propagateQueryParam(queryParams, "__airplane_tunnel_token"); propagateQueryParam(queryParams, "__airplane_sandbox_token"); const count = [view, task, runID].filter(Boolean).length; if (count > 1) { throw new Error("Only one of view, task, or runID can be set"); } if (view) { return getViewURL(view, queryParams); } else if (task) { return getTaskURL(task, queryParams); } else if (runID) { return getRunURL(runID, queryParams); } else { return Promise.resolve(`/#${queryParams}`); } }, [getTaskURL, getViewURL, getRunURL]); const navigate = useCallback(({ view, task, runID, params }) => { if (typeof window === "undefined" || !window.top) { return Promise.resolve(); } const nav = async () => { if (view || task || runID) { window.top.location.href = await getHref({ view, task, runID, params }); } else if (inIframe()) { sendViewMessage({ type: "update_query_params", params: coerceParamsType(params) }); } else { window.history.pushState({}, "", await getHref({ params })); window.dispatchEvent(new HashChangeEvent("hashchange")); } }; return nav(); }, [getHref]); const peek = useCallback((peekParams) => { if (inIframe()) { if ("view" in peekParams && peekParams.view) { sendViewMessage({ type: "peek", peekType: "view", slug: peekParams.view, params: peekParams.params, as: peekParams.as }); } else if ("task" in peekParams && peekParams.task) { sendViewMessage({ type: "peek", peekType: "task", slug: peekParams.task, params: peekParams.params, as: peekParams.as }); } else if ("runbook" in peekParams && peekParams.runbook) { sendViewMessage({ type: "peek", peekType: "runbook", slug: peekParams.runbook, params: peekParams.params, as: peekParams.as }); } else if ("page" in peekParams && peekParams.page) { sendViewMessage({ type: "peek", peekType: "page", slug: peekParams.page, params: peekParams.params, as: peekParams.as }); } else { throw new Error("Must specify task, view, runbook, or page"); } } }, []); return { params: Object.fromEntries(viewParams), navigate, getHref, peek }; }; const coerceParamsType = (params) => { if (params) { const filteredParams = {}; Object.entries(params).forEach(([key, value]) => { if (value !== void 0) { filteredParams[key] = value; } }); return filteredParams; } return params; }; const useQueryParamsFromHash = () => { let initialViewParams; if (typeof window === "undefined") { initialViewParams = new URLSearchParams(); } else { initialViewParams = new URLSearchParams(getParamsStringFromHash()); } const [viewParams, setViewParams] = useState(new URLSearchParams(initialViewParams)); useEffect(() => { const handleHashChange = () => { setViewParams(new URLSearchParams(getParamsStringFromHash())); }; window.addEventListener("hashchange", handleHashChange); return () => { window.removeEventListener("hashchange", handleHashChange); }; }, []); return viewParams; }; function inIframe() { try { return window.self !== window.top; } catch (e) { return true; } } const getParamsStringFromHash = () => { var _a; return (_a = window.location.hash) == null ? void 0 : _a.slice(1); }; const isLocalDevRunID = (runID) => { return runID.startsWith("devrun"); }; const isRemoteRunID = (runID) => { return runID.startsWith("run"); }; const propagateQueryParam = (queryParams, key) => { const value = window !== void 0 ? new URLSearchParams(window.location.search).get(key) : void 0; if (value) { queryParams.append(key, value); } }; export { isLocalDevRunID, isRemoteRunID, useRouter }; //# sourceMappingURL=useRouter.js.map