fix: Various editor header and metadata fixes (#2361)

* fix: Publish button disabled on drafts in read-only mode
fix: Template selector appears on edited documents

* fix: Save button does not immediately come available when selecting a template

* fix: Template menu item alignment
closes #2204

* fixes: Use policy for display of star in document title
closes #2354

* fix: Modified time is sometimes bold when last edited user is current user
closes #2355

* fix: Allow starring of drafts
This commit is contained in:
Tom Moor
2021-07-22 18:17:18 -04:00
committed by GitHub
parent d35b5d2613
commit 84ad7c482c
6 changed files with 33 additions and 16 deletions

View File

@ -8,6 +8,7 @@ import Document from "models/Document";
import DocumentBreadcrumb from "components/DocumentBreadcrumb"; import DocumentBreadcrumb from "components/DocumentBreadcrumb";
import Flex from "components/Flex"; import Flex from "components/Flex";
import Time from "components/Time"; import Time from "components/Time";
import useCurrentUser from "hooks/useCurrentUser";
import useStores from "hooks/useStores"; import useStores from "hooks/useStores";
const Container = styled(Flex)` const Container = styled(Flex)`
@ -50,7 +51,9 @@ function DocumentMeta({
...rest ...rest
}: Props) { }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const { collections, auth } = useStores(); const { collections } = useStores();
const user = useCurrentUser();
const { const {
modifiedSinceViewed, modifiedSinceViewed,
updatedAt, updatedAt,
@ -69,6 +72,8 @@ function DocumentMeta({
return null; return null;
} }
const collection = collections.get(document.collectionId);
const lastUpdatedByCurrentUser = user.id === updatedBy.id;
let content; let content;
if (deletedAt) { if (deletedAt) {
@ -103,15 +108,12 @@ function DocumentMeta({
); );
} else { } else {
content = ( content = (
<Modified highlight={modifiedSinceViewed}> <Modified highlight={modifiedSinceViewed && !lastUpdatedByCurrentUser}>
{t("updated")} <Time dateTime={updatedAt} addSuffix /> {t("updated")} <Time dateTime={updatedAt} addSuffix />
</Modified> </Modified>
); );
} }
const collection = collections.get(document.collectionId);
const updatedByMe = auth.user && auth.user.id === updatedBy.id;
const timeSinceNow = () => { const timeSinceNow = () => {
if (isDraft || !showLastViewed) { if (isDraft || !showLastViewed) {
return null; return null;
@ -137,7 +139,7 @@ function DocumentMeta({
return ( return (
<Container align="center" rtl={document.dir === "rtl"} {...rest} dir="ltr"> <Container align="center" rtl={document.dir === "rtl"} {...rest} dir="ltr">
{updatedByMe ? t("You") : updatedBy.name}&nbsp; {lastUpdatedByCurrentUser ? t("You") : updatedBy.name}&nbsp;
{to ? <Link to={to}>{content}</Link> : content} {to ? <Link to={to}>{content}</Link> : content}
{showCollection && collection && ( {showCollection && collection && (
<span> <span>

View File

@ -40,13 +40,13 @@ function TemplatesMenu({ document }: Props) {
{...menu} {...menu}
> >
<DocumentIcon /> <DocumentIcon />
<div> <TemplateItem>
<strong>{template.titleWithDefault}</strong> <strong>{template.titleWithDefault}</strong>
<br /> <br />
<Author> <Author>
{t("By {{ author }}", { author: template.createdBy.name })} {t("By {{ author }}", { author: template.createdBy.name })}
</Author> </Author>
</div> </TemplateItem>
</MenuItem> </MenuItem>
); );
@ -70,9 +70,12 @@ function TemplatesMenu({ document }: Props) {
); );
} }
const Author = styled.div` const TemplateItem = styled.div`
font-size: 13px;
text-align: left; text-align: left;
`; `;
const Author = styled.div`
font-size: 13px;
`;
export default observer(TemplatesMenu); export default observer(TemplatesMenu);

View File

@ -76,6 +76,10 @@ class DocumentScene extends React.Component<Props> {
@observable title: string = this.props.document.title; @observable title: string = this.props.document.title;
getEditorText: () => string = () => this.props.document.text; getEditorText: () => string = () => this.props.document.text;
componentDidMount() {
this.updateIsDirty();
}
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { auth, document, t } = this.props; const { auth, document, t } = this.props;
@ -113,6 +117,7 @@ class DocumentScene extends React.Component<Props> {
document.injectTemplate = false; document.injectTemplate = false;
this.title = document.title; this.title = document.title;
this.isDirty = true; this.isDirty = true;
this.updateIsDirty();
} }
} }
@ -529,6 +534,6 @@ const MaxWidth = styled(Flex)`
export default withRouter( export default withRouter(
withTranslation()<DocumentScene>( withTranslation()<DocumentScene>(
inject("ui", "auth", "policies", "revisions", "toasts")(DocumentScene) inject("ui", "auth", "toasts")(DocumentScene)
) )
); );

View File

@ -1,6 +1,6 @@
// @flow // @flow
import { observable } from "mobx"; import { observable } from "mobx";
import { observer } from "mobx-react"; import { inject, observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import Textarea from "react-autosize-textarea"; import Textarea from "react-autosize-textarea";
import { type TFunction, withTranslation } from "react-i18next"; import { type TFunction, withTranslation } from "react-i18next";
@ -9,6 +9,7 @@ import breakpoint from "styled-components-breakpoint";
import { MAX_TITLE_LENGTH } from "shared/constants"; import { MAX_TITLE_LENGTH } from "shared/constants";
import { light } from "shared/theme"; import { light } from "shared/theme";
import parseTitle from "shared/utils/parseTitle"; import parseTitle from "shared/utils/parseTitle";
import PoliciesStore from "stores/PoliciesStore";
import Document from "models/Document"; import Document from "models/Document";
import ClickablePadding from "components/ClickablePadding"; import ClickablePadding from "components/ClickablePadding";
import DocumentMetaWithViews from "components/DocumentMetaWithViews"; import DocumentMetaWithViews from "components/DocumentMetaWithViews";
@ -29,6 +30,7 @@ type Props = {|
onSave: ({ done?: boolean, autosave?: boolean, publish?: boolean }) => any, onSave: ({ done?: boolean, autosave?: boolean, publish?: boolean }) => any,
innerRef: { current: any }, innerRef: { current: any },
children: React.Node, children: React.Node,
policies: PoliciesStore,
t: TFunction, t: TFunction,
|}; |};
@ -104,10 +106,12 @@ class DocumentEditor extends React.Component<Props> {
readOnly, readOnly,
innerRef, innerRef,
children, children,
policies,
t, t,
...rest ...rest
} = this.props; } = this.props;
const can = policies.abilities(document.id);
const { emoji } = parseTitle(title); const { emoji } = parseTitle(title);
const startsWithEmojiAndSpace = !!(emoji && title.startsWith(`${emoji} `)); const startsWithEmojiAndSpace = !!(emoji && title.startsWith(`${emoji} `));
const normalizedTitle = const normalizedTitle =
@ -124,7 +128,9 @@ class DocumentEditor extends React.Component<Props> {
dir="auto" dir="auto"
> >
<span>{normalizedTitle}</span>{" "} <span>{normalizedTitle}</span>{" "}
{!shareId && <StarButton document={document} size={32} />} {(can.star || can.unstar) && (
<StarButton document={document} size={32} />
)}
</Title> </Title>
) : ( ) : (
<Title <Title
@ -231,4 +237,6 @@ const Title = styled(Textarea)`
} }
`; `;
export default withTranslation()<DocumentEditor>(DocumentEditor); export default withTranslation()<DocumentEditor>(
inject("policies")(DocumentEditor)
);

View File

@ -76,7 +76,7 @@ function DocumentHeader({
onSave({ done: true, publish: true }); onSave({ done: true, publish: true });
}, [onSave]); }, [onSave]);
const isNew = document.isNew; const isNew = document.isNewDocument;
const isTemplate = document.isTemplate; const isTemplate = document.isTemplate;
const can = policies.abilities(document.id); const can = policies.abilities(document.id);
const canShareDocument = auth.team && auth.team.sharing && can.share; const canShareDocument = auth.team && auth.team.sharing && can.share;

View File

@ -23,7 +23,6 @@ allow(User, ["star", "unstar"], Document, (user, document) => {
if (document.archivedAt) return false; if (document.archivedAt) return false;
if (document.deletedAt) return false; if (document.deletedAt) return false;
if (document.template) return false; if (document.template) return false;
if (!document.publishedAt) return false;
invariant( invariant(
document.collection, document.collection,