@backstage/plugin-techdocs
Version:
The Backstage plugin that renders technical documentation for your components
174 lines (171 loc) • 4.99 kB
JavaScript
import { useApi } from '@backstage/core-plugin-api';
import { useReducer, useRef, useMemo } from 'react';
import useAsync from 'react-use/esm/useAsync';
import useAsyncRetry from 'react-use/esm/useAsyncRetry';
import { techdocsStorageApiRef } from '@backstage/plugin-techdocs-react';
function calculateDisplayState({
contentLoading,
content,
activeSyncState
}) {
if (contentLoading) {
return "CHECKING";
}
if (activeSyncState === "BUILD_READY_RELOAD") {
return "CHECKING";
}
if (!content && activeSyncState === "CHECKING") {
return "CHECKING";
}
if (!content && activeSyncState === "BUILDING") {
return "INITIAL_BUILD";
}
if (!content) {
return "CONTENT_NOT_FOUND";
}
if (activeSyncState === "BUILDING") {
return "CONTENT_STALE_REFRESHING";
}
if (activeSyncState === "BUILD_READY") {
return "CONTENT_STALE_READY";
}
if (activeSyncState === "ERROR") {
return "CONTENT_STALE_ERROR";
}
return "CONTENT_FRESH";
}
function reducer(oldState, action) {
const newState = { ...oldState };
switch (action.type) {
case "sync":
if (action.state === "CHECKING") {
newState.buildLog = [];
}
newState.activeSyncState = action.state;
newState.syncError = action.syncError;
break;
case "contentLoading":
newState.contentLoading = true;
newState.contentError = void 0;
break;
case "content":
if (typeof action.path === "string") {
newState.path = action.path;
}
newState.contentLoading = false;
newState.content = action.content;
newState.contentError = action.contentError;
break;
case "buildLog":
newState.buildLog = newState.buildLog.concat(action.log);
break;
default:
throw new Error();
}
if (["BUILD_READY", "BUILD_READY_RELOAD"].includes(newState.activeSyncState) && ["contentLoading", "content"].includes(action.type)) {
newState.activeSyncState = "UP_TO_DATE";
newState.buildLog = [];
}
return newState;
}
function useReaderState(kind, namespace, name, path) {
const [state, dispatch] = useReducer(reducer, {
activeSyncState: "CHECKING",
path,
contentLoading: true,
buildLog: []
});
const techdocsStorageApi = useApi(techdocsStorageApiRef);
const { retry: contentReload } = useAsyncRetry(async () => {
dispatch({ type: "contentLoading" });
try {
const entityDocs = await techdocsStorageApi.getEntityDocs(
{ kind, namespace, name },
path
);
dispatch({ type: "content", content: entityDocs, path });
return entityDocs;
} catch (e) {
dispatch({ type: "content", contentError: e, path });
}
return void 0;
}, [techdocsStorageApi, kind, namespace, name, path]);
const contentRef = useRef({
content: void 0,
reload: () => {
}
});
contentRef.current = { content: state.content, reload: contentReload };
useAsync(async () => {
dispatch({ type: "sync", state: "CHECKING" });
const buildingTimeout = setTimeout(() => {
dispatch({ type: "sync", state: "BUILDING" });
}, 1e3);
try {
const result = await techdocsStorageApi.syncEntityDocs(
{
kind,
namespace,
name
},
(log) => {
dispatch({ type: "buildLog", log });
}
);
switch (result) {
case "updated":
if (!contentRef.current.content) {
contentRef.current.reload();
dispatch({ type: "sync", state: "BUILD_READY_RELOAD" });
} else {
dispatch({ type: "sync", state: "BUILD_READY" });
}
break;
case "cached":
dispatch({ type: "sync", state: "UP_TO_DATE" });
break;
default:
dispatch({
type: "sync",
state: "ERROR",
syncError: new Error("Unexpected return state")
});
break;
}
} catch (e) {
dispatch({ type: "sync", state: "ERROR", syncError: e });
} finally {
clearTimeout(buildingTimeout);
}
}, [kind, name, namespace, techdocsStorageApi, dispatch, contentRef]);
const displayState = useMemo(
() => calculateDisplayState({
activeSyncState: state.activeSyncState,
contentLoading: state.contentLoading,
content: state.content
}),
[state.activeSyncState, state.content, state.contentLoading]
);
return useMemo(
() => ({
state: displayState,
contentReload,
path: state.path,
content: state.content,
contentErrorMessage: state.contentError?.toString(),
syncErrorMessage: state.syncError?.toString(),
buildLog: state.buildLog
}),
[
displayState,
contentReload,
state.path,
state.content,
state.contentError,
state.syncError,
state.buildLog
]
);
}
export { calculateDisplayState, reducer, useReaderState };
//# sourceMappingURL=useReaderState.esm.js.map