diff --git a/docs/src/theme/DocItem/Content/index.js b/docs/src/theme/DocItem/Content/index.js index 2fa065ed9cb..3e36dee744b 100644 --- a/docs/src/theme/DocItem/Content/index.js +++ b/docs/src/theme/DocItem/Content/index.js @@ -1,7 +1,6 @@ import React from "react"; import Content from "@theme-original/DocItem/Content"; import Feedback from "../../Feedback"; -import LastUpdatedComponent from "../../LastUpdatedComponent"; export default function ContentWrapper(props) { return ( @@ -9,7 +8,6 @@ export default function ContentWrapper(props) { {/* eslint-disable react/jsx-props-no-spreading */} - ); } diff --git a/docs/src/theme/LastUpdated.js b/docs/src/theme/LastUpdated.js new file mode 100644 index 00000000000..df1d8245f93 --- /dev/null +++ b/docs/src/theme/LastUpdated.js @@ -0,0 +1,88 @@ +/* eslint-disable react/jsx-props-no-spreading, react/destructuring-assignment */ +import React from "react"; + +const BASE_GIT_URL = "https://api.github.com/repos/langchain-ai/langchain/commits?path=docs" +const LAST_UPDATED_ELEMENT_ID = "lc_last_updated" +const INVALID_DATE_STRING = "Invalid date" +/** + * + * @param {Array} urls + * @returns {Promise} The formatted date string or null if not found + */ +const fetchUrls = async (urls) => { + try { + const allResponses = await Promise.allSettled(urls.map(url => fetch(url))) + const allOkResponses = allResponses.filter(({ ok }) => ok); + const allData = await Promise.allSettled(allOkResponses.map(({ value }) => value.json())); + /** @type {null | string} */ + let formattedDate = null; + allData.forEach((item) => { + if (formattedDate && formattedDate !== INVALID_DATE_STRING || !item || item.length === 0 || !item[0]?.commit?.author?.date) return; + const lastCommitDate = new Date(item[0]?.commit?.author?.date); + formattedDate = lastCommitDate.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }); + }) + if (formattedDate !== INVALID_DATE_STRING) { + return formattedDate; + } + } catch (_) { + // no-op + } + return null; +} + +const getAllPossibleUrls = (currentPath) => { + currentPath = currentPath.endsWith("/") ? currentPath.slice(0, -1) : currentPath; + return { + notebookPath: `${BASE_GIT_URL}${currentPath}.ipynb`, + notebookIndexPath: `${BASE_GIT_URL}${currentPath}/index.ipynb`, + mdPath: `${BASE_GIT_URL}${currentPath}.md`, + mdIndexPath: `${BASE_GIT_URL}${currentPath}/index.md`, + mdxPath: `${BASE_GIT_URL}${currentPath}.mdx`, + mdxIndexPath: `${BASE_GIT_URL}${currentPath}/index.mdx`, + } +} + +/** + * NOTE: This component file should NEVER be updated as it overrides + * the default docusaurus LastUpdated component. + */ +export default function LastUpdated() { + const [lastUpdatedDate, setLastUpdatedDate] = React.useState(null); + + React.useEffect(() => { + if (typeof window === "undefined") return; + try { + let currentPath = window.location.pathname; + const allUrls = getAllPossibleUrls(currentPath); + const { notebookPath, notebookIndexPath, ...rest } = allUrls; + + fetchUrls([notebookPath, notebookIndexPath]) + .then((date) => { + if (date) { + setLastUpdatedDate(date); + } else { + fetchUrls(rest) + .then((date) => { + if (date) { + setLastUpdatedDate(date); + } + }); + } + }); + } catch (_) { + // no-op + } + }, []) + + if (!lastUpdatedDate) return null; + + return ( +
+

Last updated on {lastUpdatedDate}

+
+ ); +} diff --git a/docs/src/theme/LastUpdatedComponent.js b/docs/src/theme/LastUpdatedComponent.js deleted file mode 100644 index a87034d5acb..00000000000 --- a/docs/src/theme/LastUpdatedComponent.js +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable react/jsx-props-no-spreading, react/destructuring-assignment */ -import React from "react"; - -const BASE_GIT_URL = "https://api.github.com/repos/langchain-ai/langchain/commits?path=docs" - -const LAST_UPDATED_ELEMENT_ID = "lc_last_updated" - -const fetchUrl = async (url) => { - try { - const res = await fetch(url) - if (!res.ok) return null; - const json = await res.json(); - if (!json || json.length === 0 || !json[0]?.commit?.author?.date) return null; - const lastCommitDate = new Date(json[0]?.commit?.author?.date); - const formattedDate = lastCommitDate.toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); - if (formattedDate !== "Invalid Date") { - return formattedDate; - } - } catch (_) { - // no-op - } - return null; -} - -/** - * NOTE: This component file can NOT be named `LastUpdated` as it - * conflicts with the built-in Docusaurus component, and will override it. - */ -export default function LastUpdatedComponent() { - const [lastUpdatedDate, setLastUpdatedDate] = React.useState(null); - - React.useEffect(() => { - if (typeof window === "undefined") return; - try { - let currentPath = window.location.pathname; - if (currentPath.endsWith("/")) { - // strip the trailing slash - currentPath = currentPath.slice(0, -1); - } - const apiUrl = `${BASE_GIT_URL}${currentPath}.ipynb` - const apiUrlWithIndex = `${BASE_GIT_URL}${currentPath}/index.ipynb` - - fetchUrl(apiUrl) - .then((date) => { - if (date) { - setLastUpdatedDate(date); - } else { - fetchUrl(apiUrlWithIndex) - .then((date) => { - if (date) { - setLastUpdatedDate(date); - } - }); - } - }); - } catch (_) { - // no-op - } - }, []) - - if (!lastUpdatedDate) return null; - - return ( -
-

Last updated on {lastUpdatedDate}

-
- ); -}