* Split permissions for reading documents from updating collection * fix: Admins should have collection read permission, tests * tsc * Add admin option to permission selector * Combine publish and create permissions, update -> createDocuments where appropriate * Plural -> singular * wip * Quick version of collection structure loading, will revisit * Remove documentIds method * stash * fixing tests to account for admin creation * Add self-hosted migration * fix: Allow groups to have admin permission * Prefetch collection documents * fix: Document explorer (move/publish) not working with async documents * fix: Cannot re-parent document to collection by drag and drop * fix: Cannot drag to import into collection item without admin permission * Remove unused isEditor getter
128 lines
3.9 KiB
TypeScript
128 lines
3.9 KiB
TypeScript
import { AnimatePresence } from "framer-motion";
|
|
import { observer, useLocalStore } from "mobx-react";
|
|
import * as React from "react";
|
|
import { Switch, Route, useLocation, matchPath } from "react-router-dom";
|
|
import { TeamPreference } from "@shared/types";
|
|
import ErrorSuspended from "~/scenes/ErrorSuspended";
|
|
import DocumentContext from "~/components/DocumentContext";
|
|
import type { DocumentContextValue } from "~/components/DocumentContext";
|
|
import Layout from "~/components/Layout";
|
|
import RegisterKeyDown from "~/components/RegisterKeyDown";
|
|
import Sidebar from "~/components/Sidebar";
|
|
import SidebarRight from "~/components/Sidebar/Right";
|
|
import SettingsSidebar from "~/components/Sidebar/Settings";
|
|
import type { Editor as TEditor } from "~/editor";
|
|
import usePolicy from "~/hooks/usePolicy";
|
|
import useStores from "~/hooks/useStores";
|
|
import history from "~/utils/history";
|
|
import {
|
|
searchPath,
|
|
newDocumentPath,
|
|
settingsPath,
|
|
matchDocumentHistory,
|
|
matchDocumentSlug as slug,
|
|
matchDocumentInsights,
|
|
} from "~/utils/routeHelpers";
|
|
import Fade from "./Fade";
|
|
|
|
const DocumentComments = React.lazy(
|
|
() => import("~/scenes/Document/components/Comments")
|
|
);
|
|
const DocumentHistory = React.lazy(
|
|
() => import("~/scenes/Document/components/History")
|
|
);
|
|
const DocumentInsights = React.lazy(
|
|
() => import("~/scenes/Document/components/Insights")
|
|
);
|
|
const CommandBar = React.lazy(() => import("~/components/CommandBar"));
|
|
|
|
const AuthenticatedLayout: React.FC = ({ children }) => {
|
|
const { ui, auth } = useStores();
|
|
const location = useLocation();
|
|
const can = usePolicy(ui.activeCollectionId);
|
|
const { user, team } = auth;
|
|
const documentContext = useLocalStore<DocumentContextValue>(() => ({
|
|
editor: null,
|
|
setEditor: (editor: TEditor) => {
|
|
documentContext.editor = editor;
|
|
},
|
|
}));
|
|
|
|
const goToSearch = (ev: KeyboardEvent) => {
|
|
if (!ev.metaKey && !ev.ctrlKey) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
history.push(searchPath());
|
|
}
|
|
};
|
|
|
|
const goToNewDocument = (event: KeyboardEvent) => {
|
|
if (event.metaKey || event.altKey) {
|
|
return;
|
|
}
|
|
const { activeCollectionId } = ui;
|
|
if (!activeCollectionId || !can.createDocument) {
|
|
return;
|
|
}
|
|
history.push(newDocumentPath(activeCollectionId));
|
|
};
|
|
|
|
if (auth.isSuspended) {
|
|
return <ErrorSuspended />;
|
|
}
|
|
|
|
const showSidebar = auth.authenticated && user && team;
|
|
|
|
const sidebar = showSidebar ? (
|
|
<Fade>
|
|
<Switch>
|
|
<Route path={settingsPath()} component={SettingsSidebar} />
|
|
<Route component={Sidebar} />
|
|
</Switch>
|
|
</Fade>
|
|
) : undefined;
|
|
|
|
const showHistory = !!matchPath(location.pathname, {
|
|
path: matchDocumentHistory,
|
|
});
|
|
const showInsights = !!matchPath(location.pathname, {
|
|
path: matchDocumentInsights,
|
|
});
|
|
const showComments =
|
|
!showInsights &&
|
|
!showHistory &&
|
|
ui.activeDocumentId &&
|
|
ui.commentsExpanded.includes(ui.activeDocumentId) &&
|
|
team?.getPreference(TeamPreference.Commenting);
|
|
|
|
const sidebarRight = (
|
|
<AnimatePresence>
|
|
{(showHistory || showInsights || showComments) && (
|
|
<Route path={`/doc/${slug}`}>
|
|
<SidebarRight>
|
|
<React.Suspense fallback={null}>
|
|
{showHistory && <DocumentHistory />}
|
|
{showInsights && <DocumentInsights />}
|
|
{showComments && <DocumentComments />}
|
|
</React.Suspense>
|
|
</SidebarRight>
|
|
</Route>
|
|
)}
|
|
</AnimatePresence>
|
|
);
|
|
|
|
return (
|
|
<DocumentContext.Provider value={documentContext}>
|
|
<Layout title={team?.name} sidebar={sidebar} sidebarRight={sidebarRight}>
|
|
<RegisterKeyDown trigger="n" handler={goToNewDocument} />
|
|
<RegisterKeyDown trigger="t" handler={goToSearch} />
|
|
<RegisterKeyDown trigger="/" handler={goToSearch} />
|
|
{children}
|
|
<CommandBar />
|
|
</Layout>
|
|
</DocumentContext.Provider>
|
|
);
|
|
};
|
|
|
|
export default observer(AuthenticatedLayout);
|