@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
JavaScript
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