diff --git a/app/components/Avatar/Avatar.tsx b/app/components/Avatar/Avatar.tsx index 4d694718f..d7f2acf6c 100644 --- a/app/components/Avatar/Avatar.tsx +++ b/app/components/Avatar/Avatar.tsx @@ -54,6 +54,7 @@ Avatar.defaultProps = { const Relative = styled.div` position: relative; + flex-shrink: 0; `; const IconWrapper = styled.div` @@ -77,6 +78,7 @@ const CircleImg = styled.img<{ size: number; $showBorder?: boolean }>` ${(props) => props.$showBorder === false ? "transparent" : props.theme.background}; flex-shrink: 0; + overflow: hidden; `; export default Avatar; diff --git a/app/components/Sidebar/App.tsx b/app/components/Sidebar/App.tsx index 4385bf0a7..6965ab0ae 100644 --- a/app/components/Sidebar/App.tsx +++ b/app/components/Sidebar/App.tsx @@ -24,9 +24,9 @@ import TeamLogo from "../TeamLogo"; import Sidebar from "./Sidebar"; import ArchiveLink from "./components/ArchiveLink"; import Collections from "./components/Collections"; +import HeaderButton, { HeaderButtonProps } from "./components/HeaderButton"; import Section from "./components/Section"; import SidebarAction from "./components/SidebarAction"; -import SidebarButton, { SidebarButtonProps } from "./components/SidebarButton"; import SidebarLink from "./components/SidebarLink"; import Starred from "./components/Starred"; import TrashLink from "./components/TrashLink"; @@ -59,8 +59,8 @@ function AppSidebar() { {dndArea && ( - {(props: SidebarButtonProps) => ( - ( + } diff --git a/app/components/Sidebar/Settings.tsx b/app/components/Sidebar/Settings.tsx index 647c6d6a9..5ac80f451 100644 --- a/app/components/Sidebar/Settings.tsx +++ b/app/components/Sidebar/Settings.tsx @@ -11,8 +11,8 @@ import useAuthorizedSettingsConfig from "~/hooks/useAuthorizedSettingsConfig"; import isCloudHosted from "~/utils/isCloudHosted"; import Sidebar from "./Sidebar"; import Header from "./components/Header"; +import HeaderButton from "./components/HeaderButton"; import Section from "./components/Section"; -import SidebarButton from "./components/SidebarButton"; import SidebarLink from "./components/SidebarLink"; import Version from "./components/Version"; @@ -28,7 +28,7 @@ function SettingsSidebar() { return ( - } onClick={returnToApp} diff --git a/app/components/Sidebar/Shared.tsx b/app/components/Sidebar/Shared.tsx index 29800a437..0f6fb5546 100644 --- a/app/components/Sidebar/Shared.tsx +++ b/app/components/Sidebar/Shared.tsx @@ -1,33 +1,52 @@ import { observer } from "mobx-react"; import * as React from "react"; +import { useTranslation } from "react-i18next"; import styled from "styled-components"; +import Team from "~/models/Team"; import Scrollable from "~/components/Scrollable"; import SearchPopover from "~/components/SearchPopover"; import useStores from "~/hooks/useStores"; import { NavigationNode } from "~/types"; +import history from "~/utils/history"; +import { homePath, sharedDocumentPath } from "~/utils/routeHelpers"; +import TeamLogo from "../TeamLogo"; import Sidebar from "./Sidebar"; +import HeaderButton from "./components/HeaderButton"; import Section from "./components/Section"; import DocumentLink from "./components/SharedDocumentLink"; type Props = { + team?: Team; rootNode: NavigationNode; shareId: string; }; -function SharedSidebar({ rootNode, shareId }: Props) { - const { ui, documents } = useStores(); +function SharedSidebar({ rootNode, team, shareId }: Props) { + const { ui, documents, auth } = useStores(); + const { t } = useTranslation(); return ( - + {team && ( + } + onClick={() => + history.push( + auth.user ? homePath() : sharedDocumentPath(shareId, rootNode.url) + ) + } + /> + )} +
( {user && ( - {(props: SidebarButtonProps) => ( - ( + ; }; -const SidebarButton = React.forwardRef( +const HeaderButton = React.forwardRef( ( { showDisclosure, @@ -22,7 +22,7 @@ const SidebarButton = React.forwardRef( title, minHeight = 0, ...rest - }: SidebarButtonProps, + }: HeaderButtonProps, ref ) => ( ( {...rest} ref={ref} > - + <Title gap={6} align="center"> {image} {title} @@ -79,4 +79,4 @@ const Wrapper = styled(Flex)<{ minHeight: number }>` } `; -export default SidebarButton; +export default HeaderButton; diff --git a/app/components/Sidebar/components/SharedDocumentLink.tsx b/app/components/Sidebar/components/SharedDocumentLink.tsx index e379c2bcc..4a709907f 100644 --- a/app/components/Sidebar/components/SharedDocumentLink.tsx +++ b/app/components/Sidebar/components/SharedDocumentLink.tsx @@ -100,7 +100,7 @@ function DocumentLink( }} label={ <> - {hasChildDocuments && ( + {hasChildDocuments && depth !== 0 && ( )} {title} diff --git a/app/components/TeamLogo.ts b/app/components/TeamLogo.ts index 6cadfd425..ec8501e62 100644 --- a/app/components/TeamLogo.ts +++ b/app/components/TeamLogo.ts @@ -4,8 +4,6 @@ import Avatar from "./Avatar"; const TeamLogo = styled(Avatar)` border-radius: 4px; border: 1px solid ${(props) => props.theme.divider}; - overflow: hidden; - flex-shrink: 0; `; export default TeamLogo; diff --git a/app/scenes/Document/Shared.tsx b/app/scenes/Document/Shared.tsx index 13cbab1e2..e07d81386 100644 --- a/app/scenes/Document/Shared.tsx +++ b/app/scenes/Document/Shared.tsx @@ -7,6 +7,7 @@ import { RouteComponentProps, useLocation, Redirect } from "react-router-dom"; import styled, { useTheme } from "styled-components"; import { setCookie } from "tiny-cookie"; import DocumentModel from "~/models/Document"; +import Team from "~/models/Team"; import Error404 from "~/scenes/Error404"; import ErrorOffline from "~/scenes/ErrorOffline"; import Layout from "~/components/Layout"; @@ -26,6 +27,7 @@ const EMPTY_OBJECT = {}; type Response = { document: DocumentModel; + team?: Team; sharedTree?: NavigationNode | undefined; }; @@ -157,8 +159,12 @@ function SharedDocumentScene(props: Props) { return ; } - const sidebar = response.sharedTree ? ( - + const sidebar = response.sharedTree?.children.length ? ( + ) : undefined; return ( diff --git a/app/scenes/Settings/Features.tsx b/app/scenes/Settings/Features.tsx index 14360327c..13be0cfb5 100644 --- a/app/scenes/Settings/Features.tsx +++ b/app/scenes/Settings/Features.tsx @@ -43,15 +43,15 @@ function Features() { {team.collaborativeEditing && ( @@ -59,16 +59,16 @@ function Features() { )} {team.avatarUrl && ( diff --git a/app/stores/DocumentsStore.ts b/app/stores/DocumentsStore.ts index 80eb6dbba..67c658b86 100644 --- a/app/stores/DocumentsStore.ts +++ b/app/stores/DocumentsStore.ts @@ -10,6 +10,7 @@ import { DocumentValidation } from "@shared/validations"; import BaseStore from "~/stores/BaseStore"; import RootStore from "~/stores/RootStore"; import Document from "~/models/Document"; +import Team from "~/models/Team"; import env from "~/env"; import { FetchOptions, @@ -40,7 +41,10 @@ type ImportOptions = { }; export default class DocumentsStore extends BaseStore { - sharedTreeCache: Map = new Map(); + sharedCache: Map< + string, + { sharedTree: NavigationNode; team: Team } | undefined + > = new Map(); @observable searchCache: Map = new Map(); @@ -265,7 +269,7 @@ export default class DocumentsStore extends BaseStore { } getSharedTree(documentId: string): NavigationNode | undefined { - return this.sharedTreeCache.get(documentId); + return this.sharedCache.get(documentId)?.sharedTree; } @action @@ -466,6 +470,7 @@ export default class DocumentsStore extends BaseStore { options: FetchOptions = {} ): Promise<{ document: Document; + team?: Team; sharedTree?: NavigationNode; }> => { if (!options.prefetch) { @@ -482,10 +487,10 @@ export default class DocumentsStore extends BaseStore { return { document: doc, }; - } else if (this.sharedTreeCache.has(options.shareId)) { + } else if (this.sharedCache.has(options.shareId)) { return { document: doc, - sharedTree: this.sharedTreeCache.get(options.shareId), + ...this.sharedCache.get(options.shareId), }; } } @@ -504,10 +509,14 @@ export default class DocumentsStore extends BaseStore { invariant(document, "Document not available"); if (options.shareId) { - this.sharedTreeCache.set(options.shareId, res.data.sharedTree); + this.sharedCache.set(options.shareId, { + sharedTree: res.data.sharedTree, + team: res.data.team, + }); return { document, sharedTree: res.data.sharedTree, + team: res.data.team, }; } diff --git a/server/routes/api/auth.ts b/server/routes/api/auth.ts index 80d67e323..c6c9f2bdc 100644 --- a/server/routes/api/auth.ts +++ b/server/routes/api/auth.ts @@ -1,5 +1,6 @@ import Router from "koa-router"; import { find, uniqBy } from "lodash"; +import { TeamPreference } from "@shared/types"; import { parseDomain } from "@shared/utils/domains"; import env from "@server/env"; import auth from "@server/middlewares/authentication"; @@ -57,7 +58,9 @@ router.post("auth.config", async (ctx) => { ctx.body = { data: { name: team.name, - logo: team.preferences?.publicBranding ? team.avatarUrl : undefined, + logo: team.getPreference(TeamPreference.PublicBranding) + ? team.avatarUrl + : undefined, providers: filterProviders(team), }, }; @@ -78,7 +81,9 @@ router.post("auth.config", async (ctx) => { ctx.body = { data: { name: team.name, - logo: team.preferences?.publicBranding ? team.avatarUrl : undefined, + logo: team.getPreference(TeamPreference.PublicBranding) + ? team.avatarUrl + : undefined, hostname: ctx.request.hostname, providers: filterProviders(team), }, @@ -100,7 +105,9 @@ router.post("auth.config", async (ctx) => { ctx.body = { data: { name: team.name, - logo: team.preferences?.publicBranding ? team.avatarUrl : undefined, + logo: team.getPreference(TeamPreference.PublicBranding) + ? team.avatarUrl + : undefined, hostname: ctx.request.hostname, providers: filterProviders(team), }, diff --git a/server/routes/api/documents.ts b/server/routes/api/documents.ts index fe20c05b9..f008cd859 100644 --- a/server/routes/api/documents.ts +++ b/server/routes/api/documents.ts @@ -1,8 +1,10 @@ import fs from "fs-extra"; import invariant from "invariant"; import Router from "koa-router"; +import { pick } from "lodash"; import mime from "mime-types"; import { Op, ScopeOptions, WhereOptions } from "sequelize"; +import { TeamPreference } from "@shared/types"; import { subtractDate } from "@shared/utils/date"; import { bytesToHumanReadable } from "@shared/utils/files"; import documentCreator from "@server/commands/documentCreator"; @@ -422,13 +424,18 @@ router.post( const serializedDocument = await presentDocument(document, { isPublic, }); - // Passing apiVersion=2 has a single effect, to change the response payload to - // include document and sharedTree keys. + const team = await document.$get("team"); + + // Passing apiVersion=2 has a single effect, to change the response payload to + // include top level keys for document, sharedTree, and team. const data = apiVersion === 2 ? { document: serializedDocument, + team: team?.getPreference(TeamPreference.PublicBranding) + ? pick(team, ["avatarUrl", "name"]) + : undefined, sharedTree: share && share.includeChildDocuments ? collection?.getDocumentTree(share.documentId)