diff --git a/app/components/Actions.js b/app/components/Actions.js index dd662324..2e3fbf41 100644 --- a/app/components/Actions.js +++ b/app/components/Actions.js @@ -12,7 +12,7 @@ export const Action = styled(Flex)` flex-shrink: 0; a { - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; height: 24px; } @@ -26,7 +26,7 @@ export const Separator = styled.div` margin-left: 12px; width: 1px; height: 28px; - background: ${props => props.theme.divider}; + background: ${(props) => props.theme.divider}; `; const Actions = styled(Flex)` @@ -35,8 +35,8 @@ const Actions = styled(Flex)` right: 0; left: 0; border-radius: 3px; - background: ${props => props.theme.background}; - transition: ${props => props.theme.backgroundTransition}; + background: ${(props) => props.theme.background}; + transition: ${(props) => props.theme.backgroundTransition}; padding: 12px; -webkit-backdrop-filter: blur(20px); diff --git a/app/components/Analytics.js b/app/components/Analytics.js index 30cf0832..49e4798d 100644 --- a/app/components/Analytics.js +++ b/app/components/Analytics.js @@ -14,7 +14,7 @@ export default class Analytics extends React.Component { // standard Google Analytics script window.ga = window.ga || - function() { + function () { // $FlowIssue (ga.q = ga.q || []).push(arguments); }; diff --git a/app/components/Avatar/Avatar.js b/app/components/Avatar/Avatar.js index 1066a34a..34774c81 100644 --- a/app/components/Avatar/Avatar.js +++ b/app/components/Avatar/Avatar.js @@ -48,8 +48,8 @@ const IconWrapper = styled.div` position: absolute; bottom: -2px; right: -2px; - background: ${props => props.theme.primary}; - border: 2px solid ${props => props.theme.background}; + background: ${(props) => props.theme.primary}; + border: 2px solid ${(props) => props.theme.background}; border-radius: 100%; width: 20px; height: 20px; @@ -57,10 +57,10 @@ const IconWrapper = styled.div` const CircleImg = styled.img` display: block; - width: ${props => props.size}px; - height: ${props => props.size}px; + width: ${(props) => props.size}px; + height: ${(props) => props.size}px; border-radius: 50%; - border: 2px solid ${props => props.theme.background}; + border: 2px solid ${(props) => props.theme.background}; flex-shrink: 0; `; diff --git a/app/components/Avatar/AvatarWithPresence.js b/app/components/Avatar/AvatarWithPresence.js index 1d2f6f5c..a413a58b 100644 --- a/app/components/Avatar/AvatarWithPresence.js +++ b/app/components/Avatar/AvatarWithPresence.js @@ -47,7 +47,9 @@ class AvatarWithPresence extends React.Component { {user.name} {isCurrentUser && "(You)"}
{isPresent - ? isEditing ? "currently editing" : "currently viewing" + ? isEditing + ? "currently editing" + : "currently viewing" : `viewed ${distanceInWordsToNow(new Date(lastViewedAt))} ago`} } @@ -77,7 +79,7 @@ const Centered = styled.div` `; const AvatarWrapper = styled.div` - opacity: ${props => (props.isPresent ? 1 : 0.5)}; + opacity: ${(props) => (props.isPresent ? 1 : 0.5)}; transition: opacity 250ms ease-in-out; `; diff --git a/app/components/Branding.js b/app/components/Branding.js index 88a51686..38a90a34 100644 --- a/app/components/Branding.js +++ b/app/components/Branding.js @@ -11,7 +11,8 @@ type Props = { function Branding({ href = env.URL }: Props) { return ( -  Outline + +  Outline ); } @@ -25,17 +26,17 @@ const Link = styled.a` font-size: 14px; text-decoration: none; border-top-right-radius: 2px; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; display: flex; align-items: center; padding: 16px; svg { - fill: ${props => props.theme.text}; + fill: ${(props) => props.theme.text}; } &:hover { - background: ${props => props.theme.sidebarBackground}; + background: ${(props) => props.theme.sidebarBackground}; } `; diff --git a/app/components/Breadcrumb.js b/app/components/Breadcrumb.js index 6965e502..097875f4 100644 --- a/app/components/Breadcrumb.js +++ b/app/components/Breadcrumb.js @@ -40,7 +40,7 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => { )} {collection.name} - {path.map(n => ( + {path.map((n) => ( {n.title} @@ -61,7 +61,8 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => { {isTemplate && ( -   + +   Templates @@ -70,14 +71,16 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => { {isDraft && ( -   + +   Drafts )} -   + +   {collection.name} {isNestedDocument && ( @@ -119,7 +122,7 @@ const SmallSlash = styled(GoToIcon)` export const Slash = styled(GoToIcon)` flex-shrink: 0; - fill: ${props => props.theme.divider}; + fill: ${(props) => props.theme.divider}; `; const Overflow = styled(MoreIcon)` @@ -134,7 +137,7 @@ const Overflow = styled(MoreIcon)` `; const Crumb = styled(Link)` - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; font-size: 15px; height: 24px; text-overflow: ellipsis; @@ -149,7 +152,7 @@ const Crumb = styled(Link)` const CollectionName = styled(Link)` display: flex; flex-shrink: 0; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; font-size: 15px; font-weight: 500; white-space: nowrap; diff --git a/app/components/BreadcrumbMenu.js b/app/components/BreadcrumbMenu.js index 18aacf2a..fb372727 100644 --- a/app/components/BreadcrumbMenu.js +++ b/app/components/BreadcrumbMenu.js @@ -14,7 +14,7 @@ export default class BreadcrumbMenu extends React.Component { return ( - {path.map(item => ( + {path.map((item) => ( {item.title} diff --git a/app/components/Button.js b/app/components/Button.js index ef5c0128..de0e5524 100644 --- a/app/components/Button.js +++ b/app/components/Button.js @@ -5,13 +5,13 @@ import { darken, lighten } from "polished"; import { ExpandedIcon } from "outline-icons"; const RealButton = styled.button` - display: ${props => (props.fullwidth ? "block" : "inline-block")}; - width: ${props => (props.fullwidth ? "100%" : "auto")}; + display: ${(props) => (props.fullwidth ? "block" : "inline-block")}; + width: ${(props) => (props.fullwidth ? "100%" : "auto")}; margin: 0; padding: 0; border: 0; - background: ${props => props.theme.buttonBackground}; - color: ${props => props.theme.buttonText}; + background: ${(props) => props.theme.buttonBackground}; + color: ${(props) => props.theme.buttonText}; box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px; border-radius: 4px; font-size: 14px; @@ -24,7 +24,7 @@ const RealButton = styled.button` user-select: none; svg { - fill: ${props => props.iconColor || props.theme.buttonText}; + fill: ${(props) => props.iconColor || props.theme.buttonText}; } &::-moz-focus-inner { @@ -33,12 +33,12 @@ const RealButton = styled.button` } &:hover { - background: ${props => darken(0.05, props.theme.buttonBackground)}; + background: ${(props) => darken(0.05, props.theme.buttonBackground)}; } &:focus { transition-duration: 0.05s; - box-shadow: ${props => lighten(0.4, props.theme.buttonBackground)} 0px 0px + box-shadow: ${(props) => lighten(0.4, props.theme.buttonBackground)} 0px 0px 0px 3px; outline: none; } @@ -46,10 +46,10 @@ const RealButton = styled.button` &:disabled { cursor: default; pointer-events: none; - color: ${props => props.theme.white50}; + color: ${(props) => props.theme.white50}; } - ${props => + ${(props) => props.neutral && ` background: ${props.theme.buttonNeutralBackground}; @@ -80,9 +80,9 @@ const RealButton = styled.button` &:disabled { color: ${props.theme.textTertiary}; } - `} ${props => - props.danger && - ` + `} ${(props) => + props.danger && + ` background: ${props.theme.danger}; color: ${props.theme.white}; @@ -103,20 +103,20 @@ const Label = styled.span` white-space: nowrap; text-overflow: ellipsis; - ${props => props.hasIcon && "padding-left: 4px;"}; + ${(props) => props.hasIcon && "padding-left: 4px;"}; `; export const Inner = styled.span` display: flex; padding: 0 8px; - padding-right: ${props => (props.disclosure ? 2 : 8)}px; - line-height: ${props => (props.hasIcon ? 24 : 32)}px; + padding-right: ${(props) => (props.disclosure ? 2 : 8)}px; + line-height: ${(props) => (props.hasIcon ? 24 : 32)}px; justify-content: center; align-items: center; min-height: 30px; - ${props => props.hasIcon && props.hasText && "padding-left: 4px;"}; - ${props => props.hasIcon && !props.hasText && "padding: 0 4px;"}; + ${(props) => props.hasIcon && props.hasText && "padding-left: 4px;"}; + ${(props) => props.hasIcon && !props.hasText && "padding: 0 4px;"}; `; export type Props = { diff --git a/app/components/Checkbox.js b/app/components/Checkbox.js index 8acbaabc..cbf361c3 100644 --- a/app/components/Checkbox.js +++ b/app/components/Checkbox.js @@ -15,13 +15,13 @@ export type Props = { const LabelText = styled.span` font-weight: 500; - margin-left: ${props => (props.small ? "6px" : "10px")}; - ${props => (props.small ? `color: ${props.theme.textSecondary}` : "")}; + margin-left: ${(props) => (props.small ? "6px" : "10px")}; + ${(props) => (props.small ? `color: ${props.theme.textSecondary}` : "")}; `; const Wrapper = styled.div` padding-bottom: 8px; - ${props => (props.small ? "font-size: 14px" : "")}; + ${(props) => (props.small ? "font-size: 14px" : "")}; `; const Label = styled.label` diff --git a/app/components/Collaborators.js b/app/components/Collaborators.js index ea673d01..627dda16 100644 --- a/app/components/Collaborators.js +++ b/app/components/Collaborators.js @@ -32,27 +32,27 @@ class Collaborators extends React.Component { const documentViews = views.inDocument(document.id); - const presentIds = documentPresence.map(p => p.userId); + const presentIds = documentPresence.map((p) => p.userId); const editingIds = documentPresence - .filter(p => p.isEditing) - .map(p => p.userId); + .filter((p) => p.isEditing) + .map((p) => p.userId); // ensure currently present via websocket are always ordered first const mostRecentViewers = sortBy( documentViews.slice(0, MAX_AVATAR_DISPLAY), - view => { + (view) => { return presentIds.includes(view.user.id); } ); - const viewersKeyedByUserId = keyBy(mostRecentViewers, v => v.user.id); + const viewersKeyedByUserId = keyBy(mostRecentViewers, (v) => v.user.id); const overflow = documentViews.length - mostRecentViewers.length; return ( v.user)} + users={mostRecentViewers.map((v) => v.user)} overflow={overflow} - renderAvatar={user => { + renderAvatar={(user) => { const isPresent = presentIds.includes(user.id); const isEditing = editingIds.includes(user.id); const { lastViewedAt } = viewersKeyedByUserId[user.id]; diff --git a/app/components/DocumentHistory/DocumentHistory.js b/app/components/DocumentHistory/DocumentHistory.js index 283d37d2..18171726 100644 --- a/app/components/DocumentHistory/DocumentHistory.js +++ b/app/components/DocumentHistory/DocumentHistory.js @@ -133,16 +133,16 @@ const Wrapper = styled(Flex)` top: 0; right: 0; z-index: 1; - min-width: ${props => props.theme.sidebarWidth}; + min-width: ${(props) => props.theme.sidebarWidth}; height: 100%; overflow-y: auto; overscroll-behavior: none; `; const Sidebar = styled(Flex)` - background: ${props => props.theme.background}; - min-width: ${props => props.theme.sidebarWidth}; - border-left: 1px solid ${props => props.theme.divider}; + background: ${(props) => props.theme.background}; + min-width: ${(props) => props.theme.sidebarWidth}; + border-left: 1px solid ${(props) => props.theme.divider}; z-index: 1; `; diff --git a/app/components/DocumentHistory/components/Revision.js b/app/components/DocumentHistory/components/Revision.js index da5778c4..b6b7a7e3 100644 --- a/app/components/DocumentHistory/components/Revision.js +++ b/app/components/DocumentHistory/components/Revision.js @@ -66,7 +66,7 @@ const StyledRevisionMenu = styled(RevisionMenu)` `; const StyledNavLink = styled(NavLink)` - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; display: block; padding: 8px 16px; font-size: 15px; diff --git a/app/components/DocumentList.js b/app/components/DocumentList.js index d12e730b..2b1112fc 100644 --- a/app/components/DocumentList.js +++ b/app/components/DocumentList.js @@ -17,7 +17,7 @@ export default function DocumentList({ limit, documents, ...rest }: Props) { mode={ArrowKeyNavigation.mode.VERTICAL} defaultActiveChildIndex={0} > - {items.map(document => ( + {items.map((document) => ( ))} diff --git a/app/components/DocumentPreview/DocumentPreview.js b/app/components/DocumentPreview/DocumentPreview.js index b80c650a..18f58c23 100644 --- a/app/components/DocumentPreview/DocumentPreview.js +++ b/app/components/DocumentPreview/DocumentPreview.js @@ -48,7 +48,7 @@ class DocumentPreview extends React.Component { return tag.replace(/]*>(.*?)<\/b>/gi, "$1"); }; - handleNewFromTemplate = event => { + handleNewFromTemplate = (event) => { event.preventDefault(); event.stopPropagation(); @@ -97,18 +97,14 @@ class DocumentPreview extends React.Component { )} )} - {document.isDraft && - showDraft && ( - - Draft - - )} - {document.isTemplate && - showTemplate && Template} + {document.isDraft && showDraft && ( + + Draft + + )} + {document.isTemplate && showTemplate && ( + Template + )} {document.isTemplate && !document.isArchived && @@ -120,7 +116,8 @@ class DocumentPreview extends React.Component { > New doc - )}  + )} +   @@ -146,7 +143,7 @@ const StyledStar = withTheme(styled(({ solid, theme, ...props }) => ( ))` flex-shrink: 0; - opacity: ${props => (props.solid ? "1 !important" : 0)}; + opacity: ${(props) => (props.solid ? "1 !important" : 0)}; transition: all 100ms ease-in-out; &:hover { @@ -182,7 +179,7 @@ const DocumentLink = styled(Link)` &:hover, &:active, &:focus { - background: ${props => props.theme.listItemHoverBackground}; + background: ${(props) => props.theme.listItemHoverBackground}; outline: none; ${SecondaryActions} { @@ -207,7 +204,7 @@ const Heading = styled.h3` margin-bottom: 0.25em; overflow: hidden; white-space: nowrap; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; `; @@ -225,7 +222,7 @@ const Title = styled(Highlight)` const ResultContext = styled(Highlight)` display: block; - color: ${props => props.theme.textTertiary}; + color: ${(props) => props.theme.textTertiary}; font-size: 14px; margin-top: -0.25em; margin-bottom: 0.25em; diff --git a/app/components/DropToImport.js b/app/components/DropToImport.js index 3621b226..7a4677a1 100644 --- a/app/components/DropToImport.js +++ b/app/components/DropToImport.js @@ -30,12 +30,12 @@ type Props = { export const GlobalStyles = createGlobalStyle` .activeDropZone { border-radius: 4px; - background: ${props => props.theme.slateDark}; - svg { fill: ${props => props.theme.white}; } + background: ${(props) => props.theme.slateDark}; + svg { fill: ${(props) => props.theme.white}; } } .activeDropZone a { - color: ${props => props.theme.white} !important; + color: ${(props) => props.theme.white} !important; } `; diff --git a/app/components/DropdownMenu/DropdownMenu.js b/app/components/DropdownMenu/DropdownMenu.js index cd5fb7df..a7396ae7 100644 --- a/app/components/DropdownMenu/DropdownMenu.js +++ b/app/components/DropdownMenu/DropdownMenu.js @@ -204,7 +204,7 @@ class DropdownMenu extends React.Component { onClick={ typeof children === "function" ? undefined - : ev => { + : (ev) => { ev.stopPropagation(); closePortal(); } @@ -245,24 +245,24 @@ const Position = styled.div` ${({ bottom }) => (bottom !== undefined ? `bottom: ${bottom}px` : "")}; max-height: 75%; z-index: 1000; - transform: ${props => + transform: ${(props) => props.position === "center" ? "translateX(-50%)" : "initial"}; pointer-events: none; `; const Menu = styled.div` animation: ${fadeAndScaleIn} 200ms ease; - transform-origin: ${props => (props.left !== undefined ? "25%" : "75%")} 0; + transform-origin: ${(props) => (props.left !== undefined ? "25%" : "75%")} 0; backdrop-filter: blur(10px); - background: ${props => rgba(props.theme.menuBackground, 0.8)}; - border: ${props => + background: ${(props) => rgba(props.theme.menuBackground, 0.8)}; + border: ${(props) => props.theme.menuBorder ? `1px solid ${props.theme.menuBorder}` : "none"}; border-radius: 2px; padding: 0.5em 0; min-width: 180px; overflow: hidden; overflow-y: auto; - box-shadow: ${props => props.theme.menuShadow}; + box-shadow: ${(props) => props.theme.menuShadow}; pointer-events: all; hr { @@ -278,7 +278,7 @@ export const Header = styled.h3` font-size: 11px; font-weight: 600; text-transform: uppercase; - color: ${props => props.theme.sidebarText}; + color: ${(props) => props.theme.sidebarText}; letter-spacing: 0.04em; margin: 1em 12px 0.5em; `; diff --git a/app/components/DropdownMenu/DropdownMenuItem.js b/app/components/DropdownMenu/DropdownMenuItem.js index a825408a..1e71f8f7 100644 --- a/app/components/DropdownMenu/DropdownMenuItem.js +++ b/app/components/DropdownMenu/DropdownMenuItem.js @@ -29,7 +29,8 @@ const DropdownMenuItem = ({   + /> +   )} {children} @@ -44,7 +45,7 @@ const MenuItem = styled.a` width: 100%; min-height: 32px; - color: ${props => + color: ${(props) => props.disabled ? props.theme.textTertiary : props.theme.textSecondary}; justify-content: left; align-items: center; @@ -57,10 +58,10 @@ const MenuItem = styled.a` } svg { - opacity: ${props => (props.disabled ? ".5" : 1)}; + opacity: ${(props) => (props.disabled ? ".5" : 1)}; } - ${props => + ${(props) => props.disabled ? "pointer-events: none;" : ` diff --git a/app/components/Editor.js b/app/components/Editor.js index f8cc8d23..4938ea27 100644 --- a/app/components/Editor.js +++ b/app/components/Editor.js @@ -81,11 +81,11 @@ class Editor extends React.Component { } const StyledEditor = styled(RichMarkdownEditor)` - flex-grow: ${props => (props.grow ? 1 : 0)}; + flex-grow: ${(props) => (props.grow ? 1 : 0)}; justify-content: start; > div { - transition: ${props => props.theme.backgroundTransition}; + transition: ${(props) => props.theme.backgroundTransition}; } .notice-block.tip, @@ -95,13 +95,13 @@ const StyledEditor = styled(RichMarkdownEditor)` p { a { - color: ${props => props.theme.text}; - border-bottom: 1px solid ${props => lighten(0.5, props.theme.text)}; + color: ${(props) => props.theme.text}; + border-bottom: 1px solid ${(props) => lighten(0.5, props.theme.text)}; text-decoration: none !important; font-weight: 500; &:hover { - border-bottom: 1px solid ${props => props.theme.text}; + border-bottom: 1px solid ${(props) => props.theme.text}; text-decoration: none; } } diff --git a/app/components/Empty.js b/app/components/Empty.js index eed3945e..b7a603c4 100644 --- a/app/components/Empty.js +++ b/app/components/Empty.js @@ -2,7 +2,7 @@ import styled from "styled-components"; const Empty = styled.p` - color: ${props => props.theme.textTertiary}; + color: ${(props) => props.theme.textTertiary}; `; export default Empty; diff --git a/app/components/ErrorBoundary.js b/app/components/ErrorBoundary.js index 77ba0613..3d62ad9b 100644 --- a/app/components/ErrorBoundary.js +++ b/app/components/ErrorBoundary.js @@ -48,9 +48,9 @@ class ErrorBoundary extends React.Component {

Something Unexpected Happened

- Sorry, an unrecoverable error occurred{isReported && - " – our engineers have been notified"}. Please try reloading the - page, it may have been a temporary glitch. + Sorry, an unrecoverable error occurred + {isReported && " – our engineers have been notified"}. Please try + reloading the page, it may have been a temporary glitch. {this.showDetails &&
{this.error.toString()}
}

@@ -73,7 +73,7 @@ class ErrorBoundary extends React.Component { } const Pre = styled.pre` - background: ${props => props.theme.smoke}; + background: ${(props) => props.theme.smoke}; padding: 16px; border-radius: 4px; font-size: 12px; diff --git a/app/components/Facepile.js b/app/components/Facepile.js index d2f1d6e2..da2c6fad 100644 --- a/app/components/Facepile.js +++ b/app/components/Facepile.js @@ -31,7 +31,7 @@ class Facepile extends React.Component { +{overflow} )} - {users.map(user => ( + {users.map((user) => ( {renderAvatar(user)} ))} @@ -56,12 +56,12 @@ const More = styled.div` flex-direction: column; align-items: center; justify-content: center; - min-width: ${props => props.size}px; - height: ${props => props.size}px; + min-width: ${(props) => props.size}px; + height: ${(props) => props.size}px; border-radius: 100%; - background: ${props => props.theme.slate}; - color: ${props => props.theme.text}; - border: 2px solid ${props => props.theme.background}; + background: ${(props) => props.theme.slate}; + color: ${(props) => props.theme.text}; + border: 2px solid ${(props) => props.theme.background}; text-align: center; font-size: 11px; font-weight: 600; diff --git a/app/components/Fade.js b/app/components/Fade.js index bf3dc996..f649bc8f 100644 --- a/app/components/Fade.js +++ b/app/components/Fade.js @@ -3,7 +3,7 @@ import styled from "styled-components"; import { fadeIn } from "shared/styles/animations"; const Fade = styled.span` - animation: ${fadeIn} ${props => props.timing || "250ms"} ease-in-out; + animation: ${fadeIn} ${(props) => props.timing || "250ms"} ease-in-out; `; export default Fade; diff --git a/app/components/GroupListItem.js b/app/components/GroupListItem.js index d1255d11..3b980102 100644 --- a/app/components/GroupListItem.js +++ b/app/components/GroupListItem.js @@ -41,7 +41,7 @@ class GroupListItem extends React.Component { const membershipsInGroup = groupMemberships.inGroup(group.id); const users = membershipsInGroup .slice(0, MAX_AVATAR_DISPLAY) - .map(gm => gm.user); + .map((gm) => gm.user); const overflow = memberCount - users.length; diff --git a/app/components/HelpText.js b/app/components/HelpText.js index af222361..e9f6de97 100644 --- a/app/components/HelpText.js +++ b/app/components/HelpText.js @@ -3,8 +3,8 @@ import styled from "styled-components"; const HelpText = styled.p` margin-top: 0; - color: ${props => props.theme.textSecondary}; - font-size: ${props => (props.small ? "13px" : "inherit")}; + color: ${(props) => props.theme.textSecondary}; + font-size: ${(props) => (props.small ? "13px" : "inherit")}; `; export default HelpText; diff --git a/app/components/Highlight.js b/app/components/Highlight.js index 83d370b5..c31e01c5 100644 --- a/app/components/Highlight.js +++ b/app/components/Highlight.js @@ -38,7 +38,7 @@ function Highlight({ } const Mark = styled.mark` - background: ${props => props.theme.yellow}; + background: ${(props) => props.theme.yellow}; border-radius: 2px; padding: 0 4px; `; diff --git a/app/components/HoverPreview.js b/app/components/HoverPreview.js index b5907b79..5aeb5885 100644 --- a/app/components/HoverPreview.js +++ b/app/components/HoverPreview.js @@ -57,42 +57,39 @@ function HoverPreview({ node, documents, onClose, event }: Props) { } }; - React.useEffect( - () => { - if (slug) { - documents.prefetchDocument(slug, { - prefetch: true, - }); - } + React.useEffect(() => { + if (slug) { + documents.prefetchDocument(slug, { + prefetch: true, + }); + } - startOpenTimer(); + startOpenTimer(); + + if (cardRef.current) { + cardRef.current.addEventListener("mouseenter", stopCloseTimer); + cardRef.current.addEventListener("mouseleave", startCloseTimer); + } + + node.addEventListener("mouseout", startCloseTimer); + node.addEventListener("mouseover", stopCloseTimer); + node.addEventListener("mouseover", startOpenTimer); + + return () => { + node.removeEventListener("mouseout", startCloseTimer); + node.removeEventListener("mouseover", stopCloseTimer); + node.removeEventListener("mouseover", startOpenTimer); if (cardRef.current) { - cardRef.current.addEventListener("mouseenter", stopCloseTimer); - cardRef.current.addEventListener("mouseleave", startCloseTimer); + cardRef.current.removeEventListener("mouseenter", stopCloseTimer); + cardRef.current.removeEventListener("mouseleave", startCloseTimer); } - node.addEventListener("mouseout", startCloseTimer); - node.addEventListener("mouseover", stopCloseTimer); - node.addEventListener("mouseover", startOpenTimer); - - return () => { - node.removeEventListener("mouseout", startCloseTimer); - node.removeEventListener("mouseover", stopCloseTimer); - node.removeEventListener("mouseover", startOpenTimer); - - if (cardRef.current) { - cardRef.current.removeEventListener("mouseenter", stopCloseTimer); - cardRef.current.removeEventListener("mouseleave", startCloseTimer); - } - - if (timerClose.current) { - clearTimeout(timerClose.current); - } - }; - }, - [node] - ); + if (timerClose.current) { + clearTimeout(timerClose.current); + } + }; + }, [node]); const anchorBounds = node.getBoundingClientRect(); const cardBounds = cardRef.current @@ -112,7 +109,7 @@ function HoverPreview({ node, documents, onClose, event }: Props) { >

- {content => + {(content) => isVisible ? ( @@ -156,8 +153,8 @@ const CardContent = styled.div` // &:after — gradient mask for overflow text const Card = styled.div` backdrop-filter: blur(10px); - background: ${props => props.theme.background}; - border: ${props => + background: ${(props) => props.theme.background}; + border: ${(props) => props.theme.menuBorder ? `1px solid ${props.theme.menuBorder}` : "none"}; border-radius: 4px; box-shadow: 0 30px 90px -20px rgba(0, 0, 0, 0.3), @@ -179,15 +176,15 @@ const Card = styled.div` pointer-events: none; background: linear-gradient( 90deg, - ${props => transparentize(1, props.theme.background)} 0%, - ${props => transparentize(1, props.theme.background)} 75%, - ${props => props.theme.background} 90% + ${(props) => transparentize(1, props.theme.background)} 0%, + ${(props) => transparentize(1, props.theme.background)} 75%, + ${(props) => props.theme.background} 90% ); bottom: 0; left: 0; right: 0; height: 1.7em; - border-bottom: 16px solid ${props => props.theme.background}; + border-bottom: 16px solid ${(props) => props.theme.background}; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } @@ -205,7 +202,7 @@ const Position = styled.div` const Pointer = styled.div` top: -22px; - left: ${props => props.offset}px; + left: ${(props) => props.offset}px; width: 22px; height: 22px; position: absolute; @@ -222,14 +219,14 @@ const Pointer = styled.div` &:before { border: 8px solid transparent; - border-bottom-color: ${props => + border-bottom-color: ${(props) => props.theme.menuBorder || "rgba(0, 0, 0, 0.1)"}; right: -1px; } &:after { border: 7px solid transparent; - border-bottom-color: ${props => props.theme.background}; + border-bottom-color: ${(props) => props.theme.background}; } `; diff --git a/app/components/HoverPreviewDocument.js b/app/components/HoverPreviewDocument.js index 8fee8b13..bbee79a8 100644 --- a/app/components/HoverPreviewDocument.js +++ b/app/components/HoverPreviewDocument.js @@ -11,7 +11,7 @@ import DocumentMeta from "components/DocumentMeta"; type Props = { url: string, documents: DocumentsStore, - children: React.Node => React.Node, + children: (React.Node) => React.Node, }; function HoverPreviewDocument({ url, documents, children }: Props) { @@ -45,7 +45,7 @@ const Content = styled(Link)` const Heading = styled.h2` margin: 0 0 0.75em; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; `; export default inject("documents")(observer(HoverPreviewDocument)); diff --git a/app/components/IconPicker.js b/app/components/IconPicker.js index 01a3497c..8294e224 100644 --- a/app/components/IconPicker.js +++ b/app/components/IconPicker.js @@ -166,7 +166,7 @@ class IconPicker extends React.Component { const Component = icons[this.props.icon || "collection"].component; return ( - (this.node = ref)}> + (this.node = ref)}> @@ -179,7 +179,7 @@ class IconPicker extends React.Component { } > - {Object.keys(icons).map(name => { + {Object.keys(icons).map((name) => { const Component = icons[name].component; return ( { + onChange={(color) => this.props.onChange(color.hex, this.props.icon) } colors={colors} @@ -214,7 +214,7 @@ const Icons = styled.div` `; const LabelButton = styled(NudeButton)` - border: 1px solid ${props => props.theme.inputBorder}; + border: 1px solid ${(props) => props.theme.inputBorder}; width: 32px; height: 32px; `; diff --git a/app/components/Input.js b/app/components/Input.js index 566e7a0d..d3ae4e8a 100644 --- a/app/components/Input.js +++ b/app/components/Input.js @@ -9,29 +9,29 @@ import Flex from "components/Flex"; const RealTextarea = styled.textarea` border: 0; flex: 1; - padding: 8px 12px 8px ${props => (props.hasIcon ? "8px" : "12px")}; + padding: 8px 12px 8px ${(props) => (props.hasIcon ? "8px" : "12px")}; outline: none; background: none; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; &:disabled, &::placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } `; const RealInput = styled.input` border: 0; flex: 1; - padding: 8px 12px 8px ${props => (props.hasIcon ? "8px" : "12px")}; + padding: 8px 12px 8px ${(props) => (props.hasIcon ? "8px" : "12px")}; outline: none; background: none; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; height: 30px; &:disabled, &::placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } &::-webkit-search-cancel-button { @@ -40,8 +40,8 @@ const RealInput = styled.input` `; const Wrapper = styled.div` - flex: ${props => (props.flex ? "1" : "0")}; - max-width: ${props => (props.short ? "350px" : "100%")}; + flex: ${(props) => (props.flex ? "1" : "0")}; + max-width: ${(props) => (props.short ? "350px" : "100%")}; min-height: ${({ minHeight }) => (minHeight ? `${minHeight}px` : "0")}; max-height: ${({ maxHeight }) => (maxHeight ? `${maxHeight}px` : "initial")}; `; @@ -56,16 +56,17 @@ const IconWrapper = styled.span` export const Outline = styled(Flex)` display: flex; flex: 1; - margin: ${props => (props.margin !== undefined ? props.margin : "0 0 16px")}; + margin: ${(props) => + props.margin !== undefined ? props.margin : "0 0 16px"}; color: inherit; border-width: 1px; border-style: solid; - border-color: ${props => + border-color: ${(props) => props.hasError ? "red" : props.focused - ? props.theme.inputBorderFocused - : props.theme.inputBorder}; + ? props.theme.inputBorderFocused + : props.theme.inputBorder}; border-radius: 4px; font-weight: normal; align-items: center; @@ -147,7 +148,7 @@ class Input extends React.Component { {icon && {icon}} (this.input = ref)} + ref={(ref) => (this.input = ref)} onBlur={this.handleBlur} onFocus={this.handleFocus} type={type === "textarea" ? undefined : type} diff --git a/app/components/InputSearch.js b/app/components/InputSearch.js index be7053ee..8500403b 100644 --- a/app/components/InputSearch.js +++ b/app/components/InputSearch.js @@ -30,7 +30,7 @@ class InputSearch extends React.Component { } } - handleSearchInput = ev => { + handleSearchInput = (ev) => { ev.preventDefault(); this.props.history.push( searchUrl(ev.target.value, this.props.collectionId) @@ -50,7 +50,7 @@ class InputSearch extends React.Component { return ( (this.input = ref)} + ref={(ref) => (this.input = ref)} type="search" placeholder={placeholder} onInput={this.handleSearchInput} diff --git a/app/components/InputSelect.js b/app/components/InputSelect.js index 726e24b5..f46188d8 100644 --- a/app/components/InputSelect.js +++ b/app/components/InputSelect.js @@ -12,11 +12,11 @@ const Select = styled.select` padding: 8px 12px; outline: none; background: none; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; &:disabled, &::placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } `; @@ -57,7 +57,7 @@ class InputSelect extends React.Component { ))} (this.file = ref)} + ref={(ref) => (this.file = ref)} onChange={this.onFilePicked} - onClick={ev => ev.stopPropagation()} + onClick={(ev) => ev.stopPropagation()} accept="text/markdown, text/plain" /> @@ -153,6 +153,8 @@ class CollectionMenu extends React.Component { } } -export default inject("ui", "documents", "policies")( - withRouter(CollectionMenu) -); +export default inject( + "ui", + "documents", + "policies" +)(withRouter(CollectionMenu)); diff --git a/app/menus/DocumentMenu.js b/app/menus/DocumentMenu.js index cc9e7e8b..2bd8a524 100644 --- a/app/menus/DocumentMenu.js +++ b/app/menus/DocumentMenu.js @@ -219,12 +219,11 @@ class DocumentMenu extends React.Component { New nested document )} - {can.update && - !document.isTemplate && ( - - Create template… - - )} + {can.update && !document.isTemplate && ( + + Create template… + + )} {can.update && ( Edit )} diff --git a/app/menus/NewDocumentMenu.js b/app/menus/NewDocumentMenu.js index 46f23fe0..3587cc30 100644 --- a/app/menus/NewDocumentMenu.js +++ b/app/menus/NewDocumentMenu.js @@ -63,7 +63,7 @@ class NewDocumentMenu extends React.Component { {...rest} >
Choose a collection
- {collections.orderedData.map(collection => { + {collections.orderedData.map((collection) => { const can = policies.abilities(collection.id); return ( @@ -72,7 +72,8 @@ class NewDocumentMenu extends React.Component { onClick={() => this.handleNewDocument(collection.id)} disabled={!can.update} > -  {collection.name} + +  {collection.name} ); })} diff --git a/app/menus/NewTemplateMenu.js b/app/menus/NewTemplateMenu.js index ac26af4a..91a21821 100644 --- a/app/menus/NewTemplateMenu.js +++ b/app/menus/NewTemplateMenu.js @@ -53,7 +53,7 @@ class NewTemplateMenu extends React.Component { {...rest} >
Choose a collection
- {collections.orderedData.map(collection => { + {collections.orderedData.map((collection) => { const can = policies.abilities(collection.id); return ( @@ -62,7 +62,8 @@ class NewTemplateMenu extends React.Component { onClick={() => this.handleNewDocument(collection.id)} disabled={!can.update} > -  {collection.name} + +  {collection.name} ); })} diff --git a/app/menus/TemplatesMenu.js b/app/menus/TemplatesMenu.js index 3234df9e..3025396f 100644 --- a/app/menus/TemplatesMenu.js +++ b/app/menus/TemplatesMenu.js @@ -33,7 +33,7 @@ class TemplatesMenu extends React.Component { } {...rest} > - {templates.map(template => ( + {templates.map((template) => ( document.updateFromTemplate(template)} diff --git a/app/menus/UserMenu.js b/app/menus/UserMenu.js index a3595c88..5b69f59a 100644 --- a/app/menus/UserMenu.js +++ b/app/menus/UserMenu.js @@ -18,9 +18,7 @@ class UserMenu extends React.Component { const { user, users } = this.props; if ( !window.confirm( - `Are you want to make ${ - user.name - } an admin? Admins can modify team and billing information.` + `Are you want to make ${user.name} an admin? Admins can modify team and billing information.` ) ) { return; @@ -72,12 +70,11 @@ class UserMenu extends React.Component { Make {user.name} a member… )} - {!user.isAdmin && - !user.isSuspended && ( - - Make {user.name} an admin… - - )} + {!user.isAdmin && !user.isSuspended && ( + + Make {user.name} an admin… + + )} {!user.lastActiveAt && ( Revoke invite… diff --git a/app/models/BaseModel.js b/app/models/BaseModel.js index 10754755..aad634fe 100644 --- a/app/models/BaseModel.js +++ b/app/models/BaseModel.js @@ -11,7 +11,7 @@ export default class BaseModel { this.store = store; } - save = async params => { + save = async (params) => { this.isSaving = true; try { diff --git a/app/models/Collection.js b/app/models/Collection.js index dab6cbb7..e6bb170c 100644 --- a/app/models/Collection.js +++ b/app/models/Collection.js @@ -37,7 +37,7 @@ export default class Collection extends BaseModel { get documentIds(): string[] { const results = []; const travelDocuments = (documentList, path) => - documentList.forEach(document => { + documentList.forEach((document) => { results.push(document.id); travelDocuments(document.children); }); @@ -49,7 +49,7 @@ export default class Collection extends BaseModel { @action updateDocument(document: Document) { const travelDocuments = (documentList, path) => - documentList.forEach(d => { + documentList.forEach((d) => { if (d.id === document.id) { d.title = document.title; d.url = document.url; @@ -63,8 +63,8 @@ export default class Collection extends BaseModel { getDocumentChildren(documentId: string): NavigationNode[] { let result = []; - const traveler = nodes => { - nodes.forEach(childNode => { + const traveler = (nodes) => { + nodes.forEach((childNode) => { if (childNode.id === documentId) { result = childNode.children; return; @@ -83,7 +83,7 @@ export default class Collection extends BaseModel { pathToDocument(document: Document) { let path; const traveler = (nodes, previousPath) => { - nodes.forEach(childNode => { + nodes.forEach((childNode) => { const newPath = [...previousPath, childNode]; if (childNode.id === document.id) { path = newPath; diff --git a/app/models/Document.js b/app/models/Document.js index 02ecdc2c..5aac074f 100644 --- a/app/models/Document.js +++ b/app/models/Document.js @@ -133,7 +133,7 @@ export default class Document extends BaseModel { }; @action - updateFromJson = data => { + updateFromJson = (data) => { set(this, data); }; @@ -253,11 +253,7 @@ export default class Document extends BaseModel { }; getSummary = (paragraphs: number = 4) => { - const result = this.text - .trim() - .split("\n") - .slice(0, paragraphs) - .join("\n"); + const result = this.text.trim().split("\n").slice(0, paragraphs).join("\n"); return result; }; diff --git a/app/scenes/Collection.js b/app/scenes/Collection.js index 23b18887..cc417a2f 100644 --- a/app/scenes/Collection.js +++ b/app/scenes/Collection.js @@ -171,14 +171,17 @@ class CollectionScene extends React.Component { {collection.name} doesn’t contain any - documents yet.
Get started by creating a new one! + documents yet. +
+ Get started by creating a new one!
-    + +    {collection.private && ( - )} + {canEdit && onRemove && ( + + Remove + + )} + {canEdit && onAdd && ( + + )}
} /> diff --git a/app/scenes/CollectionMembers/components/UserListItem.js b/app/scenes/CollectionMembers/components/UserListItem.js index a0f878ec..b729b5d1 100644 --- a/app/scenes/CollectionMembers/components/UserListItem.js +++ b/app/scenes/CollectionMembers/components/UserListItem.js @@ -37,9 +37,7 @@ const UserListItem = ({ user, onAdd, canEdit }: Props) => { - ) : ( - undefined - ) + ) : undefined } /> ); diff --git a/app/scenes/CollectionNew.js b/app/scenes/CollectionNew.js index 4241447a..07f748e6 100644 --- a/app/scenes/CollectionNew.js +++ b/app/scenes/CollectionNew.js @@ -85,7 +85,7 @@ class CollectionNew extends React.Component { this.hasOpenedIconPicker = true; }; - handleDescriptionChange = getValue => { + handleDescriptionChange = (getValue) => { this.description = getValue(); }; diff --git a/app/scenes/Document/components/Container.js b/app/scenes/Document/components/Container.js index b27159eb..2b708f7d 100644 --- a/app/scenes/Document/components/Container.js +++ b/app/scenes/Document/components/Container.js @@ -4,7 +4,7 @@ import Flex from "components/Flex"; const Container = styled(Flex)` position: relative; - margin-top: ${props => (props.isShare ? "50px" : "0")}; + margin-top: ${(props) => (props.isShare ? "50px" : "0")}; `; export default Container; diff --git a/app/scenes/Document/components/Contents.js b/app/scenes/Document/components/Contents.js index e415e7b7..99c22118 100644 --- a/app/scenes/Document/components/Contents.js +++ b/app/scenes/Document/components/Contents.js @@ -16,26 +16,23 @@ export default function Contents({ headings }: Props) { const [activeSlug, setActiveSlug] = React.useState(); const position = useWindowScrollPosition({ throttle: 100 }); - React.useEffect( - () => { - for (let key = 0; key < headings.length; key++) { - const heading = headings[key]; - const element = window.document.getElementById( - decodeURIComponent(heading.id) - ); + React.useEffect(() => { + for (let key = 0; key < headings.length; key++) { + const heading = headings[key]; + const element = window.document.getElementById( + decodeURIComponent(heading.id) + ); - if (element) { - const bounding = element.getBoundingClientRect(); - if (bounding.top > HEADING_OFFSET) { - const last = headings[Math.max(0, key - 1)]; - setActiveSlug(last.id); - return; - } + if (element) { + const bounding = element.getBoundingClientRect(); + if (bounding.top > HEADING_OFFSET) { + const last = headings[Math.max(0, key - 1)]; + setActiveSlug(last.id); + return; } } - }, - [position, headings] - ); + } + }, [position, headings]); // calculate the minimum heading level and adjust all the headings to make // that the top-most. This prevents the contents from being weirdly indented @@ -52,7 +49,7 @@ export default function Contents({ headings }: Props) { Contents {headings.length ? ( - {headings.map(heading => ( + {headings.map((heading) => ( darken(0.05, props.theme.sidebarBackground)}; + box-shadow: 1px 0 0 ${(props) => darken(0.05, props.theme.sidebarBackground)}; margin-top: 40px; margin-right: 2em; min-height: 40px; @@ -93,7 +90,7 @@ const Heading = styled("h3")` font-size: 11px; font-weight: 600; text-transform: uppercase; - color: ${props => props.theme.sidebarText}; + color: ${(props) => props.theme.sidebarText}; letter-spacing: 0.04em; `; @@ -106,20 +103,20 @@ const Empty = styled(HelpText)` `; const ListItem = styled("li")` - margin-left: ${props => (props.level - 1) * 10}px; + margin-left: ${(props) => (props.level - 1) * 10}px; margin-bottom: 8px; padding-right: 2em; line-height: 1.3; border-right: 3px solid - ${props => (props.active ? props.theme.textSecondary : "transparent")}; + ${(props) => (props.active ? props.theme.textSecondary : "transparent")}; `; const Link = styled("a")` - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; font-size: 14px; &:hover { - color: ${props => props.theme.primary}; + color: ${(props) => props.theme.primary}; } `; diff --git a/app/scenes/Document/components/DataLoader.js b/app/scenes/Document/components/DataLoader.js index 6575d0d2..1c1bc792 100644 --- a/app/scenes/Document/components/DataLoader.js +++ b/app/scenes/Document/components/DataLoader.js @@ -77,7 +77,7 @@ class DataLoader extends React.Component { const results = await this.props.documents.search(term); return results - .filter(result => result.document.title) + .filter((result) => result.document.title) .map((result, index) => ({ title: result.document.title, url: result.document.url, @@ -130,7 +130,7 @@ class DataLoader extends React.Component { return this.goToDocumentCanonical(); } - this.props.shares.fetch(document.id).catch(err => { + this.props.shares.fetch(document.id).catch((err) => { if (!(err instanceof NotFoundError)) { throw err; } @@ -195,7 +195,12 @@ class DataLoader extends React.Component { } export default withRouter( - inject("ui", "auth", "documents", "revisions", "policies", "shares")( - DataLoader - ) + inject( + "ui", + "auth", + "documents", + "revisions", + "policies", + "shares" + )(DataLoader) ); diff --git a/app/scenes/Document/components/Document.js b/app/scenes/Document/components/Document.js index 145ac45e..bf8f36fd 100644 --- a/app/scenes/Document/components/Document.js +++ b/app/scenes/Document/components/Document.js @@ -298,7 +298,7 @@ class DocumentScene extends React.Component { this.isUploading = false; }; - onChange = getEditorText => { + onChange = (getEditorText) => { this.getEditorText = getEditorText; // document change while read only is presumed to be a checkbox edit, @@ -312,7 +312,7 @@ class DocumentScene extends React.Component { } }; - onChangeTitle = event => { + onChangeTitle = (event) => { this.title = event.target.value; this.updateIsDirtyDebounced(); this.autosave(); @@ -409,22 +409,20 @@ class DocumentScene extends React.Component { column auto > - {document.isTemplate && - !readOnly && ( - - You’re editing a template. Highlight some text and use the{" "} - control to add - placeholders that can be filled out when creating new - documents from this template. - - )} - {document.archivedAt && - !document.deletedAt && ( - - Archived by {document.updatedBy.name}{" "} - - )} + {document.isTemplate && !readOnly && ( + + You’re editing a template. Highlight some text and use the{" "} + control to add + placeholders that can be filled out when creating new + documents from this template. + + )} + {document.archivedAt && !document.deletedAt && ( + + Archived by {document.updatedBy.name}{" "} + + )} {document.deletedAt && ( Deleted by {document.updatedBy.name}{" "} @@ -440,15 +438,14 @@ class DocumentScene extends React.Component { )} - {ui.tocVisible && - readOnly && ( - - )} + {ui.tocVisible && readOnly && ( + + )} { + ref={(ref) => { if (ref) { this.editor = ref; } @@ -476,16 +473,14 @@ class DocumentScene extends React.Component { ui={this.props.ui} /> - {readOnly && - !isShare && - !revision && ( - - - - - - - )} + {readOnly && !isShare && !revision && ( + + + + + + + )} @@ -501,12 +496,12 @@ const PlaceholderIcon = styled(InputIcon)` `; const Background = styled(Container)` - background: ${props => props.theme.background}; - transition: ${props => props.theme.backgroundTransition}; + background: ${(props) => props.theme.background}; + transition: ${(props) => props.theme.backgroundTransition}; `; const ReferencesWrapper = styled("div")` - margin-top: ${props => (props.isOnlyTitle ? -45 : 16)}px; + margin-top: ${(props) => (props.isOnlyTitle ? -45 : 16)}px; @media print { display: none; @@ -514,7 +509,7 @@ const ReferencesWrapper = styled("div")` `; const MaxWidth = styled(Flex)` - ${props => + ${(props) => props.archived && `* { color: ${props.theme.textSecondary} !important; } `}; padding: 0 16px; max-width: 100vw; @@ -523,7 +518,7 @@ const MaxWidth = styled(Flex)` ${breakpoint("tablet")` padding: 0 24px; margin: 4px auto 12px; - max-width: calc(48px + ${props => (props.tocVisible ? "64em" : "46em")}); + max-width: calc(48px + ${(props) => (props.tocVisible ? "64em" : "46em")}); `}; ${breakpoint("desktopLarge")` diff --git a/app/scenes/Document/components/DocumentMove.js b/app/scenes/Document/components/DocumentMove.js index 57022869..d4c1e16f 100644 --- a/app/scenes/Document/components/DocumentMove.js +++ b/app/scenes/Document/components/DocumentMove.js @@ -44,7 +44,7 @@ class DocumentMove extends React.Component { // Build index const indexeableDocuments = []; - paths.forEach(path => indexeableDocuments.push(path)); + paths.forEach((path) => indexeableDocuments.push(path)); index.addDocuments(indexeableDocuments); return index; @@ -65,20 +65,20 @@ class DocumentMove extends React.Component { // Exclude root from search results if document is already at the root if (!document.parentDocumentId) { - results = results.filter(result => result.id !== document.collectionId); + results = results.filter((result) => result.id !== document.collectionId); } // Exclude document if on the path to result, or the same result results = results.filter( - result => - !result.path.map(doc => doc.id).includes(document.id) && - last(result.path.map(doc => doc.id)) !== document.parentDocumentId + (result) => + !result.path.map((doc) => doc.id).includes(document.id) && + last(result.path.map((doc) => doc.id)) !== document.parentDocumentId ); return results; } - handleKeyDown = ev => { + handleKeyDown = (ev) => { // Down if (ev.which === 40) { ev.preventDefault(); @@ -98,7 +98,7 @@ class DocumentMove extends React.Component { this.searchTerm = ev.target.value; }; - setFirstDocumentRef = ref => { + setFirstDocumentRef = (ref) => { this.firstDocument = ref; }; @@ -121,50 +121,47 @@ class DocumentMove extends React.Component { return ( - {document && - collections.isLoaded && ( - -
- - {this.renderPathToCurrentDocument()} - -
+ {document && collections.isLoaded && ( + +
+ + {this.renderPathToCurrentDocument()} + +
-
- - - - - - {this.results - .slice(0, MAX_RESULTS) - .map((result, index) => ( - - index === 0 && this.setFirstDocumentRef(ref) - } - onSuccess={this.handleSuccess} - /> - ))} - - -
-
- )} +
+ + + + + + {this.results.slice(0, MAX_RESULTS).map((result, index) => ( + + index === 0 && this.setFirstDocumentRef(ref) + } + onSuccess={this.handleSuccess} + /> + ))} + + +
+
+ )}
); } diff --git a/app/scenes/Document/components/Editor.js b/app/scenes/Document/components/Editor.js index e2f968a5..394e72b9 100644 --- a/app/scenes/Document/components/Editor.js +++ b/app/scenes/Document/components/Editor.js @@ -89,7 +89,7 @@ class DocumentEditor extends React.Component { /> (this.editor = ref)} + ref={(ref) => (this.editor = ref)} autoFocus={title && !this.props.defaultValue} placeholder="…the rest is up to you" onHoverLink={this.handleLinkActive} @@ -98,15 +98,13 @@ class DocumentEditor extends React.Component { {...this.props} /> {!readOnly && } - {this.activeLinkEvent && - !isShare && - readOnly && ( - - )} + {this.activeLinkEvent && !isShare && readOnly && ( + + )} ); } @@ -117,10 +115,10 @@ const Title = styled(Textarea)` line-height: 1.25; margin-top: 1em; margin-bottom: 0.5em; - text: ${props => props.theme.text}; - background: ${props => props.theme.background}; - transition: ${props => props.theme.backgroundTransition}; - color: ${props => props.theme.text}; + text: ${(props) => props.theme.text}; + background: ${(props) => props.theme.background}; + transition: ${(props) => props.theme.backgroundTransition}; + color: ${(props) => props.theme.text}; font-size: 2.25em; font-weight: 500; outline: none; @@ -129,7 +127,7 @@ const Title = styled(Textarea)` resize: none; &::placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } `; diff --git a/app/scenes/Document/components/Header.js b/app/scenes/Document/components/Header.js index 9278283d..529a2a87 100644 --- a/app/scenes/Document/components/Header.js +++ b/app/scenes/Document/components/Header.js @@ -194,12 +194,11 @@ class Header extends React.Component { )} - {isSaving && - !isPublishing && ( - - Saving… - - )} + {isSaving && !isPublishing && ( + + Saving… + + )}   { currentUserId={auth.user ? auth.user.id : undefined} /> - {isEditing && - !isTemplate && - isNew && ( - - - - )} - {!isEditing && - canShareDocuments && ( - - - Anyone with the link
can view this document - - ) : ( - "" - ) - } - delay={500} - placement="bottom" + {isEditing && !isTemplate && isNew && ( + + + + )} + {!isEditing && canShareDocuments && ( + + + Anyone with the link
+ can view this document + + ) : ( + "" + ) + } + delay={500} + placement="bottom" + > + -
-
- )} + Share + +
+
+ )} {isEditing && ( @@ -282,62 +279,56 @@ class Header extends React.Component { )} - {canEdit && - can.createChildDocument && ( - - - - - } - /> - - )} - {canEdit && - isTemplate && - !isDraft && - !isRevision && ( - + {canEdit && can.createChildDocument && ( + + + + + } + /> + + )} + {canEdit && isTemplate && !isDraft && !isRevision && ( + + + + )} + {can.update && isDraft && !isRevision && ( + + - - )} - {can.update && - isDraft && - !isRevision && ( - - - - - - )} + + + )} {!isEditing && ( @@ -358,7 +349,7 @@ class Header extends React.Component { } const Status = styled.div` - color: ${props => props.theme.slate}; + color: ${(props) => props.theme.slate}; `; const BreadcrumbAndContents = styled(Flex)` @@ -386,9 +377,9 @@ const Actions = styled(Flex)` right: 0; left: 0; z-index: 2; - background: ${props => transparentize(0.2, props.theme.background)}; + background: ${(props) => transparentize(0.2, props.theme.background)}; box-shadow: 0 1px 0 - ${props => + ${(props) => props.isCompact ? darken(0.05, props.theme.sidebarBackground) : "transparent"}; @@ -402,7 +393,7 @@ const Actions = styled(Flex)` } ${breakpoint("tablet")` - padding: ${props => (props.isCompact ? "12px" : `24px 24px 0`)}; + padding: ${(props) => (props.isCompact ? "12px" : `24px 24px 0`)}; `}; `; diff --git a/app/scenes/Document/components/ReferenceListItem.js b/app/scenes/Document/components/ReferenceListItem.js index 933248af..043dd07e 100644 --- a/app/scenes/Document/components/ReferenceListItem.js +++ b/app/scenes/Document/components/ReferenceListItem.js @@ -26,7 +26,7 @@ const DocumentLink = styled(Link)` &:hover, &:active, &:focus { - background: ${props => props.theme.listItemHoverBackground}; + background: ${(props) => props.theme.listItemHoverBackground}; outline: none; } `; @@ -39,7 +39,7 @@ const Title = styled.h3` margin-top: 0; margin-bottom: 0.25em; white-space: nowrap; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; `; diff --git a/app/scenes/Document/components/References.js b/app/scenes/Document/components/References.js index 3e6f7324..92d72f89 100644 --- a/app/scenes/Document/components/References.js +++ b/app/scenes/Document/components/References.js @@ -52,7 +52,7 @@ class References extends React.Component { )} {isBacklinksTab - ? backlinks.map(backlinkedDocument => ( + ? backlinks.map((backlinkedDocument) => ( { } /> )) - : children.map(node => { + : children.map((node) => { // If we have the document in the store already then use it to get the extra // contextual info, otherwise the collection node will do (only has title and id) const document = documents.get(node.id); diff --git a/app/scenes/DocumentDelete.js b/app/scenes/DocumentDelete.js index 203bf949..9c23d56d 100644 --- a/app/scenes/DocumentDelete.js +++ b/app/scenes/DocumentDelete.js @@ -51,17 +51,15 @@ class DocumentDelete extends React.Component { Are you sure about that? Deleting the{" "} {document.titleWithDefault} {document.noun} will - delete all of its history{document.isTemplate - ? "" - : ", and any nested documents"}. + delete all of its history + {document.isTemplate ? "" : ", and any nested documents"}. - {!document.isDraft && - !document.isArchived && ( - - If you’d like the option of referencing or restoring this{" "} - {document.noun} in the future, consider archiving it instead. - - )} + {!document.isDraft && !document.isArchived && ( + + If you’d like the option of referencing or restoring this{" "} + {document.noun} in the future, consider archiving it instead. + + )} diff --git a/app/scenes/DocumentShare.js b/app/scenes/DocumentShare.js index ab2f22df..215c1e2c 100644 --- a/app/scenes/DocumentShare.js +++ b/app/scenes/DocumentShare.js @@ -35,7 +35,7 @@ class DocumentShare extends React.Component { clearTimeout(this.timeout); } - handlePublishedChange = async event => { + handlePublishedChange = async (event) => { const { document, shares } = this.props; const share = shares.getByDocumentId(document.id); invariant(share, "Share must exist"); @@ -76,7 +76,8 @@ class DocumentShare extends React.Component { : "It is only viewable by those that already have access to the collection."}{" "} Manage all share links - . + + . {canPublish && ( @@ -112,7 +113,9 @@ class DocumentShare extends React.Component { -     + +     + Preview
diff --git a/app/scenes/Error404.js b/app/scenes/Error404.js index f5d5f988..83378a5d 100644 --- a/app/scenes/Error404.js +++ b/app/scenes/Error404.js @@ -10,9 +10,8 @@ const Error404 = () => {

Not found

- We were unable to find the page you’re looking for. Go to the  - homepage - ? + We were unable to find the page you’re looking for. Go to the  + homepage? ); diff --git a/app/scenes/GroupMembers/AddPeopleToGroup.js b/app/scenes/GroupMembers/AddPeopleToGroup.js index f0f36a0f..d879d5a1 100644 --- a/app/scenes/GroupMembers/AddPeopleToGroup.js +++ b/app/scenes/GroupMembers/AddPeopleToGroup.js @@ -50,7 +50,7 @@ class AddPeopleToGroup extends React.Component { }); }, 250); - handleAddUser = async user => { + handleAddUser = async (user) => { try { await this.props.groupMemberships.create({ groupId: this.props.group.id, @@ -74,7 +74,8 @@ class AddPeopleToGroup extends React.Component { someone who’s not yet on the team yet?{" "} Invite them to {team.name} - . + + . { } items={users.notInGroup(group.id, this.query)} fetch={this.query ? undefined : users.fetchPage} - renderItem={item => ( + renderItem={(item) => ( { } } -export default inject("auth", "users", "groupMemberships", "ui")( - AddPeopleToGroup -); +export default inject( + "auth", + "users", + "groupMemberships", + "ui" +)(AddPeopleToGroup); diff --git a/app/scenes/GroupMembers/GroupMembers.js b/app/scenes/GroupMembers/GroupMembers.js index 1b052601..0bdaf77d 100644 --- a/app/scenes/GroupMembers/GroupMembers.js +++ b/app/scenes/GroupMembers/GroupMembers.js @@ -40,7 +40,7 @@ class GroupMembers extends React.Component { this.addModalOpen = false; }; - handleRemoveUser = async user => { + handleRemoveUser = async (user) => { try { await this.props.groupMemberships.delete({ groupId: this.props.group.id, @@ -91,7 +91,7 @@ class GroupMembers extends React.Component { fetch={groupMemberships.fetchPage} options={{ id: group.id }} empty={This group has no members.} - renderItem={item => ( + renderItem={(item) => ( { } } -export default inject("auth", "users", "policies", "groupMemberships", "ui")( - GroupMembers -); +export default inject( + "auth", + "users", + "policies", + "groupMemberships", + "ui" +)(GroupMembers); diff --git a/app/scenes/GroupMembers/components/UserListItem.js b/app/scenes/GroupMembers/components/UserListItem.js index 7dd0b73f..2b371970 100644 --- a/app/scenes/GroupMembers/components/UserListItem.js +++ b/app/scenes/GroupMembers/components/UserListItem.js @@ -37,9 +37,7 @@ const UserListItem = ({ user, onAdd, canEdit }: Props) => { - ) : ( - undefined - ) + ) : undefined } /> ); diff --git a/app/scenes/Invite.js b/app/scenes/Invite.js index e9ee4464..a81d2cb1 100644 --- a/app/scenes/Invite.js +++ b/app/scenes/Invite.js @@ -128,7 +128,8 @@ class Invite extends React.Component { label="Want a link to share directly with your team?" readOnly flex - />   + /> +    ) : ( - )}   + )} +    @@ -319,7 +322,7 @@ class Search extends React.Component { return ( index === 0 && this.setFirstDocumentRef(ref)} + ref={(ref) => index === 0 && this.setFirstDocumentRef(ref)} key={document.id} document={document} highlight={this.query} @@ -361,14 +364,14 @@ const Container = styled(CenteredContent)` const ResultsWrapper = styled(Flex)` position: absolute; transition: all 300ms cubic-bezier(0.65, 0.05, 0.36, 1); - top: ${props => (props.pinToTop ? "0%" : "50%")}; - margin-top: ${props => (props.pinToTop ? "40px" : "-75px")}; + top: ${(props) => (props.pinToTop ? "0%" : "50%")}; + margin-top: ${(props) => (props.pinToTop ? "40px" : "-75px")}; width: 100%; `; const ResultList = styled(Flex)` margin-bottom: 150px; - opacity: ${props => (props.visible ? "1" : "0")}; + opacity: ${(props) => (props.visible ? "1" : "0")}; transition: all 400ms cubic-bezier(0.65, 0.05, 0.36, 1); `; diff --git a/app/scenes/Search/components/CollectionFilter.js b/app/scenes/Search/components/CollectionFilter.js index 4191452e..524188e2 100644 --- a/app/scenes/Search/components/CollectionFilter.js +++ b/app/scenes/Search/components/CollectionFilter.js @@ -19,7 +19,7 @@ type Props = { class CollectionFilter extends React.Component { render() { const { onSelect, collectionId, collections } = this.props; - const collectionOptions = collections.orderedData.map(user => ({ + const collectionOptions = collections.orderedData.map((user) => ({ key: user.id, label: user.name, })); diff --git a/app/scenes/Search/components/FilterOption.js b/app/scenes/Search/components/FilterOption.js index 898b4df9..5ad5b688 100644 --- a/app/scenes/Search/components/FilterOption.js +++ b/app/scenes/Search/components/FilterOption.js @@ -31,7 +31,7 @@ const FilterOption = ({ label, note, onSelect, active }: Props) => { const Checkmark = styled(CheckmarkIcon)` flex-shrink: 0; padding-left: 4px; - fill: ${props => props.theme.text}; + fill: ${(props) => props.theme.text}; `; const Anchor = styled("a")` @@ -39,7 +39,7 @@ const Anchor = styled("a")` flex-direction: column; font-size: 15px; padding: 4px 8px; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; min-height: 32px; ${HelpText} { @@ -48,13 +48,13 @@ const Anchor = styled("a")` } &:hover { - background: ${props => props.theme.listItemHoverBackground}; + background: ${(props) => props.theme.listItemHoverBackground}; } `; const ListItem = styled("li")` list-style: none; - font-weight: ${props => (props.active ? "600" : "normal")}; + font-weight: ${(props) => (props.active ? "600" : "normal")}; `; export default FilterOption; diff --git a/app/scenes/Search/components/FilterOptions.js b/app/scenes/Search/components/FilterOptions.js index 7c45d7ab..a523de68 100644 --- a/app/scenes/Search/components/FilterOptions.js +++ b/app/scenes/Search/components/FilterOptions.js @@ -32,7 +32,7 @@ const FilterOptions = ({ {({ closeMenu }) => ( - {options.map(option => ( + {options.map((option) => ( { @@ -73,7 +73,7 @@ const StyledButton = styled(Button)` } `; -const SearchFilter = props => { +const SearchFilter = (props) => { return ( void, + onChange: (string) => void, defaultValue?: string, theme: Object, }; @@ -40,7 +40,7 @@ class SearchField extends React.Component { /> (this.input = ref)} + ref={(ref) => (this.input = ref)} onChange={this.handleChange} spellCheck="false" placeholder="Search…" @@ -64,26 +64,26 @@ const StyledInput = styled.input` font-weight: 400; outline: none; border: 0; - background: ${props => props.theme.sidebarBackground}; - transition: ${props => props.theme.backgroundTransition}; + background: ${(props) => props.theme.sidebarBackground}; + transition: ${(props) => props.theme.backgroundTransition}; border-radius: 4px; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; ::-webkit-search-cancel-button { -webkit-appearance: none; } ::-webkit-input-placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } :-moz-placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } ::-moz-placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } :-ms-input-placeholder { - color: ${props => props.theme.placeholder}; + color: ${(props) => props.theme.placeholder}; } `; diff --git a/app/scenes/Search/components/UserFilter.js b/app/scenes/Search/components/UserFilter.js index 9c293165..9cc6c1e5 100644 --- a/app/scenes/Search/components/UserFilter.js +++ b/app/scenes/Search/components/UserFilter.js @@ -23,7 +23,7 @@ class UserFilter extends React.Component { render() { const { onSelect, userId, users } = this.props; - const userOptions = users.all.map(user => ({ + const userOptions = users.all.map((user) => ({ key: user.id, label: user.name, })); diff --git a/app/scenes/Settings/Details.js b/app/scenes/Settings/Details.js index fdc63bd8..fd81367c 100644 --- a/app/scenes/Settings/Details.js +++ b/app/scenes/Settings/Details.js @@ -106,7 +106,7 @@ class Details extends React.Component { -
(this.form = ref)}> + (this.form = ref)}> props.theme.white}; + background: ${(props) => props.theme.white}; div div { ${avatarStyles}; @@ -176,7 +176,7 @@ const AvatarContainer = styled(Flex)` &:hover div { opacity: 1; background: rgba(0, 0, 0, 0.75); - color: ${props => props.theme.white}; + color: ${(props) => props.theme.white}; } `; diff --git a/app/scenes/Settings/Events.js b/app/scenes/Settings/Events.js index b58a8184..b3d5c1f9 100644 --- a/app/scenes/Settings/Events.js +++ b/app/scenes/Settings/Events.js @@ -85,7 +85,9 @@ class Events extends React.Component { ) : ( - {events.orderedData.map(event => )} + {events.orderedData.map((event) => ( + + ))} {this.allowLoadMore && ( )} diff --git a/app/scenes/Settings/Export.js b/app/scenes/Settings/Export.js index 2efecf09..80739dd8 100644 --- a/app/scenes/Settings/Export.js +++ b/app/scenes/Settings/Export.js @@ -61,7 +61,9 @@ class Export extends React.Component { > {this.isExporting ? "Export Requested" - : this.isLoading ? "Requesting Export…" : "Export All Data"} + : this.isLoading + ? "Requesting Export…" + : "Export All Data"} ); diff --git a/app/scenes/Settings/Groups.js b/app/scenes/Settings/Groups.js index 2de85319..32ef87c9 100644 --- a/app/scenes/Settings/Groups.js +++ b/app/scenes/Settings/Groups.js @@ -85,7 +85,7 @@ class Groups extends React.Component { - {groups.orderedData.map(group => ( + {groups.orderedData.map((group) => ( { this.inviteModalOpen = false; }; - fetchPage = params => { + fetchPage = (params) => { return this.props.users.fetchPage({ ...params, includeSuspended: true }); }; @@ -116,7 +116,7 @@ class People extends React.Component { items={users} empty={No people to see here.} fetch={this.fetchPage} - renderItem={item => ( + renderItem={(item) => ( { - (this.form = ref)}> + (this.form = ref)}> { } const DangerZone = styled.div` - background: ${props => props.theme.background}; - transition: ${props => props.theme.backgroundTransition}; + background: ${(props) => props.theme.background}; + transition: ${(props) => props.theme.backgroundTransition}; position: absolute; bottom: 16px; `; @@ -162,7 +162,7 @@ const AvatarContainer = styled(Flex)` &:hover div { opacity: 1; background: rgba(0, 0, 0, 0.75); - color: ${props => props.theme.white}; + color: ${(props) => props.theme.white}; } `; diff --git a/app/scenes/Settings/Shares.js b/app/scenes/Settings/Shares.js index 5f1371fd..e1a3a9d2 100644 --- a/app/scenes/Settings/Shares.js +++ b/app/scenes/Settings/Shares.js @@ -39,20 +39,19 @@ class Shares extends React.Component { public link can access a read-only version of the document until the link has been revoked. - {user && - user.isAdmin && ( - - {!canShareDocuments && ( - Sharing is currently disabled. - )}{" "} - You can turn {canShareDocuments ? "off" : "on"} public document - sharing in security settings. - - )} + {user && user.isAdmin && ( + + {!canShareDocuments && ( + Sharing is currently disabled. + )}{" "} + You can turn {canShareDocuments ? "off" : "on"} public document + sharing in security settings. + + )} Shared Documents {hasSharedDocuments ? ( - {shares.published.map(share => ( + {shares.published.map((share) => ( ))} diff --git a/app/scenes/Settings/Slack.js b/app/scenes/Settings/Slack.js index 4f2fe4d1..5aa3e0e3 100644 --- a/app/scenes/Settings/Slack.js +++ b/app/scenes/Settings/Slack.js @@ -83,7 +83,7 @@ class Slack extends React.Component { - {collections.orderedData.map(collection => { + {collections.orderedData.map((collection) => { const integration = find(integrations.slackIntegrations, { collectionId: collection.id, }); diff --git a/app/scenes/Settings/Tokens.js b/app/scenes/Settings/Tokens.js index 84efd58d..73b80c57 100644 --- a/app/scenes/Settings/Tokens.js +++ b/app/scenes/Settings/Tokens.js @@ -48,12 +48,13 @@ class Tokens extends React.Component { with the API. For more details about the API take a look at the{" "} developer documentation - . + + . {hasApiKeys && ( - {apiKeys.orderedData.map(token => ( + {apiKeys.orderedData.map((token) => ( { +const description = (event) => { switch (event.name) { case "api_keys.create": return ( @@ -61,11 +61,11 @@ const description = event => { case "users.invite": return ( - {capitalize(event.verbPastTense)} {event.data.name} ( + {capitalize(event.verbPastTense)} {event.data.name} ( + {event.data.email || ""} - ) + + ) ); case "users.suspend": @@ -220,16 +220,14 @@ const EventListItem = ({ event }: Props) => { {event.actorIpAddress} - ) : ( - undefined - ) + ) : undefined } /> ); }; const IP = styled("span")` - color: ${props => props.theme.textTertiary}; + color: ${(props) => props.theme.textTertiary}; font-size: 12px; `; diff --git a/app/scenes/Settings/components/ImageUpload.js b/app/scenes/Settings/components/ImageUpload.js index 423eee56..9f42337d 100644 --- a/app/scenes/Settings/components/ImageUpload.js +++ b/app/scenes/Settings/components/ImageUpload.js @@ -14,8 +14,8 @@ import UiStore from "stores/UiStore"; type Props = { children?: React.Node, - onSuccess: string => void | Promise, - onError: string => void, + onSuccess: (string) => void | Promise, + onError: (string) => void, submitText: string, borderRadius: number, ui: UiStore, @@ -85,7 +85,7 @@ class ImageUpload extends React.Component { {this.isUploading && } (this.avatarEditorRef = ref)} + ref={(ref) => (this.avatarEditorRef = ref)} image={this.file} width={250} height={250} @@ -154,7 +154,7 @@ const RangeInput = styled.input` height: 16px; width: 16px; border-radius: 50%; - background: ${props => props.theme.text}; + background: ${(props) => props.theme.text}; cursor: pointer; } diff --git a/app/scenes/UserProfile.js b/app/scenes/UserProfile.js index fcbae252..01a15499 100644 --- a/app/scenes/UserProfile.js +++ b/app/scenes/UserProfile.js @@ -47,7 +47,9 @@ class UserProfile extends React.Component { {isCurrentUser ? "You joined" - : user.lastActiveAt ? "Joined" : "Invited"}{" "} + : user.lastActiveAt + ? "Joined" + : "Invited"}{" "} {distanceInWordsToNow(new Date(user.createdAt))} ago. {user.isAdmin && ( Admin diff --git a/app/stores/AuthStore.js b/app/stores/AuthStore.js index abcaa973..bbd15839 100644 --- a/app/stores/AuthStore.js +++ b/app/stores/AuthStore.js @@ -63,9 +63,9 @@ export default class AuthStore { }); } - addPolicies = policies => { + addPolicies = (policies) => { if (policies) { - policies.forEach(policy => this.rootStore.policies.add(policy)); + policies.forEach((policy) => this.rootStore.policies.add(policy)); } }; @@ -102,7 +102,7 @@ export default class AuthStore { this.team = new Team(team); if (window.Sentry) { - window.Sentry.configureScope(function(scope) { + window.Sentry.configureScope(function (scope) { scope.setUser({ id: user.id }); scope.setExtra("team", team.name); scope.setExtra("teamId", team.id); diff --git a/app/stores/BaseStore.js b/app/stores/BaseStore.js index 36dd6c9e..034d9e6c 100644 --- a/app/stores/BaseStore.js +++ b/app/stores/BaseStore.js @@ -37,9 +37,9 @@ export default class BaseStore { this.data.clear(); } - addPolicies = policies => { + addPolicies = (policies) => { if (policies) { - policies.forEach(policy => this.rootStore.policies.add(policy)); + policies.forEach((policy) => this.rootStore.policies.add(policy)); } }; diff --git a/app/stores/CollectionGroupMembershipsStore.js b/app/stores/CollectionGroupMembershipsStore.js index b55851ed..cde26298 100644 --- a/app/stores/CollectionGroupMembershipsStore.js +++ b/app/stores/CollectionGroupMembershipsStore.js @@ -7,9 +7,7 @@ import RootStore from "./RootStore"; import CollectionGroupMembership from "models/CollectionGroupMembership"; import type { PaginationParams } from "types"; -export default class CollectionGroupMembershipsStore extends BaseStore< - CollectionGroupMembership -> { +export default class CollectionGroupMembershipsStore extends BaseStore { actions = ["create", "delete"]; constructor(rootStore: RootStore) { diff --git a/app/stores/CollectionsStore.js b/app/stores/CollectionsStore.js index 9684047a..223b36b6 100644 --- a/app/stores/CollectionsStore.js +++ b/app/stores/CollectionsStore.js @@ -36,18 +36,18 @@ export default class CollectionsStore extends BaseStore { get orderedData(): Collection[] { return filter( naturalSort(Array.from(this.data.values()), "name"), - d => !d.deletedAt + (d) => !d.deletedAt ); } @computed get public(): Collection[] { - return this.orderedData.filter(collection => !collection.private); + return this.orderedData.filter((collection) => !collection.private); } @computed get private(): Collection[] { - return this.orderedData.filter(collection => collection.private); + return this.orderedData.filter((collection) => collection.private); } /** @@ -57,7 +57,7 @@ export default class CollectionsStore extends BaseStore { get pathsToDocuments(): DocumentPath[] { let results = []; const travelDocuments = (documentList, collectionId, path) => - documentList.forEach(document => { + documentList.forEach((document) => { const { id, title, url } = document; const node = { id, collectionId, title, url, type: "document" }; results.push(concat(path, node)); @@ -65,7 +65,7 @@ export default class CollectionsStore extends BaseStore { }); if (this.isLoaded) { - this.data.forEach(collection => { + this.data.forEach((collection) => { const { id, name, url } = collection; const node = { id, @@ -79,7 +79,7 @@ export default class CollectionsStore extends BaseStore { }); } - return results.map(result => { + return results.map((result) => { const tail = last(result); return { ...tail, @@ -89,11 +89,11 @@ export default class CollectionsStore extends BaseStore { } getPathForDocument(documentId: string): ?DocumentPath { - return this.pathsToDocuments.find(path => path.id === documentId); + return this.pathsToDocuments.find((path) => path.id === documentId); } titleForDocument(documentUrl: string): ?string { - const path = this.pathsToDocuments.find(path => path.url === documentUrl); + const path = this.pathsToDocuments.find((path) => path.url === documentUrl); if (path) return path.title; } diff --git a/app/stores/DocumentPresenceStore.js b/app/stores/DocumentPresenceStore.js index 6877a909..d0513eb3 100644 --- a/app/stores/DocumentPresenceStore.js +++ b/app/stores/DocumentPresenceStore.js @@ -13,7 +13,7 @@ export default class PresenceStore { @action init(documentId: string, userIds: string[], editingIds: string[]) { this.data.set(documentId, new Map()); - userIds.forEach(userId => + userIds.forEach((userId) => this.touch(documentId, userId, editingIds.includes(userId)) ); } diff --git a/app/stores/DocumentsStore.js b/app/stores/DocumentsStore.js index c70d8ba9..27ab3ca7 100644 --- a/app/stores/DocumentsStore.js +++ b/app/stores/DocumentsStore.js @@ -34,14 +34,14 @@ export default class DocumentsStore extends BaseStore { get all(): Document[] { return filter( this.orderedData, - d => !d.archivedAt && !d.deletedAt && !d.template + (d) => !d.archivedAt && !d.deletedAt && !d.template ); } @computed get recentlyViewed(): Document[] { return orderBy( - compact(this.recentlyViewedIds.map(id => this.data.get(id))), + compact(this.recentlyViewedIds.map((id) => this.data.get(id))), "updatedAt", "desc" ); @@ -56,7 +56,7 @@ export default class DocumentsStore extends BaseStore { return orderBy( filter( this.orderedData, - d => !d.archivedAt && !d.deletedAt && d.template + (d) => !d.archivedAt && !d.deletedAt && d.template ), "updatedAt", "desc" @@ -65,21 +65,24 @@ export default class DocumentsStore extends BaseStore { createdByUser(userId: string): Document[] { return orderBy( - filter(this.all, d => d.createdBy.id === userId), + filter(this.all, (d) => d.createdBy.id === userId), "updatedAt", "desc" ); } inCollection(collectionId: string): Document[] { - return filter(this.all, document => document.collectionId === collectionId); + return filter( + this.all, + (document) => document.collectionId === collectionId + ); } templatesInCollection(collectionId: string): Document[] { return orderBy( filter( this.orderedData, - d => + (d) => !d.archivedAt && !d.deletedAt && d.template === true && @@ -93,14 +96,14 @@ export default class DocumentsStore extends BaseStore { pinnedInCollection(collectionId: string): Document[] { return filter( this.recentlyUpdatedInCollection(collectionId), - document => document.pinned + (document) => document.pinned ); } publishedInCollection(collectionId: string): Document[] { return filter( this.all, - document => + (document) => document.collectionId === collectionId && !!document.publishedAt ); } @@ -130,14 +133,18 @@ export default class DocumentsStore extends BaseStore { } get starred(): Document[] { - return orderBy(filter(this.all, d => d.isStarred), "updatedAt", "desc"); + return orderBy( + filter(this.all, (d) => d.isStarred), + "updatedAt", + "desc" + ); } @computed get archived(): Document[] { return filter( orderBy(this.orderedData, "archivedAt", "desc"), - d => d.archivedAt && !d.deletedAt + (d) => d.archivedAt && !d.deletedAt ); } @@ -145,7 +152,7 @@ export default class DocumentsStore extends BaseStore { get deleted(): Document[] { return filter( orderBy(this.orderedData, "deletedAt", "desc"), - d => d.deletedAt + (d) => d.deletedAt ); } @@ -163,7 +170,7 @@ export default class DocumentsStore extends BaseStore { get drafts(): Document[] { return filter( orderBy(this.all, "updatedAt", "desc"), - doc => !doc.publishedAt + (doc) => !doc.publishedAt ); } @@ -183,14 +190,17 @@ export default class DocumentsStore extends BaseStore { const { data } = res; runInAction("DocumentsStore#fetchBacklinks", () => { data.forEach(this.add); - this.backlinks.set(documentId, data.map(doc => doc.id)); + this.backlinks.set( + documentId, + data.map((doc) => doc.id) + ); }); }; getBacklinedDocuments(documentId: string): Document[] { const documentIds = this.backlinks.get(documentId) || []; return orderBy( - compact(documentIds.map(id => this.data.get(id))), + compact(documentIds.map((id) => this.data.get(id))), "updatedAt", "desc" ); @@ -317,7 +327,7 @@ export default class DocumentsStore extends BaseStore { options: PaginationParams = {} ): Promise => { // $FlowFixMe - const compactedOptions = omitBy(options, o => !o); + const compactedOptions = omitBy(options, (o) => !o); const res = await client.get("/documents.search", { ...compactedOptions, query, @@ -325,13 +335,13 @@ export default class DocumentsStore extends BaseStore { invariant(res && res.data, "Search response should be available"); // add the documents and associated policies to the store - res.data.forEach(result => this.add(result.document)); + res.data.forEach((result) => this.add(result.document)); this.addPolicies(res.policies); // store a reference to the document model in the search cache instead // of the original result from the API. const results: SearchResult[] = compact( - res.data.map(result => { + res.data.map((result) => { const document = this.data.get(result.document.id); if (!document) return null; @@ -462,8 +472,8 @@ export default class DocumentsStore extends BaseStore { @action removeCollectionDocuments(collectionId: string) { const documents = this.inCollection(collectionId); - const documentIds = documents.map(doc => doc.id); - documentIds.forEach(id => this.remove(id)); + const documentIds = documents.map((doc) => doc.id); + documentIds.forEach((id) => this.remove(id)); } @action @@ -554,7 +564,7 @@ export default class DocumentsStore extends BaseStore { }; getByUrl = (url: string = ""): ?Document => { - return find(this.orderedData, doc => url.endsWith(doc.urlId)); + return find(this.orderedData, (doc) => url.endsWith(doc.urlId)); }; getCollectionForDocument(document: Document) { diff --git a/app/stores/GroupMembershipsStore.js b/app/stores/GroupMembershipsStore.js index ee3c794d..e57a4ef4 100644 --- a/app/stores/GroupMembershipsStore.js +++ b/app/stores/GroupMembershipsStore.js @@ -74,6 +74,6 @@ export default class GroupMembershipsStore extends BaseStore { }; inGroup = (groupId: string) => { - return filter(this.orderedData, member => member.groupId === groupId); + return filter(this.orderedData, (member) => member.groupId === groupId); }; } diff --git a/app/stores/GroupsStore.js b/app/stores/GroupsStore.js index 7d97c7e6..103b667a 100644 --- a/app/stores/GroupsStore.js +++ b/app/stores/GroupsStore.js @@ -43,10 +43,10 @@ export default class GroupsStore extends BaseStore { inCollection = (collectionId: string, query: string) => { const memberships = filter( this.rootStore.collectionGroupMemberships.orderedData, - member => member.collectionId === collectionId + (member) => member.collectionId === collectionId ); - const groupIds = memberships.map(member => member.groupId); - const groups = filter(this.orderedData, group => + const groupIds = memberships.map((member) => member.groupId); + const groups = filter(this.orderedData, (group) => groupIds.includes(group.id) ); @@ -57,12 +57,12 @@ export default class GroupsStore extends BaseStore { notInCollection = (collectionId: string, query: string = "") => { const memberships = filter( this.rootStore.collectionGroupMemberships.orderedData, - member => member.collectionId === collectionId + (member) => member.collectionId === collectionId ); - const groupIds = memberships.map(member => member.groupId); + const groupIds = memberships.map((member) => member.groupId); const groups = filter( this.orderedData, - group => !groupIds.includes(group.id) + (group) => !groupIds.includes(group.id) ); if (!query) return groups; @@ -71,7 +71,7 @@ export default class GroupsStore extends BaseStore { } function queriedGroups(groups, query) { - return filter(groups, group => + return filter(groups, (group) => group.name.toLowerCase().match(query.toLowerCase()) ); } diff --git a/app/stores/NotificationSettingsStore.js b/app/stores/NotificationSettingsStore.js index 4640a658..cf4968a5 100644 --- a/app/stores/NotificationSettingsStore.js +++ b/app/stores/NotificationSettingsStore.js @@ -4,9 +4,7 @@ import NotificationSetting from "models/NotificationSetting"; import BaseStore from "./BaseStore"; import RootStore from "./RootStore"; -export default class NotificationSettingsStore extends BaseStore< - NotificationSetting -> { +export default class NotificationSettingsStore extends BaseStore { actions = ["list", "create", "delete"]; constructor(rootStore: RootStore) { diff --git a/app/stores/RevisionsStore.js b/app/stores/RevisionsStore.js index d1c15501..f92e1132 100644 --- a/app/stores/RevisionsStore.js +++ b/app/stores/RevisionsStore.js @@ -52,7 +52,7 @@ export default class RevisionsStore extends BaseStore { const res = await client.post("/revisions.list", options); invariant(res && res.data, "Document revisions not available"); runInAction("RevisionsStore#fetchPage", () => { - res.data.forEach(revision => this.add(revision)); + res.data.forEach((revision) => this.add(revision)); this.isLoaded = true; }); return res.data; diff --git a/app/stores/SharesStore.js b/app/stores/SharesStore.js index 57ea16db..6e273c3a 100644 --- a/app/stores/SharesStore.js +++ b/app/stores/SharesStore.js @@ -21,7 +21,7 @@ export default class SharesStore extends BaseStore { @computed get published(): Share[] { - return filter(this.orderedData, share => share.published); + return filter(this.orderedData, (share) => share.published); } @action @@ -57,6 +57,6 @@ export default class SharesStore extends BaseStore { } getByDocumentId = (documentId): ?Share => { - return find(this.orderedData, share => share.documentId === documentId); + return find(this.orderedData, (share) => share.documentId === documentId); }; } diff --git a/app/stores/UiStore.js b/app/stores/UiStore.js index f2f33af1..9609be79 100644 --- a/app/stores/UiStore.js +++ b/app/stores/UiStore.js @@ -38,7 +38,7 @@ class UiStore { "(prefers-color-scheme: dark)" ); - const setSystemTheme = event => { + const setSystemTheme = (event) => { this.systemTheme = event.matches ? "dark" : "light"; }; setSystemTheme(colorSchemeQueryList); diff --git a/app/stores/UsersStore.js b/app/stores/UsersStore.js index c9790088..50bf4f83 100644 --- a/app/stores/UsersStore.js +++ b/app/stores/UsersStore.js @@ -16,33 +16,33 @@ export default class UsersStore extends BaseStore { get active(): User[] { return filter( this.orderedData, - user => !user.isSuspended && user.lastActiveAt + (user) => !user.isSuspended && user.lastActiveAt ); } @computed get suspended(): User[] { - return filter(this.orderedData, user => user.isSuspended); + return filter(this.orderedData, (user) => user.isSuspended); } @computed get activeOrInvited(): User[] { - return filter(this.orderedData, user => !user.isSuspended); + return filter(this.orderedData, (user) => !user.isSuspended); } @computed get invited(): User[] { - return filter(this.orderedData, user => !user.lastActiveAt); + return filter(this.orderedData, (user) => !user.lastActiveAt); } @computed get admins(): User[] { - return filter(this.orderedData, user => user.isAdmin); + return filter(this.orderedData, (user) => user.isAdmin); } @computed get all(): User[] { - return filter(this.orderedData, user => user.lastActiveAt); + return filter(this.orderedData, (user) => user.lastActiveAt); } @computed @@ -83,12 +83,12 @@ export default class UsersStore extends BaseStore { notInCollection = (collectionId: string, query: string = "") => { const memberships = filter( this.rootStore.memberships.orderedData, - member => member.collectionId === collectionId + (member) => member.collectionId === collectionId ); - const userIds = memberships.map(member => member.userId); + const userIds = memberships.map((member) => member.userId); const users = filter( this.activeOrInvited, - user => !userIds.includes(user.id) + (user) => !userIds.includes(user.id) ); if (!query) return users; @@ -98,10 +98,10 @@ export default class UsersStore extends BaseStore { inCollection = (collectionId: string, query: string) => { const memberships = filter( this.rootStore.memberships.orderedData, - member => member.collectionId === collectionId + (member) => member.collectionId === collectionId ); - const userIds = memberships.map(member => member.userId); - const users = filter(this.activeOrInvited, user => + const userIds = memberships.map((member) => member.userId); + const users = filter(this.activeOrInvited, (user) => userIds.includes(user.id) ); @@ -112,12 +112,12 @@ export default class UsersStore extends BaseStore { notInGroup = (groupId: string, query: string = "") => { const memberships = filter( this.rootStore.groupMemberships.orderedData, - member => member.groupId === groupId + (member) => member.groupId === groupId ); - const userIds = memberships.map(member => member.userId); + const userIds = memberships.map((member) => member.userId); const users = filter( this.activeOrInvited, - user => !userIds.includes(user.id) + (user) => !userIds.includes(user.id) ); if (!query) return users; @@ -127,10 +127,10 @@ export default class UsersStore extends BaseStore { inGroup = (groupId: string, query: string) => { const groupMemberships = filter( this.rootStore.groupMemberships.orderedData, - member => member.groupId === groupId + (member) => member.groupId === groupId ); - const userIds = groupMemberships.map(member => member.userId); - const users = filter(this.activeOrInvited, user => + const userIds = groupMemberships.map((member) => member.userId); + const users = filter(this.activeOrInvited, (user) => userIds.includes(user.id) ); @@ -152,7 +152,7 @@ export default class UsersStore extends BaseStore { } function queriedUsers(users, query) { - return filter(users, user => + return filter(users, (user) => user.name.toLowerCase().includes(query.toLowerCase()) ); } diff --git a/app/stores/ViewsStore.js b/app/stores/ViewsStore.js index 990f864f..421aef3c 100644 --- a/app/stores/ViewsStore.js +++ b/app/stores/ViewsStore.js @@ -13,7 +13,7 @@ export default class ViewsStore extends BaseStore { inDocument(documentId: string): View[] { return orderBy( - filter(this.orderedData, view => view.documentId === documentId), + filter(this.orderedData, (view) => view.documentId === documentId), "lastViewedAt", "desc" ); @@ -27,7 +27,7 @@ export default class ViewsStore extends BaseStore { touch(documentId: string, userId: string) { const view = find( this.orderedData, - view => view.documentId === documentId && view.user.id === userId + (view) => view.documentId === documentId && view.user.id === userId ); if (!view) return; view.touch(); diff --git a/app/utils/download.js b/app/utils/download.js index 709c4a4d..a502a7eb 100644 --- a/app/utils/download.js +++ b/app/utils/download.js @@ -19,7 +19,7 @@ export default function download( x = data, D = document, a = D.createElement("a"), - z = function(a, o) { + z = function (a, o) { return String(a); }, B = self.Blob || self.MozBlob || self.WebKitBlob || z, @@ -82,11 +82,11 @@ export default function download( a.setAttribute("download", fn); a.innerHTML = "downloading…"; D.body && D.body.appendChild(a); - setTimeout(function() { + setTimeout(function () { a.click(); D.body && D.body.removeChild(a); if (winMode === true) { - setTimeout(function() { + setTimeout(function () { self.URL.revokeObjectURL(a.href); }, 250); } @@ -103,7 +103,7 @@ export default function download( } f.src = url; - setTimeout(function() { + setTimeout(function () { D.body && D.body.removeChild(f); }, 333); } @@ -134,7 +134,7 @@ export default function download( // Blob but not URL: fr = new FileReader(); - fr.onload = function(e) { + fr.onload = function (e) { saver(this.result); }; diff --git a/app/utils/importFile.js b/app/utils/importFile.js index 49f4e62f..55706fd6 100644 --- a/app/utils/importFile.js +++ b/app/utils/importFile.js @@ -19,7 +19,7 @@ const importFile = async ({ return new Promise((resolve, reject) => { const reader = new FileReader(); - reader.onload = async ev => { + reader.onload = async (ev) => { let text = ev.target.result; let title; diff --git a/package.json b/package.json index c80840b2..d3f05377 100644 --- a/package.json +++ b/package.json @@ -183,7 +183,7 @@ "koa-webpack-hot-middleware": "^1.0.3", "mobx-react-devtools": "^6.0.3", "nodemon": "^1.19.4", - "prettier": "1.8.2", + "prettier": "^2.0.5", "rimraf": "^2.5.4" }, "resolutions": { diff --git a/server/api/apiKeys.js b/server/api/apiKeys.js index bbff4c8e..efafe939 100644 --- a/server/api/apiKeys.js +++ b/server/api/apiKeys.js @@ -10,7 +10,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("apiKeys.create", auth(), async ctx => { +router.post("apiKeys.create", auth(), async (ctx) => { const { name } = ctx.body; ctx.assertPresent(name, "name is required"); @@ -36,7 +36,7 @@ router.post("apiKeys.create", auth(), async ctx => { }; }); -router.post("apiKeys.list", auth(), pagination(), async ctx => { +router.post("apiKeys.list", auth(), pagination(), async (ctx) => { const user = ctx.state.user; const keys = await ApiKey.findAll({ where: { @@ -53,7 +53,7 @@ router.post("apiKeys.list", auth(), pagination(), async ctx => { }; }); -router.post("apiKeys.delete", auth(), async ctx => { +router.post("apiKeys.delete", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); diff --git a/server/api/attachments.js b/server/api/attachments.js index 98722bc3..e33d0d9d 100644 --- a/server/api/attachments.js +++ b/server/api/attachments.js @@ -18,7 +18,7 @@ const { authorize } = policy; const router = new Router(); const AWS_S3_ACL = process.env.AWS_S3_ACL || "private"; -router.post("attachments.create", auth(), async ctx => { +router.post("attachments.create", auth(), async (ctx) => { let { name, documentId, contentType, size } = ctx.body; ctx.assertPresent(name, "name is required"); @@ -31,7 +31,9 @@ router.post("attachments.create", auth(), async ctx => { const acl = ctx.body.public === undefined ? AWS_S3_ACL - : ctx.body.public ? "public-read" : "private"; + : ctx.body.public + ? "public-read" + : "private"; const credential = makeCredential(); const longDate = format(new Date(), "YYYYMMDDTHHmmss\\Z"); const policy = makePolicy(credential, longDate, acl); @@ -88,7 +90,7 @@ router.post("attachments.create", auth(), async ctx => { }; }); -router.post("attachments.redirect", auth(), async ctx => { +router.post("attachments.redirect", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); diff --git a/server/api/auth.js b/server/api/auth.js index b254c2fa..de0abd1b 100644 --- a/server/api/auth.js +++ b/server/api/auth.js @@ -37,19 +37,19 @@ function filterServices(team) { let output = services; if (team && !team.googleId) { - output = reject(output, service => service.id === "google"); + output = reject(output, (service) => service.id === "google"); } if (team && !team.slackId) { - output = reject(output, service => service.id === "slack"); + output = reject(output, (service) => service.id === "slack"); } if (!team || !team.guestSignin) { - output = reject(output, service => service.id === "email"); + output = reject(output, (service) => service.id === "email"); } return output; } -router.post("auth.config", async ctx => { +router.post("auth.config", async (ctx) => { // If self hosted AND there is only one team then that team becomes the // brand for the knowledge base and it's guest signin option is used for the // root login page. @@ -100,7 +100,7 @@ router.post("auth.config", async ctx => { }; }); -router.post("auth.info", auth(), async ctx => { +router.post("auth.info", auth(), async (ctx) => { const user = ctx.state.user; const team = await Team.findByPk(user.teamId); diff --git a/server/api/collections.js b/server/api/collections.js index 5da4c65f..20cd8645 100644 --- a/server/api/collections.js +++ b/server/api/collections.js @@ -29,7 +29,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("collections.create", auth(), async ctx => { +router.post("collections.create", auth(), async (ctx) => { const { name, color, description, icon, type } = ctx.body; const isPrivate = ctx.body.private; ctx.assertPresent(name, "name is required"); @@ -74,7 +74,7 @@ router.post("collections.create", auth(), async ctx => { }; }); -router.post("collections.info", auth(), async ctx => { +router.post("collections.info", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -90,7 +90,7 @@ router.post("collections.info", auth(), async ctx => { }; }); -router.post("collections.add_group", auth(), async ctx => { +router.post("collections.add_group", auth(), async (ctx) => { const { id, groupId, permission = "read_write" } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertUuid(groupId, "groupId is required"); @@ -140,7 +140,7 @@ router.post("collections.add_group", auth(), async ctx => { }; }); -router.post("collections.remove_group", auth(), async ctx => { +router.post("collections.remove_group", auth(), async (ctx) => { const { id, groupId } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertUuid(groupId, "groupId is required"); @@ -173,7 +173,7 @@ router.post( "collections.group_memberships", auth(), pagination(), - async ctx => { + async (ctx) => { const { id, query, permission } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -226,13 +226,13 @@ router.post( collectionGroupMemberships: memberships.map( presentCollectionGroupMembership ), - groups: memberships.map(membership => presentGroup(membership.group)), + groups: memberships.map((membership) => presentGroup(membership.group)), }, }; } ); -router.post("collections.add_user", auth(), async ctx => { +router.post("collections.add_user", auth(), async (ctx) => { const { id, userId, permission = "read_write" } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertUuid(userId, "userId is required"); @@ -282,7 +282,7 @@ router.post("collections.add_user", auth(), async ctx => { }; }); -router.post("collections.remove_user", auth(), async ctx => { +router.post("collections.remove_user", auth(), async (ctx) => { const { id, userId } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertUuid(userId, "userId is required"); @@ -313,7 +313,7 @@ router.post("collections.remove_user", auth(), async ctx => { }); // DEPRECATED: Use collection.memberships which has pagination, filtering and permissions -router.post("collections.users", auth(), async ctx => { +router.post("collections.users", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -330,7 +330,7 @@ router.post("collections.users", auth(), async ctx => { }; }); -router.post("collections.memberships", auth(), pagination(), async ctx => { +router.post("collections.memberships", auth(), pagination(), async (ctx) => { const { id, query, permission } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -380,12 +380,12 @@ router.post("collections.memberships", auth(), pagination(), async ctx => { pagination: ctx.state.pagination, data: { memberships: memberships.map(presentMembership), - users: memberships.map(membership => presentUser(membership.user)), + users: memberships.map((membership) => presentUser(membership.user)), }, }; }); -router.post("collections.export", auth(), async ctx => { +router.post("collections.export", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -411,7 +411,7 @@ router.post("collections.export", auth(), async ctx => { ctx.body = fs.createReadStream(filePath); }); -router.post("collections.export_all", auth(), async ctx => { +router.post("collections.export_all", auth(), async (ctx) => { const { download = false } = ctx.body; const user = ctx.state.user; @@ -445,7 +445,7 @@ router.post("collections.export_all", auth(), async ctx => { } }); -router.post("collections.update", auth(), async ctx => { +router.post("collections.update", auth(), async (ctx) => { const { id, name, description, icon, color } = ctx.body; const isPrivate = ctx.body.private; ctx.assertPresent(name, "name is required"); @@ -508,7 +508,7 @@ router.post("collections.update", auth(), async ctx => { }; }); -router.post("collections.list", auth(), pagination(), async ctx => { +router.post("collections.list", auth(), pagination(), async (ctx) => { const user = ctx.state.user; const collectionIds = await user.collectionIds(); let collections = await Collection.scope({ @@ -530,7 +530,7 @@ router.post("collections.list", auth(), pagination(), async ctx => { }; }); -router.post("collections.delete", auth(), async ctx => { +router.post("collections.delete", auth(), async (ctx) => { const { id } = ctx.body; const user = ctx.state.user; ctx.assertUuid(id, "id is required"); diff --git a/server/api/documents.js b/server/api/documents.js index aa0f5b68..6767263d 100644 --- a/server/api/documents.js +++ b/server/api/documents.js @@ -28,7 +28,7 @@ const Op = Sequelize.Op; const { authorize, cannot } = policy; const router = new Router(); -router.post("documents.list", auth(), pagination(), async ctx => { +router.post("documents.list", auth(), pagination(), async (ctx) => { const { sort = "updatedAt", template, @@ -90,7 +90,7 @@ router.post("documents.list", auth(), pagination(), async ctx => { where = { ...where, - id: backlinks.map(backlink => backlink.reverseDocumentId), + id: backlinks.map((backlink) => backlink.reverseDocumentId), }; } @@ -109,7 +109,7 @@ router.post("documents.list", auth(), pagination(), async ctx => { }); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -121,7 +121,7 @@ router.post("documents.list", auth(), pagination(), async ctx => { }; }); -router.post("documents.pinned", auth(), pagination(), async ctx => { +router.post("documents.pinned", auth(), pagination(), async (ctx) => { const { collectionId, sort = "updatedAt" } = ctx.body; let direction = ctx.body.direction; if (direction !== "ASC") direction = "DESC"; @@ -154,7 +154,7 @@ router.post("documents.pinned", auth(), pagination(), async ctx => { }); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -166,7 +166,7 @@ router.post("documents.pinned", auth(), pagination(), async ctx => { }; }); -router.post("documents.archived", auth(), pagination(), async ctx => { +router.post("documents.archived", auth(), pagination(), async (ctx) => { const { sort = "updatedAt" } = ctx.body; let direction = ctx.body.direction; if (direction !== "ASC") direction = "DESC"; @@ -192,7 +192,7 @@ router.post("documents.archived", auth(), pagination(), async ctx => { }); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -204,7 +204,7 @@ router.post("documents.archived", auth(), pagination(), async ctx => { }; }); -router.post("documents.deleted", auth(), pagination(), async ctx => { +router.post("documents.deleted", auth(), pagination(), async (ctx) => { const { sort = "deletedAt" } = ctx.body; let direction = ctx.body.direction; if (direction !== "ASC") direction = "DESC"; @@ -232,7 +232,7 @@ router.post("documents.deleted", auth(), pagination(), async ctx => { }); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -244,7 +244,7 @@ router.post("documents.deleted", auth(), pagination(), async ctx => { }; }); -router.post("documents.viewed", auth(), pagination(), async ctx => { +router.post("documents.viewed", auth(), pagination(), async (ctx) => { let { sort = "updatedAt", direction } = ctx.body; if (direction !== "ASC") direction = "DESC"; @@ -275,9 +275,9 @@ router.post("documents.viewed", auth(), pagination(), async ctx => { limit: ctx.state.pagination.limit, }); - const documents = views.map(view => view.document); + const documents = views.map((view) => view.document); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -289,7 +289,7 @@ router.post("documents.viewed", auth(), pagination(), async ctx => { }; }); -router.post("documents.starred", auth(), pagination(), async ctx => { +router.post("documents.starred", auth(), pagination(), async (ctx) => { let { sort = "updatedAt", direction } = ctx.body; if (direction !== "ASC") direction = "DESC"; @@ -326,9 +326,9 @@ router.post("documents.starred", auth(), pagination(), async ctx => { limit: ctx.state.pagination.limit, }); - const documents = stars.map(star => star.document); + const documents = stars.map((star) => star.document); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -340,7 +340,7 @@ router.post("documents.starred", auth(), pagination(), async ctx => { }; }); -router.post("documents.drafts", auth(), pagination(), async ctx => { +router.post("documents.drafts", auth(), pagination(), async (ctx) => { let { sort = "updatedAt", direction } = ctx.body; if (direction !== "ASC") direction = "DESC"; @@ -363,7 +363,7 @@ router.post("documents.drafts", auth(), pagination(), async ctx => { }); const data = await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ); const policies = presentPolicies(user, documents); @@ -417,7 +417,7 @@ async function loadDocument({ id, shareId, user }) { return document; } -router.post("documents.info", auth({ required: false }), async ctx => { +router.post("documents.info", auth({ required: false }), async (ctx) => { const { id, shareId } = ctx.body; ctx.assertPresent(id || shareId, "id or shareId is required"); @@ -431,7 +431,7 @@ router.post("documents.info", auth({ required: false }), async ctx => { }; }); -router.post("documents.export", auth({ required: false }), async ctx => { +router.post("documents.export", auth({ required: false }), async (ctx) => { const { id, shareId } = ctx.body; ctx.assertPresent(id || shareId, "id or shareId is required"); @@ -443,7 +443,7 @@ router.post("documents.export", auth({ required: false }), async ctx => { }; }); -router.post("documents.restore", auth(), async ctx => { +router.post("documents.restore", auth(), async (ctx) => { const { id, revisionId } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -513,7 +513,7 @@ router.post("documents.restore", auth(), async ctx => { }; }); -router.post("documents.search", auth(), pagination(), async ctx => { +router.post("documents.search", auth(), pagination(), async (ctx) => { const { query, includeArchived, @@ -559,9 +559,9 @@ router.post("documents.search", auth(), pagination(), async ctx => { limit, }); - const documents = results.map(result => result.document); + const documents = results.map((result) => result.document); const data = await Promise.all( - results.map(async result => { + results.map(async (result) => { const document = await presentDocument(result.document); return { ...result, document }; }) @@ -576,7 +576,7 @@ router.post("documents.search", auth(), pagination(), async ctx => { }; }); -router.post("documents.pin", auth(), async ctx => { +router.post("documents.pin", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -603,7 +603,7 @@ router.post("documents.pin", auth(), async ctx => { }; }); -router.post("documents.unpin", auth(), async ctx => { +router.post("documents.unpin", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -630,7 +630,7 @@ router.post("documents.unpin", auth(), async ctx => { }; }); -router.post("documents.star", auth(), async ctx => { +router.post("documents.star", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -657,7 +657,7 @@ router.post("documents.star", auth(), async ctx => { }; }); -router.post("documents.unstar", auth(), async ctx => { +router.post("documents.unstar", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -684,7 +684,7 @@ router.post("documents.unstar", auth(), async ctx => { }; }); -router.post("documents.create", auth(), async ctx => { +router.post("documents.create", auth(), async (ctx) => { const { title = "", text = "", @@ -786,7 +786,7 @@ router.post("documents.create", auth(), async ctx => { }; }); -router.post("documents.templatize", auth(), async ctx => { +router.post("documents.templatize", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -826,7 +826,7 @@ router.post("documents.templatize", auth(), async ctx => { }; }); -router.post("documents.update", auth(), async ctx => { +router.post("documents.update", auth(), async (ctx) => { const { id, title, @@ -917,7 +917,7 @@ router.post("documents.update", auth(), async ctx => { }; }); -router.post("documents.move", auth(), async ctx => { +router.post("documents.move", auth(), async (ctx) => { const { id, collectionId, parentDocumentId, index } = ctx.body; ctx.assertUuid(id, "id must be a uuid"); ctx.assertUuid(collectionId, "collectionId must be a uuid"); @@ -964,17 +964,17 @@ router.post("documents.move", auth(), async ctx => { ctx.body = { data: { documents: await Promise.all( - documents.map(document => presentDocument(document)) + documents.map((document) => presentDocument(document)) ), collections: await Promise.all( - collections.map(collection => presentCollection(collection)) + collections.map((collection) => presentCollection(collection)) ), }, policies: presentPolicies(user, documents), }; }); -router.post("documents.archive", auth(), async ctx => { +router.post("documents.archive", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -1000,7 +1000,7 @@ router.post("documents.archive", auth(), async ctx => { }; }); -router.post("documents.delete", auth(), async ctx => { +router.post("documents.delete", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertPresent(id, "id is required"); diff --git a/server/api/events.js b/server/api/events.js index 3b0b3dd8..c098a356 100644 --- a/server/api/events.js +++ b/server/api/events.js @@ -11,7 +11,7 @@ const Op = Sequelize.Op; const { authorize } = policy; const router = new Router(); -router.post("events.list", auth(), pagination(), async ctx => { +router.post("events.list", auth(), pagination(), async (ctx) => { let { sort = "createdAt", direction, auditLog = false } = ctx.body; if (direction !== "ASC") direction = "DESC"; @@ -53,7 +53,7 @@ router.post("events.list", auth(), pagination(), async ctx => { ctx.body = { pagination: ctx.state.pagination, - data: events.map(event => presentEvent(event, auditLog)), + data: events.map((event) => presentEvent(event, auditLog)), }; }); diff --git a/server/api/groups.js b/server/api/groups.js index 5dbbefe3..50fb4443 100644 --- a/server/api/groups.js +++ b/server/api/groups.js @@ -17,7 +17,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("groups.list", auth(), pagination(), async ctx => { +router.post("groups.list", auth(), pagination(), async (ctx) => { const { sort = "updatedAt" } = ctx.body; let direction = ctx.body.direction; if (direction !== "ASC") direction = "DESC"; @@ -34,7 +34,8 @@ router.post("groups.list", auth(), pagination(), async ctx => { if (!user.isAdmin) { groups = groups.filter( - group => group.groupMemberships.filter(gm => gm.userId === user.id).length + (group) => + group.groupMemberships.filter((gm) => gm.userId === user.id).length ); } @@ -43,9 +44,9 @@ router.post("groups.list", auth(), pagination(), async ctx => { data: { groups: groups.map(presentGroup), groupMemberships: groups - .map(g => + .map((g) => g.groupMemberships - .filter(membership => !!membership.user) + .filter((membership) => !!membership.user) .slice(0, MAX_AVATAR_DISPLAY) ) .flat() @@ -55,7 +56,7 @@ router.post("groups.list", auth(), pagination(), async ctx => { }; }); -router.post("groups.info", auth(), async ctx => { +router.post("groups.info", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -69,7 +70,7 @@ router.post("groups.info", auth(), async ctx => { }; }); -router.post("groups.create", auth(), async ctx => { +router.post("groups.create", auth(), async (ctx) => { const { name } = ctx.body; ctx.assertPresent(name, "name is required"); @@ -100,7 +101,7 @@ router.post("groups.create", auth(), async ctx => { }; }); -router.post("groups.update", auth(), async ctx => { +router.post("groups.update", auth(), async (ctx) => { const { id, name } = ctx.body; ctx.assertPresent(name, "name is required"); ctx.assertUuid(id, "id is required"); @@ -130,7 +131,7 @@ router.post("groups.update", auth(), async ctx => { }; }); -router.post("groups.delete", auth(), async ctx => { +router.post("groups.delete", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -154,7 +155,7 @@ router.post("groups.delete", auth(), async ctx => { }; }); -router.post("groups.memberships", auth(), pagination(), async ctx => { +router.post("groups.memberships", auth(), pagination(), async (ctx) => { const { id, query } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -190,12 +191,12 @@ router.post("groups.memberships", auth(), pagination(), async ctx => { pagination: ctx.state.pagination, data: { groupMemberships: memberships.map(presentGroupMembership), - users: memberships.map(membership => presentUser(membership.user)), + users: memberships.map((membership) => presentUser(membership.user)), }, }; }); -router.post("groups.add_user", auth(), async ctx => { +router.post("groups.add_user", auth(), async (ctx) => { const { id, userId } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertUuid(userId, "userId is required"); @@ -249,7 +250,7 @@ router.post("groups.add_user", auth(), async ctx => { }; }); -router.post("groups.remove_user", auth(), async ctx => { +router.post("groups.remove_user", auth(), async (ctx) => { const { id, userId } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertUuid(userId, "userId is required"); diff --git a/server/api/hooks.js b/server/api/hooks.js index 02ac9b58..7dacc255 100644 --- a/server/api/hooks.js +++ b/server/api/hooks.js @@ -8,7 +8,7 @@ import * as Slack from "../slack"; const router = new Router(); // triggered by a user posting a getoutline.com link in Slack -router.post("hooks.unfurl", async ctx => { +router.post("hooks.unfurl", async (ctx) => { const { challenge, token, event } = ctx.body; if (challenge) return (ctx.body = ctx.body.challenge); @@ -49,7 +49,7 @@ router.post("hooks.unfurl", async ctx => { }); // triggered by interactions with actions, dialogs, message buttons in Slack -router.post("hooks.interactive", async ctx => { +router.post("hooks.interactive", async (ctx) => { const { payload } = ctx.body; ctx.assertPresent(payload, "payload is required"); @@ -98,7 +98,7 @@ router.post("hooks.interactive", async ctx => { }); // triggered by the /outline command in Slack -router.post("hooks.slack", async ctx => { +router.post("hooks.slack", async (ctx) => { const { token, team_id, user_id, text = "" } = ctx.body; ctx.assertPresent(token, "token is required"); ctx.assertPresent(team_id, "team_id is required"); diff --git a/server/api/index.js b/server/api/index.js index 6113b888..3d3436c9 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -56,7 +56,7 @@ router.use("/", attachments.routes()); router.use("/", utils.routes()); router.use("/", groups.routes()); -router.post("*", ctx => { +router.post("*", (ctx) => { ctx.throw(new NotFoundError("Endpoint not found")); }); diff --git a/server/api/integrations.js b/server/api/integrations.js index d2e2a8d8..c14553d5 100644 --- a/server/api/integrations.js +++ b/server/api/integrations.js @@ -10,7 +10,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("integrations.list", auth(), pagination(), async ctx => { +router.post("integrations.list", auth(), pagination(), async (ctx) => { let { sort = "updatedAt", direction } = ctx.body; if (direction !== "ASC") direction = "DESC"; @@ -28,7 +28,7 @@ router.post("integrations.list", auth(), pagination(), async ctx => { }; }); -router.post("integrations.delete", auth(), async ctx => { +router.post("integrations.delete", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); diff --git a/server/api/middlewares/pagination.js b/server/api/middlewares/pagination.js index 9bf11bbc..c45cc98a 100644 --- a/server/api/middlewares/pagination.js +++ b/server/api/middlewares/pagination.js @@ -48,7 +48,7 @@ export default function pagination(options?: Object) { } /* $FlowFixMeNowPlease This comment suppresses an error found when upgrading - * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ + * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ ctx.state.pagination = { limit, offset, @@ -60,7 +60,7 @@ export default function pagination(options?: Object) { query.offset = ctx.state.pagination.offset + query.limit; /* $FlowFixMeNowPlease This comment suppresses an error found when upgrading - * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ + * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ ctx.state.pagination.nextPath = `/api${ ctx.request.path }?${querystring.stringify(query)}`; diff --git a/server/api/notificationSettings.js b/server/api/notificationSettings.js index a911d9db..bdfc710d 100644 --- a/server/api/notificationSettings.js +++ b/server/api/notificationSettings.js @@ -9,7 +9,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("notificationSettings.create", auth(), async ctx => { +router.post("notificationSettings.create", auth(), async (ctx) => { const { event } = ctx.body; ctx.assertPresent(event, "event is required"); @@ -29,7 +29,7 @@ router.post("notificationSettings.create", auth(), async ctx => { }; }); -router.post("notificationSettings.list", auth(), async ctx => { +router.post("notificationSettings.list", auth(), async (ctx) => { const user = ctx.state.user; const settings = await NotificationSetting.findAll({ where: { @@ -42,7 +42,7 @@ router.post("notificationSettings.list", auth(), async ctx => { }; }); -router.post("notificationSettings.delete", auth(), async ctx => { +router.post("notificationSettings.delete", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); @@ -57,7 +57,7 @@ router.post("notificationSettings.delete", auth(), async ctx => { }; }); -router.post("notificationSettings.unsubscribe", async ctx => { +router.post("notificationSettings.unsubscribe", async (ctx) => { const { id, token } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertPresent(token, "token is required"); diff --git a/server/api/revisions.js b/server/api/revisions.js index 2b758239..383fffc8 100644 --- a/server/api/revisions.js +++ b/server/api/revisions.js @@ -10,7 +10,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("revisions.info", auth(), async ctx => { +router.post("revisions.info", auth(), async (ctx) => { let { id } = ctx.body; ctx.assertPresent(id, "id is required"); @@ -31,7 +31,7 @@ router.post("revisions.info", auth(), async ctx => { }; }); -router.post("revisions.list", auth(), pagination(), async ctx => { +router.post("revisions.list", auth(), pagination(), async (ctx) => { let { documentId, sort = "updatedAt", direction } = ctx.body; if (direction !== "ASC") direction = "DESC"; ctx.assertPresent(documentId, "documentId is required"); @@ -48,7 +48,7 @@ router.post("revisions.list", auth(), pagination(), async ctx => { }); const data = await Promise.all( - revisions.map(revision => presentRevision(revision)) + revisions.map((revision) => presentRevision(revision)) ); ctx.body = { diff --git a/server/api/shares.js b/server/api/shares.js index 0edcbf73..a8211cc7 100644 --- a/server/api/shares.js +++ b/server/api/shares.js @@ -12,7 +12,7 @@ const Op = Sequelize.Op; const { authorize } = policy; const router = new Router(); -router.post("shares.info", auth(), async ctx => { +router.post("shares.info", auth(), async (ctx) => { const { id, documentId } = ctx.body; ctx.assertUuid(id || documentId, "id or documentId is required"); @@ -39,7 +39,7 @@ router.post("shares.info", auth(), async ctx => { }; }); -router.post("shares.list", auth(), pagination(), async ctx => { +router.post("shares.list", auth(), pagination(), async (ctx) => { let { sort = "updatedAt", direction } = ctx.body; if (direction !== "ASC") direction = "DESC"; @@ -90,7 +90,7 @@ router.post("shares.list", auth(), pagination(), async ctx => { }; }); -router.post("shares.update", auth(), async ctx => { +router.post("shares.update", auth(), async (ctx) => { const { id, published } = ctx.body; ctx.assertUuid(id, "id is required"); ctx.assertPresent(published, "published is required"); @@ -118,7 +118,7 @@ router.post("shares.update", auth(), async ctx => { }; }); -router.post("shares.create", auth(), async ctx => { +router.post("shares.create", auth(), async (ctx) => { const { documentId } = ctx.body; ctx.assertPresent(documentId, "documentId is required"); @@ -160,7 +160,7 @@ router.post("shares.create", auth(), async ctx => { }; }); -router.post("shares.revoke", auth(), async ctx => { +router.post("shares.revoke", auth(), async (ctx) => { const { id } = ctx.body; ctx.assertUuid(id, "id is required"); diff --git a/server/api/team.js b/server/api/team.js index 2c856818..b44043e5 100644 --- a/server/api/team.js +++ b/server/api/team.js @@ -9,7 +9,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("team.update", auth(), async ctx => { +router.post("team.update", auth(), async (ctx) => { const { name, avatarUrl, diff --git a/server/api/users.js b/server/api/users.js index 0e292f1b..4ef74eec 100644 --- a/server/api/users.js +++ b/server/api/users.js @@ -11,7 +11,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("users.list", auth(), pagination(), async ctx => { +router.post("users.list", auth(), pagination(), async (ctx) => { const { sort = "createdAt", query, includeSuspended = false } = ctx.body; let direction = ctx.body.direction; if (direction !== "ASC") direction = "DESC"; @@ -48,19 +48,19 @@ router.post("users.list", auth(), pagination(), async ctx => { ctx.body = { pagination: ctx.state.pagination, - data: users.map(listUser => + data: users.map((listUser) => presentUser(listUser, { includeDetails: user.isAdmin }) ), }; }); -router.post("users.info", auth(), async ctx => { +router.post("users.info", auth(), async (ctx) => { ctx.body = { data: presentUser(ctx.state.user), }; }); -router.post("users.update", auth(), async ctx => { +router.post("users.update", auth(), async (ctx) => { const { user } = ctx.state; const { name, avatarUrl } = ctx.body; @@ -76,7 +76,7 @@ router.post("users.update", auth(), async ctx => { // Admin specific -router.post("users.promote", auth(), async ctx => { +router.post("users.promote", auth(), async (ctx) => { const userId = ctx.body.id; const teamId = ctx.state.user.teamId; ctx.assertPresent(userId, "id is required"); @@ -101,7 +101,7 @@ router.post("users.promote", auth(), async ctx => { }; }); -router.post("users.demote", auth(), async ctx => { +router.post("users.demote", auth(), async (ctx) => { const userId = ctx.body.id; const teamId = ctx.state.user.teamId; ctx.assertPresent(userId, "id is required"); @@ -126,7 +126,7 @@ router.post("users.demote", auth(), async ctx => { }; }); -router.post("users.suspend", auth(), async ctx => { +router.post("users.suspend", auth(), async (ctx) => { const admin = ctx.state.user; const userId = ctx.body.id; const teamId = ctx.state.user.teamId; @@ -152,7 +152,7 @@ router.post("users.suspend", auth(), async ctx => { }; }); -router.post("users.activate", auth(), async ctx => { +router.post("users.activate", auth(), async (ctx) => { const admin = ctx.state.user; const userId = ctx.body.id; const teamId = ctx.state.user.teamId; @@ -178,7 +178,7 @@ router.post("users.activate", auth(), async ctx => { }; }); -router.post("users.invite", auth(), async ctx => { +router.post("users.invite", auth(), async (ctx) => { const { invites } = ctx.body; ctx.assertPresent(invites, "invites is required"); @@ -190,12 +190,12 @@ router.post("users.invite", auth(), async ctx => { ctx.body = { data: { sent: response.sent, - users: response.users.map(user => presentUser(user)), + users: response.users.map((user) => presentUser(user)), }, }; }); -router.post("users.delete", auth(), async ctx => { +router.post("users.delete", auth(), async (ctx) => { const { confirmation, id } = ctx.body; ctx.assertPresent(confirmation, "confirmation is required"); diff --git a/server/api/utils.js b/server/api/utils.js index 19d788b6..cac670dd 100644 --- a/server/api/utils.js +++ b/server/api/utils.js @@ -9,7 +9,7 @@ import { Op } from "../sequelize"; const router = new Router(); const log = debug("utils"); -router.post("utils.gc", async ctx => { +router.post("utils.gc", async (ctx) => { const { token } = ctx.body; if (process.env.UTILS_SECRET !== token) { @@ -28,7 +28,7 @@ router.post("utils.gc", async ctx => { attributes: ["id"], where, }); - const documentIds = documents.map(d => d.id); + const documentIds = documents.map((d) => d.id); await Attachment.destroy({ where: { diff --git a/server/api/views.js b/server/api/views.js index 3d9b0a70..489edd4f 100644 --- a/server/api/views.js +++ b/server/api/views.js @@ -8,7 +8,7 @@ import policy from "../policies"; const { authorize } = policy; const router = new Router(); -router.post("views.list", auth(), async ctx => { +router.post("views.list", auth(), async (ctx) => { const { documentId } = ctx.body; ctx.assertUuid(documentId, "documentId is required"); @@ -23,7 +23,7 @@ router.post("views.list", auth(), async ctx => { }; }); -router.post("views.create", auth(), async ctx => { +router.post("views.create", auth(), async (ctx) => { const { documentId } = ctx.body; ctx.assertUuid(documentId, "documentId is required"); diff --git a/server/app.js b/server/app.js index 9178de59..2cfd11eb 100644 --- a/server/app.js +++ b/server/app.js @@ -114,12 +114,12 @@ app.on("error", (error, ctx) => { } if (process.env.SENTRY_DSN) { - Sentry.withScope(function(scope) { + Sentry.withScope(function (scope) { const requestId = ctx.headers["x-request-id"]; if (requestId) { scope.setTag("request_id", requestId); } - scope.addEventProcessor(function(event) { + scope.addEventProcessor(function (event) { return Sentry.Handlers.parseRequest(event, ctx.request); }); Sentry.captureException(error); diff --git a/server/auth/email.js b/server/auth/email.js index 0a54fe33..85d1db86 100644 --- a/server/auth/email.js +++ b/server/auth/email.js @@ -14,7 +14,7 @@ const router = new Router(); router.use(methodOverride()); router.use(validation()); -router.post("email", async ctx => { +router.post("email", async (ctx) => { const { email } = ctx.body; ctx.assertEmail(email, "email is required"); @@ -66,7 +66,7 @@ router.post("email", async ctx => { }; }); -router.get("email.callback", auth({ required: false }), async ctx => { +router.get("email.callback", auth({ required: false }), async (ctx) => { const { token } = ctx.request.query; ctx.assertPresent(token, "token is required"); diff --git a/server/auth/google.js b/server/auth/google.js index 779622e7..faaaa163 100644 --- a/server/auth/google.js +++ b/server/auth/google.js @@ -18,7 +18,7 @@ const client = new OAuth2Client( const allowedDomainsEnv = process.env.GOOGLE_ALLOWED_DOMAINS; // start the oauth process and redirect user to Google -router.get("google", async ctx => { +router.get("google", async (ctx) => { // Generate the url that will be used for the consent dialog. const authorizeUrl = client.generateAuthUrl({ access_type: "offline", @@ -32,7 +32,7 @@ router.get("google", async ctx => { }); // signin callback from Google -router.get("google.callback", auth({ required: false }), async ctx => { +router.get("google.callback", auth({ required: false }), async (ctx) => { const { code } = ctx.request.query; ctx.assertPresent(code, "code is required"); const response = await client.getToken(code); @@ -64,9 +64,7 @@ router.get("google.callback", auth({ required: false }), async ctx => { hash.update(googleId); const hashedGoogleId = hash.digest("hex"); const cbUrl = `https://logo.clearbit.com/${profile.data.hd}`; - const tileyUrl = `https://tiley.herokuapp.com/avatar/${hashedGoogleId}/${ - teamName[0] - }.png`; + const tileyUrl = `https://tiley.herokuapp.com/avatar/${hashedGoogleId}/${teamName[0]}.png`; const cbResponse = await fetch(cbUrl); const avatarUrl = cbResponse.status === 200 ? cbUrl : tileyUrl; diff --git a/server/auth/index.js b/server/auth/index.js index d53c4fe9..050253ff 100644 --- a/server/auth/index.js +++ b/server/auth/index.js @@ -19,7 +19,7 @@ router.use("/", slack.routes()); router.use("/", google.routes()); router.use("/", email.routes()); -router.get("/redirect", auth(), async ctx => { +router.get("/redirect", auth(), async (ctx) => { const user = ctx.state.user; // transfer access token cookie from root to subdomain diff --git a/server/auth/slack.js b/server/auth/slack.js index 4f6525ed..16859489 100644 --- a/server/auth/slack.js +++ b/server/auth/slack.js @@ -19,10 +19,8 @@ const Op = Sequelize.Op; const router = new Router(); // start the oauth process and redirect user to Slack -router.get("slack", async ctx => { - const state = Math.random() - .toString(36) - .substring(7); +router.get("slack", async (ctx) => { + const state = Math.random().toString(36).substring(7); ctx.cookies.set("state", state, { httpOnly: false, @@ -33,7 +31,7 @@ router.get("slack", async ctx => { }); // signin callback from Slack -router.get("slack.callback", auth({ required: false }), async ctx => { +router.get("slack.callback", auth({ required: false }), async (ctx) => { const { code, error, state } = ctx.request.query; ctx.assertPresent(code || error, "code is required"); ctx.assertPresent(state, "state is required"); @@ -142,7 +140,7 @@ router.get("slack.callback", auth({ required: false }), async ctx => { } }); -router.get("slack.commands", auth({ required: false }), async ctx => { +router.get("slack.commands", auth({ required: false }), async (ctx) => { const { code, state, error } = ctx.request.query; const user = ctx.state.user; ctx.assertPresent(code || error, "code is required"); @@ -194,7 +192,7 @@ router.get("slack.commands", auth({ required: false }), async ctx => { ctx.redirect("/settings/integrations/slack"); }); -router.get("slack.post", auth({ required: false }), async ctx => { +router.get("slack.post", auth({ required: false }), async (ctx) => { const { code, error, state } = ctx.request.query; const user = ctx.state.user; ctx.assertPresent(code || error, "code is required"); diff --git a/server/commands/documentMover.js b/server/commands/documentMover.js index 56c4d1d1..eab4abe8 100644 --- a/server/commands/documentMover.js +++ b/server/commands/documentMover.js @@ -53,13 +53,13 @@ export default async function documentMover({ if (collectionChanged) { result.collections.push(newCollection); - const loopChildren = async documentId => { + const loopChildren = async (documentId) => { const childDocuments = await Document.findAll({ where: { parentDocumentId: documentId }, }); await Promise.all( - childDocuments.map(async child => { + childDocuments.map(async (child) => { await loopChildren(child.id); await child.update({ collectionId }, { transaction }); child.collection = newCollection; @@ -84,8 +84,8 @@ export default async function documentMover({ teamId: document.teamId, data: { title: document.title, - collectionIds: result.collections.map(c => c.id), - documentIds: result.documents.map(d => d.id), + collectionIds: result.collections.map((c) => c.id), + documentIds: result.documents.map((d) => d.id), }, ip, }); diff --git a/server/commands/userInviter.js b/server/commands/userInviter.js index 603cd122..7040cdf0 100644 --- a/server/commands/userInviter.js +++ b/server/commands/userInviter.js @@ -19,12 +19,12 @@ export default async function userInviter({ // filter out empties and obvious non-emails const compactedInvites = invites.filter( - invite => !!invite.email.trim() && invite.email.match("@") + (invite) => !!invite.email.trim() && invite.email.match("@") ); // normalize to lowercase and remove duplicates const normalizedInvites = uniqBy( - compactedInvites.map(invite => ({ + compactedInvites.map((invite) => ({ ...invite, email: invite.email.toLowerCase(), })), @@ -32,23 +32,23 @@ export default async function userInviter({ ); // filter out any existing users in the system - const emails = normalizedInvites.map(invite => invite.email); + const emails = normalizedInvites.map((invite) => invite.email); const existingUsers = await User.findAll({ where: { teamId: user.teamId, email: emails, }, }); - const existingEmails = existingUsers.map(user => user.email); + const existingEmails = existingUsers.map((user) => user.email); const filteredInvites = normalizedInvites.filter( - invite => !existingEmails.includes(invite.email) + (invite) => !existingEmails.includes(invite.email) ); let users = []; // send and record remaining invites await Promise.all( - filteredInvites.map(async invite => { + filteredInvites.map(async (invite) => { const transaction = await sequelize.transaction(); try { const newUser = await User.create( diff --git a/server/emails/DocumentNotificationEmail.js b/server/emails/DocumentNotificationEmail.js index dc1c4248..50878dde 100644 --- a/server/emails/DocumentNotificationEmail.js +++ b/server/emails/DocumentNotificationEmail.js @@ -27,9 +27,7 @@ export const documentNotificationEmailText = ({ }: Props) => ` "${document.title}" ${eventName} -${actor.name} ${eventName} the document "${document.title}", in the ${ - collection.name -} collection. +${actor.name} ${eventName} the document "${document.title}", in the ${collection.name} collection. Open Document: ${team.url}${document.url} `; diff --git a/server/emails/InviteEmail.js b/server/emails/InviteEmail.js index b0bf30d9..ff5a84f4 100644 --- a/server/emails/InviteEmail.js +++ b/server/emails/InviteEmail.js @@ -24,9 +24,7 @@ export const inviteEmailText = ({ }: Props) => ` Join ${teamName} on Outline -${actorName} (${ - actorEmail -}) has invited you to join Outline, a place for your team to build and share knowledge. +${actorName} (${actorEmail}) has invited you to join Outline, a place for your team to build and share knowledge. Join now: ${teamUrl} `; diff --git a/server/emails/index.js b/server/emails/index.js index 83d187a2..eb519d46 100644 --- a/server/emails/index.js +++ b/server/emails/index.js @@ -7,11 +7,11 @@ import { Mailer } from "../mailer"; const emailPreviews = new Koa(); const router = new Router(); -router.get("/:type/:format", async ctx => { +router.get("/:type/:format", async (ctx) => { let mailerOutput; let mailer = new Mailer(); mailer.transporter = { - sendMail: data => (mailerOutput = data), + sendMail: (data) => (mailerOutput = data), }; switch (ctx.params.type) { diff --git a/server/events.js b/server/events.js index c1747188..066cf0ac 100644 --- a/server/events.js +++ b/server/events.js @@ -126,9 +126,9 @@ const globalEventsQueue = createQueue("global events"); const serviceEventsQueue = createQueue("service events"); // this queue processes global events and hands them off to service hooks -globalEventsQueue.process(async job => { +globalEventsQueue.process(async (job) => { const names = Object.keys(services); - names.forEach(name => { + names.forEach((name) => { const service = services[name]; if (service.on) { serviceEventsQueue.add( @@ -140,14 +140,14 @@ globalEventsQueue.process(async job => { }); // this queue processes an individual event for a specific service -serviceEventsQueue.process(async job => { +serviceEventsQueue.process(async (job) => { const event = job.data; const service = services[event.service]; if (service.on) { - service.on(event).catch(error => { + service.on(event).catch((error) => { if (process.env.SENTRY_DSN) { - Sentry.withScope(function(scope) { + Sentry.withScope(function (scope) { scope.setExtra("event", event); Sentry.captureException(error); }); diff --git a/server/index.js b/server/index.js index 22247b80..a05989d9 100644 --- a/server/index.js +++ b/server/index.js @@ -55,7 +55,7 @@ SocketAuth(io, { // has access to on connection. New collection subscriptions // are managed from the client as needed through the 'join' event const collectionIds = await user.collectionIds(); - collectionIds.forEach(collectionId => + collectionIds.forEach((collectionId) => rooms.push(`collection-${collectionId}`) ); @@ -63,7 +63,7 @@ SocketAuth(io, { socket.join(rooms); // allow the client to request to join rooms - socket.on("join", async event => { + socket.on("join", async (event) => { // user is joining a collection channel, because their permissions have // changed, granting them access. if (event.collectionId) { @@ -114,7 +114,7 @@ SocketAuth(io, { socket.emit("document.presence", { documentId: event.documentId, userIds: Array.from(userIds.keys()), - editingIds: editing.map(view => view.userId), + editingIds: editing.map((view) => view.userId), }); }); }); @@ -123,7 +123,7 @@ SocketAuth(io, { }); // allow the client to request to leave rooms - socket.on("leave", event => { + socket.on("leave", (event) => { if (event.collectionId) { socket.leave(`collection-${event.collectionId}`); } @@ -141,7 +141,7 @@ SocketAuth(io, { socket.on("disconnecting", () => { const rooms = Object.keys(socket.rooms); - rooms.forEach(room => { + rooms.forEach((room) => { if (room.startsWith("document-")) { const documentId = room.replace("document-", ""); io.to(room).emit("user.leave", { @@ -152,7 +152,7 @@ SocketAuth(io, { }); }); - socket.on("presence", async event => { + socket.on("presence", async (event) => { const room = `document-${event.documentId}`; if (event.documentId && socket.rooms[room]) { @@ -173,7 +173,7 @@ SocketAuth(io, { }, }); -server.on("error", err => { +server.on("error", (err) => { throw err; }); diff --git a/server/logistics.js b/server/logistics.js index 37d589b1..371741bf 100644 --- a/server/logistics.js +++ b/server/logistics.js @@ -38,7 +38,7 @@ async function exportAndEmailCollections(teamId: string, email: string) { }); } -logisticsQueue.process(async job => { +logisticsQueue.process(async (job) => { log("Process", job.data); switch (job.data.type) { diff --git a/server/mailer.js b/server/mailer.js index aad0f651..9acbb60e 100644 --- a/server/mailer.js +++ b/server/mailer.js @@ -116,9 +116,7 @@ export class Mailer { invite = async (opts: { to: string } & InviteEmailT) => { this.sendMail({ to: opts.to, - title: `${opts.actorName} invited you to join ${ - opts.teamName - }’s knowledge base`, + title: `${opts.actorName} invited you to join ${opts.teamName}’s knowledge base`, previewText: "Outline is a place for your team to build and share knowledge.", html: , diff --git a/server/mailer.test.js b/server/mailer.test.js index 31c00b40..84f6c2a0 100644 --- a/server/mailer.test.js +++ b/server/mailer.test.js @@ -11,7 +11,7 @@ describe("Mailer", () => { jest.resetModules(); fakeMailer.transporter = { - sendMail: output => (sendMailOutput = output), + sendMail: (output) => (sendMailOutput = output), }; }); diff --git a/server/middlewares/authentication.js b/server/middlewares/authentication.js index e47e72fa..0a235d40 100644 --- a/server/middlewares/authentication.js +++ b/server/middlewares/authentication.js @@ -61,7 +61,7 @@ export default function auth(options?: { required?: boolean } = {}) { if (!user) throw new AuthenticationError("Invalid API key"); } else { /* $FlowFixMeNowPlease This comment suppresses an error found when upgrading - * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ + * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ user = await getUserForJWT(token); } @@ -77,16 +77,16 @@ export default function auth(options?: { required?: boolean } = {}) { user.updateActiveAt(ctx.request.ip); /* $FlowFixMeNowPlease This comment suppresses an error found when upgrading - * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ + * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ ctx.state.token = token; /* $FlowFixMeNowPlease This comment suppresses an error found when upgrading - * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ + * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ ctx.state.user = user; if (!ctx.cache) ctx.cache = {}; /* $FlowFixMeNowPlease This comment suppresses an error found when upgrading - * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ + * flow-bin@0.104.0. To view the error, delete this comment and run Flow. */ ctx.cache[user.id] = user; } diff --git a/server/models/ApiKey.js b/server/models/ApiKey.js index 0c89a119..9954eec8 100644 --- a/server/models/ApiKey.js +++ b/server/models/ApiKey.js @@ -25,14 +25,14 @@ const ApiKey = sequelize.define( tableName: "apiKeys", paranoid: true, hooks: { - beforeValidate: key => { + beforeValidate: (key) => { key.secret = randomstring.generate(38); }, }, } ); -ApiKey.associate = models => { +ApiKey.associate = (models) => { ApiKey.belongsTo(models.User, { as: "user", foreignKey: "userId", diff --git a/server/models/Attachment.js b/server/models/Attachment.js index 54ff666c..e5792ece 100644 --- a/server/models/Attachment.js +++ b/server/models/Attachment.js @@ -38,24 +38,24 @@ const Attachment = sequelize.define( }, { getterMethods: { - name: function() { + name: function () { return path.parse(this.key).base; }, - redirectUrl: function() { + redirectUrl: function () { return `/api/attachments.redirect?id=${this.id}`; }, - isPrivate: function() { + isPrivate: function () { return this.acl === "private"; }, }, } ); -Attachment.beforeDestroy(async model => { +Attachment.beforeDestroy(async (model) => { await deleteFromS3(model.key); }); -Attachment.associate = models => { +Attachment.associate = (models) => { Attachment.belongsTo(models.Team); Attachment.belongsTo(models.Document); Attachment.belongsTo(models.User); diff --git a/server/models/Authentication.js b/server/models/Authentication.js index d9d48e52..819d3e35 100644 --- a/server/models/Authentication.js +++ b/server/models/Authentication.js @@ -12,7 +12,7 @@ const Authentication = sequelize.define("authentication", { token: encryptedFields.vault("token"), }); -Authentication.associate = models => { +Authentication.associate = (models) => { Authentication.belongsTo(models.User, { as: "user", foreignKey: "userId", diff --git a/server/models/Backlink.js b/server/models/Backlink.js index 6188a78a..bc0821f0 100644 --- a/server/models/Backlink.js +++ b/server/models/Backlink.js @@ -9,7 +9,7 @@ const Backlink = sequelize.define("backlink", { }, }); -Backlink.associate = models => { +Backlink.associate = (models) => { Backlink.belongsTo(models.Document, { as: "document", foreignKey: "documentId", diff --git a/server/models/Collection.js b/server/models/Collection.js index 7830bd2c..f183ced7 100644 --- a/server/models/Collection.js +++ b/server/models/Collection.js @@ -47,7 +47,7 @@ const Collection = sequelize.define( } ); -Collection.addHook("beforeSave", async model => { +Collection.addHook("beforeSave", async (model) => { if (model.icon === "collection") { model.icon = null; } @@ -55,7 +55,7 @@ Collection.addHook("beforeSave", async model => { // Class methods -Collection.associate = models => { +Collection.associate = (models) => { Collection.hasMany(models.Document, { as: "documents", foreignKey: "collectionId", @@ -88,7 +88,7 @@ Collection.associate = models => { Collection.belongsTo(models.Team, { as: "team", }); - Collection.addScope("withMembership", userId => ({ + Collection.addScope("withMembership", (userId) => ({ include: [ { model: models.CollectionUser, @@ -191,20 +191,20 @@ Collection.membershipUserIds = async (collectionId: string) => { ); const groupMemberships = collection.collectionGroupMemberships - .map(cgm => cgm.group.groupMemberships) + .map((cgm) => cgm.group.groupMemberships) .flat(); const membershipUserIds = concat( groupMemberships, collection.memberships - ).map(membership => membership.userId); + ).map((membership) => membership.userId); return uniq(membershipUserIds); }; // Instance methods -Collection.prototype.addDocumentToStructure = async function( +Collection.prototype.addDocumentToStructure = async function ( document: Document, index: number, options = {} @@ -237,8 +237,8 @@ Collection.prototype.addDocumentToStructure = async function( ); } else { // Recursively place document - const placeDocument = documentList => { - return documentList.map(childDocument => { + const placeDocument = (documentList) => { + return documentList.map((childDocument) => { if (document.parentDocumentId === childDocument.id) { childDocument.children.splice( index !== undefined ? index : childDocument.children.length, @@ -280,7 +280,7 @@ Collection.prototype.addDocumentToStructure = async function( /** * Update document's title and url in the documentStructure */ -Collection.prototype.updateDocument = async function( +Collection.prototype.updateDocument = async function ( updatedDocument: Document ) { if (!this.documentStructure) return; @@ -293,8 +293,8 @@ Collection.prototype.updateDocument = async function( const { id } = updatedDocument; - const updateChildren = documents => { - return documents.map(document => { + const updateChildren = (documents) => { + return documents.map((document) => { if (document.id === id) { document = { ...updatedDocument.toJSON(), @@ -320,12 +320,12 @@ Collection.prototype.updateDocument = async function( return this; }; -Collection.prototype.deleteDocument = async function(document) { +Collection.prototype.deleteDocument = async function (document) { await this.removeDocumentInStructure(document); await document.deleteWithChildren(); }; -Collection.prototype.removeDocumentInStructure = async function( +Collection.prototype.removeDocumentInStructure = async function ( document, options ) { @@ -339,7 +339,7 @@ Collection.prototype.removeDocumentInStructure = async function( const removeFromChildren = async (children, id) => { children = await Promise.all( - children.map(async childDocument => { + children.map(async (childDocument) => { return { ...childDocument, children: await removeFromChildren(childDocument.children, id), diff --git a/server/models/CollectionGroup.js b/server/models/CollectionGroup.js index 4a3ca253..521dc10d 100644 --- a/server/models/CollectionGroup.js +++ b/server/models/CollectionGroup.js @@ -18,7 +18,7 @@ const CollectionGroup = sequelize.define( } ); -CollectionGroup.associate = models => { +CollectionGroup.associate = (models) => { CollectionGroup.belongsTo(models.Collection, { as: "collection", foreignKey: "collectionId", diff --git a/server/models/CollectionUser.js b/server/models/CollectionUser.js index 73cd448d..4b440ede 100644 --- a/server/models/CollectionUser.js +++ b/server/models/CollectionUser.js @@ -17,7 +17,7 @@ const CollectionUser = sequelize.define( } ); -CollectionUser.associate = models => { +CollectionUser.associate = (models) => { CollectionUser.belongsTo(models.Collection, { as: "collection", foreignKey: "collectionId", diff --git a/server/models/Document.js b/server/models/Document.js index f2ce5bf2..4512e320 100644 --- a/server/models/Document.js +++ b/server/models/Document.js @@ -46,18 +46,18 @@ const createRevision = (doc, options = {}) => { ); }; -const createUrlId = doc => { +const createUrlId = (doc) => { return (doc.urlId = doc.urlId || randomstring.generate(10)); }; -const beforeCreate = async doc => { +const beforeCreate = async (doc) => { if (doc.version === undefined) { doc.version = DOCUMENT_VERSION; } return beforeSave(doc); }; -const beforeSave = async doc => { +const beforeSave = async (doc) => { const { emoji } = parseTitle(doc.text); // emoji in the title is split out for easier display @@ -123,7 +123,7 @@ const Document = sequelize.define( afterUpdate: createRevision, }, getterMethods: { - url: function() { + url: function () { const slugifiedTitle = slugify(this.title); return `/doc/${slugifiedTitle}-${this.urlId}`; }, @@ -133,7 +133,7 @@ const Document = sequelize.define( // Class methods -Document.associate = models => { +Document.associate = (models) => { Document.belongsTo(models.Collection, { as: "collection", foreignKey: "collectionId", @@ -185,7 +185,7 @@ Document.associate = models => { }, }, }); - Document.addScope("withCollection", userId => { + Document.addScope("withCollection", (userId) => { if (userId) { return { include: [ @@ -209,19 +209,19 @@ Document.associate = models => { { model: models.User, as: "updatedBy", paranoid: false }, ], }); - Document.addScope("withViews", userId => ({ + Document.addScope("withViews", (userId) => ({ include: [ { model: models.View, as: "views", where: { userId }, required: false }, ], })); - Document.addScope("withStarred", userId => ({ + Document.addScope("withStarred", (userId) => ({ include: [ { model: models.Star, as: "starred", where: { userId }, required: false }, ], })); }; -Document.findByPk = async function(id, options = {}) { +Document.findByPk = async function (id, options = {}) { // allow default preloading of collection membership if `userId` is passed in find options // almost every endpoint needs the collection membership to determine policy permissions. const scope = this.scope("withUnpublished", { @@ -322,7 +322,7 @@ Document.searchForTeam = async ( ], }); - return map(results, result => ({ + return map(results, (result) => ({ ranking: result.searchRanking, context: removeMarkdown(unescape(result.searchContext), { stripHTML: false, @@ -424,7 +424,7 @@ Document.searchForUser = async ( ], }); - return map(results, result => ({ + return map(results, (result) => ({ ranking: result.searchRanking, context: removeMarkdown(unescape(result.searchContext), { stripHTML: false, @@ -435,7 +435,7 @@ Document.searchForUser = async ( // Hooks -Document.addHook("beforeSave", async model => { +Document.addHook("beforeSave", async (model) => { if (!model.publishedAt || model.template) { return; } @@ -449,7 +449,7 @@ Document.addHook("beforeSave", async model => { model.collection = collection; }); -Document.addHook("afterCreate", async model => { +Document.addHook("afterCreate", async (model) => { if (!model.publishedAt || model.template) { return; } @@ -467,7 +467,7 @@ Document.addHook("afterCreate", async model => { // Instance methods -Document.prototype.toMarkdown = function() { +Document.prototype.toMarkdown = function () { const text = unescape(this.text); if (this.version) { @@ -477,7 +477,7 @@ Document.prototype.toMarkdown = function() { return text; }; -Document.prototype.migrateVersion = function() { +Document.prototype.migrateVersion = function () { let migrated = false; // migrate from document version 0 -> 1 @@ -505,13 +505,13 @@ Document.prototype.migrateVersion = function() { // Note: This method marks the document and it's children as deleted // in the database, it does not permanently delete them OR remove // from the collection structure. -Document.prototype.deleteWithChildren = async function(options) { +Document.prototype.deleteWithChildren = async function (options) { // Helper to destroy all child documents for a document const loopChildren = async (documentId, opts) => { const childDocuments = await Document.findAll({ where: { parentDocumentId: documentId }, }); - childDocuments.forEach(async child => { + childDocuments.forEach(async (child) => { await loopChildren(child.id, opts); await child.destroy(opts); }); @@ -521,15 +521,15 @@ Document.prototype.deleteWithChildren = async function(options) { await this.destroy(options); }; -Document.prototype.archiveWithChildren = async function(userId, options) { +Document.prototype.archiveWithChildren = async function (userId, options) { const archivedAt = new Date(); // Helper to archive all child documents for a document - const archiveChildren = async parentDocumentId => { + const archiveChildren = async (parentDocumentId) => { const childDocuments = await Document.findAll({ where: { parentDocumentId }, }); - childDocuments.forEach(async child => { + childDocuments.forEach(async (child) => { await archiveChildren(child.id); child.archivedAt = archivedAt; @@ -544,7 +544,7 @@ Document.prototype.archiveWithChildren = async function(userId, options) { return this.save(options); }; -Document.prototype.publish = async function(options) { +Document.prototype.publish = async function (options) { if (this.publishedAt) return this.save(options); const collection = await Collection.findByPk(this.collectionId); @@ -560,7 +560,7 @@ Document.prototype.publish = async function(options) { // Moves a document from being visible to the team within a collection // to the archived area, where it can be subsequently restored. -Document.prototype.archive = async function(userId) { +Document.prototype.archive = async function (userId) { // archive any children and remove from the document structure const collection = await this.getCollection(); await collection.removeDocumentInStructure(this); @@ -572,7 +572,7 @@ Document.prototype.archive = async function(userId) { }; // Restore an archived document back to being visible to the team -Document.prototype.unarchive = async function(userId) { +Document.prototype.unarchive = async function (userId) { const collection = await this.getCollection(); // check to see if the documents parent hasn't been archived also @@ -604,7 +604,7 @@ Document.prototype.unarchive = async function(userId) { }; // Delete a document, archived or otherwise. -Document.prototype.delete = function(options) { +Document.prototype.delete = function (options) { return sequelize.transaction(async (transaction: Transaction): Promise<*> => { if (!this.archivedAt) { // delete any children and remove from the document structure @@ -623,11 +623,11 @@ Document.prototype.delete = function(options) { }); }; -Document.prototype.getTimestamp = function() { +Document.prototype.getTimestamp = function () { return Math.round(new Date(this.updatedAt).getTime() / 1000); }; -Document.prototype.getSummary = function() { +Document.prototype.getSummary = function () { const plain = removeMarkdown(unescape(this.text), { stripHTML: false, }); @@ -641,7 +641,7 @@ Document.prototype.getSummary = function() { return notEmpty ? lines[1] : ""; }; -Document.prototype.toJSON = function() { +Document.prototype.toJSON = function () { // Warning: only use for new documents as order of children is // handled in the collection's documentStructure return { diff --git a/server/models/Event.js b/server/models/Event.js index d9721abb..846c2a05 100644 --- a/server/models/Event.js +++ b/server/models/Event.js @@ -14,7 +14,7 @@ const Event = sequelize.define("event", { data: DataTypes.JSONB, }); -Event.associate = models => { +Event.associate = (models) => { Event.belongsTo(models.User, { as: "user", foreignKey: "userId", @@ -37,14 +37,14 @@ Event.associate = models => { }); }; -Event.beforeCreate(event => { +Event.beforeCreate((event) => { if (event.ip) { // cleanup IPV6 representations of IPV4 addresses event.ip = event.ip.replace(/^::ffff:/, ""); } }); -Event.afterCreate(event => { +Event.afterCreate((event) => { events.add(event); }); diff --git a/server/models/Group.js b/server/models/Group.js index 2fea3813..b333547a 100644 --- a/server/models/Group.js +++ b/server/models/Group.js @@ -23,7 +23,7 @@ const Group = sequelize.define( timestamps: true, paranoid: true, validate: { - isUniqueNameInTeam: async function() { + isUniqueNameInTeam: async function () { const foundItem = await Group.findOne({ where: { teamId: this.teamId, @@ -39,7 +39,7 @@ const Group = sequelize.define( } ); -Group.associate = models => { +Group.associate = (models) => { Group.hasMany(models.GroupUser, { as: "groupMemberships", foreignKey: "groupId", diff --git a/server/models/GroupUser.js b/server/models/GroupUser.js index 1c0a92f7..b978afe6 100644 --- a/server/models/GroupUser.js +++ b/server/models/GroupUser.js @@ -10,7 +10,7 @@ const GroupUser = sequelize.define( } ); -GroupUser.associate = models => { +GroupUser.associate = (models) => { GroupUser.belongsTo(models.Group, { as: "group", foreignKey: "groupId", diff --git a/server/models/Integration.js b/server/models/Integration.js index b7dc24a9..a2136526 100644 --- a/server/models/Integration.js +++ b/server/models/Integration.js @@ -13,7 +13,7 @@ const Integration = sequelize.define("integration", { events: DataTypes.ARRAY(DataTypes.STRING), }); -Integration.associate = models => { +Integration.associate = (models) => { Integration.belongsTo(models.User, { as: "user", foreignKey: "userId", diff --git a/server/models/Notification.js b/server/models/Notification.js index 0174e0f1..bb1f00c1 100644 --- a/server/models/Notification.js +++ b/server/models/Notification.js @@ -22,7 +22,7 @@ const Notification = sequelize.define( } ); -Notification.associate = models => { +Notification.associate = (models) => { Notification.belongsTo(models.User, { as: "actor", foreignKey: "actorId", diff --git a/server/models/NotificationSetting.js b/server/models/NotificationSetting.js index 24cdd03c..490857f6 100644 --- a/server/models/NotificationSetting.js +++ b/server/models/NotificationSetting.js @@ -29,26 +29,24 @@ const NotificationSetting = sequelize.define( timestamps: true, updatedAt: false, getterMethods: { - unsubscribeUrl: function() { + unsubscribeUrl: function () { const token = NotificationSetting.getUnsubscribeToken(this.userId); - return `${process.env.URL}/api/notificationSettings.unsubscribe?token=${ - token - }&id=${this.id}`; + return `${process.env.URL}/api/notificationSettings.unsubscribe?token=${token}&id=${this.id}`; }, - unsubscribeToken: function() { + unsubscribeToken: function () { return NotificationSetting.getUnsubscribeToken(this.userId); }, }, } ); -NotificationSetting.getUnsubscribeToken = userId => { +NotificationSetting.getUnsubscribeToken = (userId) => { const hash = crypto.createHash("sha256"); hash.update(`${userId}-${process.env.SECRET_KEY}`); return hash.digest("hex"); }; -NotificationSetting.associate = models => { +NotificationSetting.associate = (models) => { NotificationSetting.belongsTo(models.User, { as: "user", foreignKey: "userId", diff --git a/server/models/Revision.js b/server/models/Revision.js index 9377d447..ee3b02b9 100644 --- a/server/models/Revision.js +++ b/server/models/Revision.js @@ -21,7 +21,7 @@ const Revision = sequelize.define("revision", { backup: DataTypes.TEXT, }); -Revision.associate = models => { +Revision.associate = (models) => { Revision.belongsTo(models.Document, { as: "document", foreignKey: "documentId", @@ -40,7 +40,7 @@ Revision.associate = models => { ); }; -Revision.prototype.migrateVersion = function() { +Revision.prototype.migrateVersion = function () { let migrated = false; // migrate from document version 0 -> 1 diff --git a/server/models/Share.js b/server/models/Share.js index 47edf755..b8ddec13 100644 --- a/server/models/Share.js +++ b/server/models/Share.js @@ -22,7 +22,7 @@ const Share = sequelize.define( } ); -Share.associate = models => { +Share.associate = (models) => { Share.belongsTo(models.User, { as: "user", foreignKey: "userId", @@ -44,7 +44,7 @@ Share.associate = models => { }); }; -Share.prototype.revoke = function(userId) { +Share.prototype.revoke = function (userId) { this.revokedAt = new Date(); this.revokedById = userId; return this.save(); diff --git a/server/models/Star.js b/server/models/Star.js index 74f3dc98..46355c11 100644 --- a/server/models/Star.js +++ b/server/models/Star.js @@ -9,7 +9,7 @@ const Star = sequelize.define("star", { }, }); -Star.associate = models => { +Star.associate = (models) => { Star.belongsTo(models.Document); Star.belongsTo(models.User); }; diff --git a/server/models/Team.js b/server/models/Team.js index 476ab46b..9567fc83 100644 --- a/server/models/Team.js +++ b/server/models/Team.js @@ -83,13 +83,13 @@ const Team = sequelize.define( } ); -Team.associate = models => { +Team.associate = (models) => { Team.hasMany(models.Collection, { as: "collections" }); Team.hasMany(models.Document, { as: "documents" }); Team.hasMany(models.User, { as: "users" }); }; -const uploadAvatar = async model => { +const uploadAvatar = async (model) => { const endpoint = publicS3Endpoint(); const { avatarUrl } = model; @@ -112,7 +112,7 @@ const uploadAvatar = async model => { } }; -Team.prototype.provisionSubdomain = async function(subdomain) { +Team.prototype.provisionSubdomain = async function (subdomain) { if (this.subdomain) return this.subdomain; let append = 0; @@ -129,7 +129,7 @@ Team.prototype.provisionSubdomain = async function(subdomain) { return subdomain; }; -Team.prototype.provisionFirstCollection = async function(userId) { +Team.prototype.provisionFirstCollection = async function (userId) { const collection = await Collection.create({ name: "Welcome", description: @@ -168,11 +168,11 @@ Team.prototype.provisionFirstCollection = async function(userId) { } }; -Team.prototype.addAdmin = async function(user: User) { +Team.prototype.addAdmin = async function (user: User) { return user.update({ isAdmin: true }); }; -Team.prototype.removeAdmin = async function(user: User) { +Team.prototype.removeAdmin = async function (user: User) { const res = await User.findAndCountAll({ where: { teamId: this.id, @@ -190,7 +190,7 @@ Team.prototype.removeAdmin = async function(user: User) { } }; -Team.prototype.suspendUser = async function(user: User, admin: User) { +Team.prototype.suspendUser = async function (user: User, admin: User) { if (user.id === admin.id) throw new ValidationError("Unable to suspend the current user"); return user.update({ @@ -199,20 +199,20 @@ Team.prototype.suspendUser = async function(user: User, admin: User) { }); }; -Team.prototype.activateUser = async function(user: User, admin: User) { +Team.prototype.activateUser = async function (user: User, admin: User) { return user.update({ suspendedById: null, suspendedAt: null, }); }; -Team.prototype.collectionIds = async function(paranoid: boolean = true) { +Team.prototype.collectionIds = async function (paranoid: boolean = true) { let models = await Collection.findAll({ attributes: ["id", "private"], where: { teamId: this.id, private: false }, paranoid, }); - return models.map(c => c.id); + return models.map((c) => c.id); }; Team.beforeSave(uploadAvatar); diff --git a/server/models/User.js b/server/models/User.js index 4a1a49c0..9e835a14 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -59,7 +59,7 @@ const User = sequelize.define( ); // Class methods -User.associate = models => { +User.associate = (models) => { User.hasMany(models.ApiKey, { as: "apiKeys", onDelete: "cascade" }); User.hasMany(models.NotificationSetting, { as: "notificationSettings", @@ -71,7 +71,7 @@ User.associate = models => { }; // Instance methods -User.prototype.collectionIds = async function(paranoid: boolean = true) { +User.prototype.collectionIds = async function (paranoid: boolean = true) { const collectionStubs = await Collection.scope({ method: ["withMembership", this.id], }).findAll({ @@ -82,15 +82,15 @@ User.prototype.collectionIds = async function(paranoid: boolean = true) { return collectionStubs .filter( - c => + (c) => !c.private || c.memberships.length > 0 || c.collectionGroupMemberships.length > 0 ) - .map(c => c.id); + .map((c) => c.id); }; -User.prototype.updateActiveAt = function(ip) { +User.prototype.updateActiveAt = function (ip) { const fiveMinutesAgo = subMinutes(new Date(), 5); // ensure this is updated only every few minutes otherwise @@ -102,17 +102,17 @@ User.prototype.updateActiveAt = function(ip) { } }; -User.prototype.updateSignedIn = function(ip) { +User.prototype.updateSignedIn = function (ip) { this.lastSignedInAt = new Date(); this.lastSignedInIp = ip; return this.save({ hooks: false }); }; -User.prototype.getJwtToken = function() { +User.prototype.getJwtToken = function () { return JWT.sign({ id: this.id }, this.jwtSecret); }; -User.prototype.getEmailSigninToken = function() { +User.prototype.getEmailSigninToken = function () { if (this.service && this.service !== "email") { throw new Error("Cannot generate email signin token for OAuth user"); } @@ -123,7 +123,7 @@ User.prototype.getEmailSigninToken = function() { ); }; -const uploadAvatar = async model => { +const uploadAvatar = async (model) => { const endpoint = publicS3Endpoint(); const { avatarUrl } = model; @@ -147,7 +147,7 @@ const uploadAvatar = async model => { } }; -const setRandomJwtSecret = model => { +const setRandomJwtSecret = (model) => { model.jwtSecret = crypto.randomBytes(64).toString("hex"); }; @@ -179,7 +179,7 @@ const removeIdentifyingInfo = async (model, options) => { await model.save({ hooks: false, transaction: options.transaction }); }; -const checkLastAdmin = async model => { +const checkLastAdmin = async (model) => { const teamId = model.teamId; if (model.isAdmin) { @@ -198,7 +198,7 @@ User.beforeDestroy(checkLastAdmin); User.beforeDestroy(removeIdentifyingInfo); User.beforeSave(uploadAvatar); User.beforeCreate(setRandomJwtSecret); -User.afterCreate(async user => { +User.afterCreate(async (user) => { const team = await Team.findByPk(user.teamId); // From Slack support: diff --git a/server/models/View.js b/server/models/View.js index 4de79ad4..ce87709d 100644 --- a/server/models/View.js +++ b/server/models/View.js @@ -25,12 +25,12 @@ const View = sequelize.define( } ); -View.associate = models => { +View.associate = (models) => { View.belongsTo(models.Document); View.belongsTo(models.User); }; -View.increment = async where => { +View.increment = async (where) => { const [model, created] = await View.findOrCreate({ where }); if (!created) { model.count += 1; @@ -39,7 +39,7 @@ View.increment = async where => { return model; }; -View.findByDocument = async documentId => { +View.findByDocument = async (documentId) => { return View.findAll({ where: { documentId }, order: [["updatedAt", "DESC"]], @@ -52,7 +52,7 @@ View.findByDocument = async documentId => { }); }; -View.findRecentlyEditingByDocument = async documentId => { +View.findRecentlyEditingByDocument = async (documentId) => { return View.findAll({ where: { documentId, diff --git a/server/models/index.js b/server/models/index.js index 73c219aa..43b1cd53 100644 --- a/server/models/index.js +++ b/server/models/index.js @@ -44,7 +44,7 @@ const models = { }; // based on https://github.com/sequelize/express-example/blob/master/models/index.js -Object.keys(models).forEach(modelName => { +Object.keys(models).forEach((modelName) => { if ("associate" in models[modelName]) { models[modelName].associate(models); } diff --git a/server/policies/collection.js b/server/policies/collection.js index 7147fb29..8b7449ed 100644 --- a/server/policies/collection.js +++ b/server/policies/collection.js @@ -23,7 +23,7 @@ allow(User, ["read", "export"], Collection, (user, collection) => { collection.collectionGroupMemberships ); - return some(allMemberships, m => + return some(allMemberships, (m) => ["read", "read_write", "maintainer"].includes(m.permission) ); } @@ -45,7 +45,7 @@ allow(User, ["publish", "update"], Collection, (user, collection) => { collection.collectionGroupMemberships ); - return some(allMemberships, m => + return some(allMemberships, (m) => ["read_write", "maintainer"].includes(m.permission) ); } @@ -66,7 +66,7 @@ allow(User, "delete", Collection, (user, collection) => { collection.collectionGroupMemberships ); - return some(allMemberships, m => + return some(allMemberships, (m) => ["read_write", "maintainer"].includes(m.permission) ); } diff --git a/server/policies/group.js b/server/policies/group.js index a8cc124d..8d484397 100644 --- a/server/policies/group.js +++ b/server/policies/group.js @@ -5,7 +5,7 @@ import { AdminRequiredError } from "../errors"; const { allow } = policy; -allow(User, ["create"], Group, actor => { +allow(User, ["create"], Group, (actor) => { if (actor.isAdmin) return true; throw new AdminRequiredError(); }); @@ -19,7 +19,7 @@ allow(User, ["update", "delete"], Group, (actor, group) => { allow(User, ["read"], Group, (actor, group) => { if (!group || actor.teamId !== group.teamId) return false; if (actor.isAdmin) return true; - if (group.groupMemberships.filter(gm => gm.userId === actor.id).length) { + if (group.groupMemberships.filter((gm) => gm.userId === actor.id).length) { return true; } return false; diff --git a/server/policies/index.js b/server/policies/index.js index 351fe148..7be7f01e 100644 --- a/server/policies/index.js +++ b/server/policies/index.js @@ -18,17 +18,17 @@ type Policy = { }; /* -* Given a user and a model – output an object which describes the actions the -* user may take against the model. This serialized policy is used for testing -* and sent in API responses to allow clients to adjust which UI is displayed. -*/ + * Given a user and a model – output an object which describes the actions the + * user may take against the model. This serialized policy is used for testing + * and sent in API responses to allow clients to adjust which UI is displayed. + */ export function serialize( model: User, target: Team | Collection | Document | Group ): Policy { let output = {}; - abilities.forEach(ability => { + abilities.forEach((ability) => { if (model instanceof ability.model && target instanceof ability.target) { let response = true; try { diff --git a/server/policies/team.js b/server/policies/team.js index c7b04885..0f474b06 100644 --- a/server/policies/team.js +++ b/server/policies/team.js @@ -12,18 +12,18 @@ allow(User, "share", Team, (user, team) => { return team.sharing; }); -allow(User, "auditLog", Team, user => { +allow(User, "auditLog", Team, (user) => { if (user.isAdmin) return true; return false; }); -allow(User, "invite", Team, user => { +allow(User, "invite", Team, (user) => { if (user.isAdmin) return true; return false; }); // ??? policy for creating new groups, I don't know how to do this other than on the team level -allow(User, "group", Team, user => { +allow(User, "group", Team, (user) => { if (user.isAdmin) return true; throw new AdminRequiredError(); }); diff --git a/server/policies/user.js b/server/policies/user.js index 43e78cf8..6098da15 100644 --- a/server/policies/user.js +++ b/server/policies/user.js @@ -12,7 +12,7 @@ allow( (actor, user) => user && user.teamId === actor.teamId ); -allow(User, "invite", User, actor => { +allow(User, "invite", User, (actor) => { return true; }); diff --git a/server/presenters/collection.js b/server/presenters/collection.js index 91372cff..c8bea575 100644 --- a/server/presenters/collection.js +++ b/server/presenters/collection.js @@ -12,7 +12,7 @@ type Document = { const sortDocuments = (documents: Document[]): Document[] => { const orderedDocs = naturalSort(documents, "title"); - return orderedDocs.map(document => ({ + return orderedDocs.map((document) => ({ ...document, children: sortDocuments(document.children), })); diff --git a/server/presenters/document.js b/server/presenters/document.js index 89568957..a08f37f4 100644 --- a/server/presenters/document.js +++ b/server/presenters/document.js @@ -13,7 +13,7 @@ const attachmentRegex = /!\[.*\]\(\/api\/attachments\.redirect\?id=(?.*)\)/g // replaces attachments.redirect urls with signed/authenticated url equivalents async function replaceImageAttachments(text) { const attachmentIds = [...text.matchAll(attachmentRegex)].map( - match => match.groups && match.groups.id + (match) => match.groups && match.groups.id ); for (const id of attachmentIds) { diff --git a/server/presenters/policy.js b/server/presenters/policy.js index 11160310..6ed13bd7 100644 --- a/server/presenters/policy.js +++ b/server/presenters/policy.js @@ -6,7 +6,7 @@ type Policy = { id: string, abilities: { [key: string]: boolean } }; export default function present(user: User, objects: Object[]): Policy[] { const { serialize } = require("../policies"); - return objects.map(object => ({ + return objects.map((object) => ({ id: object.id, abilities: serialize(user, object), })); diff --git a/server/routes.js b/server/routes.js index 5934e0aa..461384e8 100644 --- a/server/routes.js +++ b/server/routes.js @@ -16,13 +16,13 @@ const koa = new Koa(); const router = new Router(); const readFile = util.promisify(fs.readFile); -const readIndexFile = async ctx => { +const readIndexFile = async (ctx) => { if (isProduction) { return readFile(path.join(__dirname, "../dist/index.html")); } const middleware = ctx.devMiddleware; - await new Promise(resolve => middleware.waitUntilValid(resolve)); + await new Promise((resolve) => middleware.waitUntilValid(resolve)); return new Promise((resolve, reject) => { middleware.fileSystem.readFile( @@ -44,10 +44,10 @@ koa.use( }) ); -router.get("/_health", ctx => (ctx.body = "OK")); +router.get("/_health", (ctx) => (ctx.body = "OK")); if (process.env.NODE_ENV === "production") { - router.get("/static/*", async ctx => { + router.get("/static/*", async (ctx) => { ctx.set({ "Cache-Control": `max-age=${356 * 24 * 60 * 60}`, }); @@ -59,11 +59,11 @@ if (process.env.NODE_ENV === "production") { }); } -router.get("/robots.txt", ctx => { +router.get("/robots.txt", (ctx) => { ctx.body = robotsResponse(ctx); }); -router.get("/opensearch.xml", ctx => { +router.get("/opensearch.xml", (ctx) => { ctx.type = "text/xml"; ctx.body = opensearchResponse(); }); diff --git a/server/services/backlinks.js b/server/services/backlinks.js index 20398160..e704ac9c 100644 --- a/server/services/backlinks.js +++ b/server/services/backlinks.js @@ -13,7 +13,7 @@ export default class Backlinks { const linkIds = parseDocumentIds(document.text); await Promise.all( - linkIds.map(async linkId => { + linkIds.map(async (linkId) => { const linkedDocument = await Document.findByPk(linkId); if (linkedDocument.id === event.documentId) return; @@ -53,7 +53,7 @@ export default class Backlinks { // add any new backlinks that were created await Promise.all( - addedLinkIds.map(async linkId => { + addedLinkIds.map(async (linkId) => { const linkedDocument = await Document.findByPk(linkId); if (linkedDocument.id === event.documentId) return; @@ -71,7 +71,7 @@ export default class Backlinks { // delete any backlinks that were removed await Promise.all( - removedLinkIds.map(async linkId => { + removedLinkIds.map(async (linkId) => { const document = await Document.findByPk(linkId, { paranoid: false, }); @@ -102,7 +102,7 @@ export default class Backlinks { }); await Promise.all( - backlinks.map(async backlink => { + backlinks.map(async (backlink) => { const previousUrl = `/doc/${slugify(previousRevision.title)}-${ document.urlId }`; diff --git a/server/services/index.js b/server/services/index.js index eca6537c..f6ef7e97 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -6,15 +6,14 @@ import path from "path"; const log = debug("services"); const services = {}; -fs - .readdirSync(__dirname) +fs.readdirSync(__dirname) .filter( - file => + (file) => file.indexOf(".") !== 0 && file !== path.basename(__filename) && !file.includes(".test") ) - .forEach(fileName => { + .forEach((fileName) => { const servicePath = path.join(__dirname, fileName); const name = path.basename(servicePath.replace(/\.js$/, "")); // $FlowIssue diff --git a/server/services/notifications.js b/server/services/notifications.js index 21f6dad5..fdd62c5f 100644 --- a/server/services/notifications.js +++ b/server/services/notifications.js @@ -58,7 +58,7 @@ export default class Notifications { const eventName = event.name === "documents.publish" ? "published" : "updated"; - notificationSettings.forEach(setting => { + notificationSettings.forEach((setting) => { // For document updates we only want to send notifications if // the document has been edited by the user with this notification setting // This could be replaced with ability to "follow" in the future @@ -111,7 +111,7 @@ export default class Notifications { ], }); - notificationSettings.forEach(setting => + notificationSettings.forEach((setting) => mailer.collectionNotification({ to: setting.user.email, eventName: "created", diff --git a/server/services/slack.js b/server/services/slack.js index 7fdcb5f7..fb012b45 100644 --- a/server/services/slack.js +++ b/server/services/slack.js @@ -41,9 +41,7 @@ export default class Slack { "Content-Type": "application/json", }, body: JSON.stringify({ - text: `👋 Hey there! When documents are published or updated in the *${ - collection.name - }* collection on Outline they will be posted to this channel!`, + text: `👋 Hey there! When documents are published or updated in the *${collection.name}* collection on Outline they will be posted to this channel!`, attachments: [ { color: collection.color, diff --git a/server/services/websockets.js b/server/services/websockets.js index 6008730a..5b8e97b5 100644 --- a/server/services/websockets.js +++ b/server/services/websockets.js @@ -127,7 +127,7 @@ export default class Websockets { }, paranoid: false, }); - documents.forEach(document => { + documents.forEach((document) => { socketio.to(`collection-${document.collectionId}`).emit("entities", { event: event.name, documentIds: [ @@ -138,7 +138,7 @@ export default class Websockets { ], }); }); - event.data.collectionIds.forEach(collectionId => { + event.data.collectionIds.forEach((collectionId) => { socketio.to(`collection-${collectionId}`).emit("entities", { event: event.name, collectionIds: [{ id: collectionId }], diff --git a/server/test/support.js b/server/test/support.js index 2e1a0139..e163ac06 100644 --- a/server/test/support.js +++ b/server/test/support.js @@ -4,7 +4,7 @@ import { sequelize } from "../sequelize"; export function flushdb() { const sql = sequelize.getQueryInterface(); - const tables = Object.keys(sequelize.models).map(model => { + const tables = Object.keys(sequelize.models).map((model) => { const n = sequelize.models[model].getTableName(); return sql.quoteTable(typeof n === "string" ? n : n.tableName); }); diff --git a/server/utils/opensearch.js b/server/utils/opensearch.js index 4c8a3133..25a28890 100644 --- a/server/utils/opensearch.js +++ b/server/utils/opensearch.js @@ -5,12 +5,8 @@ export const opensearchResponse = (): string => { Outline Search Outline UTF-8 - ${ - process.env.URL - }/favicon.ico - + ${process.env.URL}/favicon.ico + ${process.env.URL}/search `; diff --git a/server/utils/prefetchTags.js b/server/utils/prefetchTags.js index e2c5ba99..e3b3709f 100644 --- a/server/utils/prefetchTags.js +++ b/server/utils/prefetchTags.js @@ -20,7 +20,7 @@ try { "utf8" ); const manifestData = JSON.parse(manifest); - Object.values(manifestData).forEach(filename => { + Object.values(manifestData).forEach((filename) => { if (typeof filename !== "string") return; if (filename.endsWith(".js")) { prefetchTags.push( diff --git a/server/utils/updates.js b/server/utils/updates.js index 8b4052f9..8bff9cc2 100644 --- a/server/utils/updates.js +++ b/server/utils/updates.js @@ -16,10 +16,7 @@ export default async () => { "SECRET_KEY or URL env var is not set" ); const secret = process.env.SECRET_KEY.slice(0, 6) + process.env.URL; - const id = crypto - .createHash("sha256") - .update(secret) - .digest("hex"); + const id = crypto.createHash("sha256").update(secret).digest("hex"); const [ userCount, diff --git a/shared/styles/globals.js b/shared/styles/globals.js index a55ab1e8..f8b4d0e4 100644 --- a/shared/styles/globals.js +++ b/shared/styles/globals.js @@ -30,7 +30,7 @@ export default createGlobalStyle` body { font-size: 16px; line-height: 1.5; - color: ${props => props.theme.text}; + color: ${(props) => props.theme.text}; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; @@ -38,7 +38,7 @@ export default createGlobalStyle` } a { - color: ${props => props.theme.link}; + color: ${(props) => props.theme.link}; text-decoration: none; cursor: pointer; } @@ -74,6 +74,6 @@ export default createGlobalStyle` hr { border: 0; height: 0; - border-top: 1px solid ${props => props.theme.divider}; + border-top: 1px solid ${(props) => props.theme.divider}; } `; diff --git a/shared/utils/naturalSort.js b/shared/utils/naturalSort.js index 03e7d993..ba7a594a 100644 --- a/shared/utils/naturalSort.js +++ b/shared/utils/naturalSort.js @@ -11,7 +11,7 @@ const sorter = naturalSort(); function getSortByField( item: T, - keyOrCallback: string | (T => string) + keyOrCallback: string | ((T) => string) ) { if (typeof keyOrCallback === "string") { return deburr(item[keyOrCallback]); @@ -22,7 +22,7 @@ function getSortByField( function naturalSortBy( items: T[], - key: string | (T => string), + key: string | ((T) => string), sortOptions?: NaturalSortOptions ): T[] { if (!items) return []; diff --git a/shared/utils/parseDocumentIds.js b/shared/utils/parseDocumentIds.js index f1eaaa73..6f3147e6 100644 --- a/shared/utils/parseDocumentIds.js +++ b/shared/utils/parseDocumentIds.js @@ -9,7 +9,7 @@ export default function parseDocumentIds(text: string): string[] { // get text nodes if (node.type.name === "text") { // get marks for text nodes - node.marks.forEach(mark => { + node.marks.forEach((mark) => { // any of the marks links? if (mark.type.name === "link") { const { href } = mark.attrs; diff --git a/shared/utils/routeHelpers.js b/shared/utils/routeHelpers.js index ec25200b..8bf94623 100644 --- a/shared/utils/routeHelpers.js +++ b/shared/utils/routeHelpers.js @@ -20,7 +20,7 @@ export function slackAuth( }; const urlParams = Object.keys(params) - .map(key => `${key}=${encodeURIComponent(params[key])}`) + .map((key) => `${key}=${encodeURIComponent(params[key])}`) .join("&"); return `${baseUrl}?${urlParams}`; diff --git a/yarn.lock b/yarn.lock index 8e76961f..21d4b189 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7620,16 +7620,16 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8" - integrity sha512-fHWjCwoRZgjP1rvLP7OGqOznq7xH1sHMQUFLX8qLRO79hI57+6xbc5vB904LxEkCfgFgyr3vv06JkafgCSzoZg== - prettier@^1.16.4, prettier@^1.18.2: version "1.19.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +prettier@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" + integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== + pretty-error@^2.0.2: version "2.1.1" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"