From 492affb29acbc4daede9d42fb107c85d66338e22 Mon Sep 17 00:00:00 2001 From: Denis Olsem Date: Thu, 29 Sep 2022 06:49:35 -0500 Subject: [PATCH] Share document link that opens full editor (#4134) Co-authored-by: Tom Moor --- app/components/Popover.tsx | 2 +- app/scenes/Document/Shared.tsx | 12 ++- .../Document/components/SharePopover.tsx | 89 +++++++++++++++---- shared/i18n/locales/en_US/translation.json | 4 + 4 files changed, 86 insertions(+), 21 deletions(-) diff --git a/app/components/Popover.tsx b/app/components/Popover.tsx index 2399ab418..254fff847 100644 --- a/app/components/Popover.tsx +++ b/app/components/Popover.tsx @@ -46,7 +46,7 @@ const Contents = styled.div<{ $shrink?: boolean; $width?: number }>` border-radius: 6px; padding: ${(props) => (props.$shrink ? "6px 0" : "12px 24px")}; max-height: 50vh; - overflow-y: scroll; + overflow-y: auto; box-shadow: ${(props) => props.theme.menuShadow}; width: ${(props) => props.$width}px; diff --git a/app/scenes/Document/Shared.tsx b/app/scenes/Document/Shared.tsx index 703958d6d..fb05f571b 100644 --- a/app/scenes/Document/Shared.tsx +++ b/app/scenes/Document/Shared.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import * as React from "react"; import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; -import { RouteComponentProps, useLocation } from "react-router-dom"; +import { RouteComponentProps, useLocation, Redirect } from "react-router-dom"; import styled, { useTheme } from "styled-components"; import { setCookie } from "tiny-cookie"; import DocumentModel from "~/models/Document"; @@ -12,6 +12,7 @@ import ErrorOffline from "~/scenes/ErrorOffline"; import Layout from "~/components/Layout"; import Sidebar from "~/components/Sidebar/Shared"; import Text from "~/components/Text"; +import usePolicy from "~/hooks/usePolicy"; import useStores from "~/hooks/useStores"; import { NavigationNode } from "~/types"; import { AuthorizationError, OfflineError } from "~/utils/errors"; @@ -78,12 +79,17 @@ function SharedDocumentScene(props: Props) { const { ui } = useStores(); const theme = useTheme(); const location = useLocation(); + const searchParams = React.useMemo( + () => new URLSearchParams(location.search), + [location.search] + ); const { t } = useTranslation(); const [response, setResponse] = React.useState(); const [error, setError] = React.useState(); const { documents } = useStores(); const { shareId, documentSlug } = props.match.params; const documentId = useDocumentId(documentSlug, response); + const can = usePolicy(response?.document.id ?? ""); // ensure the wider page color always matches the theme React.useEffect(() => { @@ -140,6 +146,10 @@ function SharedDocumentScene(props: Props) { return ; } + if (response && searchParams.get("edit") === "true" && can.update) { + return ; + } + const sidebar = response.sharedTree ? ( ) : undefined; diff --git a/app/scenes/Document/components/SharePopover.tsx b/app/scenes/Document/components/SharePopover.tsx index 35bff4f1e..6c203dd25 100644 --- a/app/scenes/Document/components/SharePopover.tsx +++ b/app/scenes/Document/components/SharePopover.tsx @@ -1,7 +1,7 @@ import { formatDistanceToNow } from "date-fns"; import invariant from "invariant"; import { observer } from "mobx-react"; -import { GlobeIcon, PadlockIcon } from "outline-icons"; +import { ExpandedIcon, GlobeIcon, PadlockIcon } from "outline-icons"; import * as React from "react"; import { useTranslation, Trans } from "react-i18next"; import styled from "styled-components"; @@ -10,7 +10,6 @@ import Share from "~/models/Share"; import Button from "~/components/Button"; import CopyToClipboard from "~/components/CopyToClipboard"; import Flex from "~/components/Flex"; -import Input from "~/components/Input"; import Notice from "~/components/Notice"; import Switch from "~/components/Switch"; import Text from "~/components/Text"; @@ -42,6 +41,8 @@ function SharePopover({ const { shares } = useStores(); const { showToast } = useToasts(); const [isCopied, setIsCopied] = React.useState(false); + const [expandedOptions, setExpandedOptions] = React.useState(false); + const [isEditMode, setIsEditMode] = React.useState(false); const timeout = React.useRef>(); const buttonRef = React.useRef(null); const can = usePolicy(share ? share.id : ""); @@ -56,6 +57,11 @@ function SharePopover({ ((share && share.published) || (sharedParent && sharedParent.published && !document.isDraft)); + React.useEffect(() => { + if (!visible && expandedOptions) { + setExpandedOptions(false); + } + }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps useKeyDown("Escape", onRequestClose); React.useEffect(() => { @@ -116,9 +122,10 @@ function SharePopover({ const userLocale = useUserLocale(); const locale = userLocale ? dateLocale(userLocale) : undefined; - const shareUrl = team.sharing - ? share?.url ?? "" - : `${team.url}${document.url}`; + let shareUrl = team.sharing ? share?.url ?? "" : `${team.url}${document.url}`; + if (isEditMode) { + shareUrl += "?edit=true"; + } return ( <> @@ -127,8 +134,8 @@ function SharePopover({ ) : ( - )}{" "} - {t("Share this document")} + )} + {t("Share this document")} {sharedParent && !document.isDraft && ( @@ -196,19 +203,52 @@ function SharePopover({ {share.includeChildDocuments ? t("Nested documents are publicly available") : t("Nested documents are not shared")} + . )} - - + + {expandedOptions && ( + <> + + + + setIsEditMode(checked) + } + checked={isEditMode} + disabled={!share} + /> + + + {isEditMode + ? t( + "Users with edit permission will be redirected to the main app" + ) + : t("All users see the same publicly shared view")} + . + + + + + )} + + + {expandedOptions ? ( + + ) : ( + } + onClick={() => setExpandedOptions(true)} + neutral + borderOnHover + > + {t("More options")} + + )}