Merge develop
This commit is contained in:
@@ -45,6 +45,7 @@ AWS_REGION=xx-xxxx-x
|
||||
AWS_S3_UPLOAD_BUCKET_URL=http://s3:4569
|
||||
AWS_S3_UPLOAD_BUCKET_NAME=bucket_name_here
|
||||
AWS_S3_UPLOAD_MAX_SIZE=26214400
|
||||
AWS_S3_FORCE_PATH_STYLE=true
|
||||
# uploaded s3 objects permission level, default is private
|
||||
# set to "public-read" to allow public access
|
||||
AWS_S3_ACL=private
|
||||
|
||||
5
app.json
5
app.json
@@ -92,6 +92,11 @@
|
||||
"value": "26214400",
|
||||
"required": false
|
||||
},
|
||||
"AWS_S3_FORCE_PATH_STYLE": {
|
||||
"description": "Use path-style URL's for connecting to S3 instead of subdomain. This is useful for S3-compatible storage.",
|
||||
"value": "true",
|
||||
"required": false
|
||||
},
|
||||
"AWS_REGION": {
|
||||
"value": "us-east-1",
|
||||
"description": "Region in which the above S3 bucket exists",
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
// @flow
|
||||
import ArrowKeyNavigation from "boundless-arrow-key-navigation";
|
||||
import { observable, action } from "mobx";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import { action, observable } from "mobx";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { CloseIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { type RouterHistory, type Match } from "react-router-dom";
|
||||
import { type Match, Redirect, type RouterHistory } from "react-router-dom";
|
||||
import { Waypoint } from "react-waypoint";
|
||||
import styled from "styled-components";
|
||||
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import { DEFAULT_PAGINATION_LIMIT } from "stores/BaseStore";
|
||||
import DocumentsStore from "stores/DocumentsStore";
|
||||
import RevisionsStore from "stores/RevisionsStore";
|
||||
|
||||
import Button from "components/Button";
|
||||
import Flex from "components/Flex";
|
||||
import { ListPlaceholder } from "components/LoadingPlaceholder";
|
||||
import Revision from "./components/Revision";
|
||||
import { documentHistoryUrl } from "utils/routeHelpers";
|
||||
import { documentHistoryUrl, documentUrl } from "utils/routeHelpers";
|
||||
|
||||
type Props = {
|
||||
match: Match,
|
||||
@@ -29,6 +32,7 @@ class DocumentHistory extends React.Component<Props> {
|
||||
@observable isFetching: boolean = false;
|
||||
@observable offset: number = 0;
|
||||
@observable allowLoadMore: boolean = true;
|
||||
@observable redirectTo: ?string;
|
||||
|
||||
async componentDidMount() {
|
||||
await this.loadMoreResults();
|
||||
@@ -86,15 +90,34 @@ class DocumentHistory extends React.Component<Props> {
|
||||
return this.props.revisions.getDocumentRevisions(document.id);
|
||||
}
|
||||
|
||||
onCloseHistory = () => {
|
||||
const document = this.props.documents.getByUrl(
|
||||
this.props.match.params.documentSlug
|
||||
);
|
||||
|
||||
this.redirectTo = documentUrl(document);
|
||||
};
|
||||
|
||||
render() {
|
||||
const document = this.props.documents.getByUrl(
|
||||
this.props.match.params.documentSlug
|
||||
);
|
||||
const showLoading = (!this.isLoaded && this.isFetching) || !document;
|
||||
|
||||
if (this.redirectTo) return <Redirect to={this.redirectTo} push />;
|
||||
|
||||
return (
|
||||
<Sidebar>
|
||||
<Wrapper column>
|
||||
<Header>
|
||||
<Title>History</Title>
|
||||
<Button
|
||||
icon={<CloseIcon />}
|
||||
onClick={this.onCloseHistory}
|
||||
borderOnHover
|
||||
neutral
|
||||
/>
|
||||
</Header>
|
||||
{showLoading ? (
|
||||
<Loading>
|
||||
<ListPlaceholder count={5} />
|
||||
@@ -140,10 +163,36 @@ const Wrapper = styled(Flex)`
|
||||
`;
|
||||
|
||||
const Sidebar = styled(Flex)`
|
||||
display: none;
|
||||
background: ${(props) => props.theme.background};
|
||||
min-width: ${(props) => props.theme.sidebarWidth};
|
||||
border-left: 1px solid ${(props) => props.theme.divider};
|
||||
z-index: 1;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
display: flex;
|
||||
`};
|
||||
`;
|
||||
|
||||
const Title = styled(Flex)`
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 0;
|
||||
flex-grow: 1;
|
||||
`;
|
||||
|
||||
const Header = styled(Flex)`
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid ${(props) => props.theme.divider};
|
||||
color: ${(props) => props.theme.text};
|
||||
`;
|
||||
|
||||
export default inject("documents", "revisions")(DocumentHistory);
|
||||
|
||||
@@ -9,6 +9,7 @@ import breakpoint from "styled-components-breakpoint";
|
||||
import { fadeAndScaleIn } from "shared/styles/animations";
|
||||
import Flex from "components/Flex";
|
||||
import NudeButton from "components/NudeButton";
|
||||
import Scrollable from "components/Scrollable";
|
||||
|
||||
ReactModal.setAppElement("#root");
|
||||
|
||||
@@ -27,7 +28,8 @@ const GlobalStyles = createGlobalStyle`
|
||||
}
|
||||
|
||||
${breakpoint("tablet")`
|
||||
.ReactModalPortal + .ReactModalPortal {
|
||||
.ReactModalPortal + .ReactModalPortal,
|
||||
.ReactModalPortal + [data-react-modal-body-trap] + .ReactModalPortal {
|
||||
.ReactModal__Overlay {
|
||||
margin-left: 12px;
|
||||
box-shadow: 0 -2px 10px ${(props) => props.theme.shadow};
|
||||
@@ -36,13 +38,15 @@ const GlobalStyles = createGlobalStyle`
|
||||
}
|
||||
}
|
||||
|
||||
.ReactModalPortal + .ReactModalPortal + .ReactModalPortal {
|
||||
.ReactModalPortal + .ReactModalPortal + .ReactModalPortal,
|
||||
.ReactModalPortal + .ReactModalPortal + [data-react-modal-body-trap] + .ReactModalPortal {
|
||||
.ReactModal__Overlay {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.ReactModalPortal + .ReactModalPortal + .ReactModalPortal + .ReactModalPortal {
|
||||
.ReactModalPortal + .ReactModalPortal + .ReactModalPortal + .ReactModalPortal,
|
||||
.ReactModalPortal + .ReactModalPortal + .ReactModalPortal + [data-react-modal-body-trap] + .ReactModalPortal {
|
||||
.ReactModal__Overlay {
|
||||
margin-left: 36px;
|
||||
}
|
||||
@@ -72,10 +76,11 @@ const Modal = ({
|
||||
isOpen={isOpen}
|
||||
{...rest}
|
||||
>
|
||||
<Content onClick={(ev) => ev.stopPropagation()} column>
|
||||
{title && <h1>{title}</h1>}
|
||||
|
||||
{children}
|
||||
<Content>
|
||||
<Centered onClick={(ev) => ev.stopPropagation()} column>
|
||||
{title && <h1>{title}</h1>}
|
||||
{children}
|
||||
</Centered>
|
||||
</Content>
|
||||
<Back onClick={onRequestClose}>
|
||||
<BackIcon size={32} color="currentColor" />
|
||||
@@ -89,10 +94,20 @@ const Modal = ({
|
||||
);
|
||||
};
|
||||
|
||||
const Content = styled(Flex)`
|
||||
const Content = styled(Scrollable)`
|
||||
width: 100%;
|
||||
padding: 8vh 2rem 2rem;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
padding-top: 13vh;
|
||||
`};
|
||||
`;
|
||||
|
||||
const Centered = styled(Flex)`
|
||||
width: 640px;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
`;
|
||||
|
||||
const StyledModal = styled(ReactModal)`
|
||||
@@ -107,16 +122,9 @@ const StyledModal = styled(ReactModal)`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background: ${(props) => props.theme.background};
|
||||
transition: ${(props) => props.theme.backgroundTransition};
|
||||
padding: 8vh 2rem 2rem;
|
||||
outline: none;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
padding-top: 13vh;
|
||||
`};
|
||||
`;
|
||||
|
||||
const Text = styled.span`
|
||||
@@ -147,7 +155,7 @@ const Close = styled(NudeButton)`
|
||||
`;
|
||||
|
||||
const Back = styled(NudeButton)`
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
display: none;
|
||||
align-items: center;
|
||||
top: 2rem;
|
||||
|
||||
@@ -42,20 +42,23 @@ class PathToDocument extends React.Component<Props> {
|
||||
return (
|
||||
<Component ref={ref} onClick={this.handleClick} href="" selectable>
|
||||
{collection && <CollectionIcon collection={collection} />}
|
||||
|
||||
{result.path
|
||||
.map((doc) => <Title key={doc.id}>{doc.title}</Title>)
|
||||
.reduce((prev, curr) => [prev, <StyledGoToIcon />, curr])}
|
||||
{document && (
|
||||
<Flex>
|
||||
<DocumentTitle>
|
||||
{" "}
|
||||
<StyledGoToIcon /> <Title>{document.title}</Title>
|
||||
</Flex>
|
||||
</DocumentTitle>
|
||||
)}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DocumentTitle = styled(Flex)``;
|
||||
|
||||
const Title = styled.span`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -79,13 +82,20 @@ const ResultWrapper = styled.div`
|
||||
const ResultWrapperLink = styled(ResultWrapper.withComponent("a"))`
|
||||
margin: 0 -8px;
|
||||
padding: 8px 4px;
|
||||
border-radius: 8px;
|
||||
|
||||
${DocumentTitle} {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background: ${(props) => props.theme.listItemHoverBackground};
|
||||
outline: none;
|
||||
|
||||
${DocumentTitle} {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// @flow
|
||||
import "mobx-react-lite/batchingForReactDom";
|
||||
import { Provider } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { render } from "react-dom";
|
||||
|
||||
@@ -127,6 +127,7 @@ class CollectionMenu extends React.Component<Props> {
|
||||
collection={collection}
|
||||
onSubmit={this.handleMembersModalClose}
|
||||
handleEditCollectionOpen={this.handleEditCollectionOpen}
|
||||
onEdit={this.handleEditCollectionOpen}
|
||||
/>
|
||||
</Modal>
|
||||
<DropdownMenu onOpen={onOpen} onClose={onClose} position={position}>
|
||||
|
||||
@@ -132,7 +132,7 @@ class CollectionMembers extends React.Component<Props> {
|
||||
collection. You can make this collection visible to the entire
|
||||
team by{" "}
|
||||
<a role="button" onClick={this.props.onEdit}>
|
||||
changing its visibility
|
||||
changing the visibility
|
||||
</a>
|
||||
.
|
||||
</HelpText>
|
||||
|
||||
@@ -18,6 +18,7 @@ import Branding from "components/Branding";
|
||||
import ErrorBoundary from "components/ErrorBoundary";
|
||||
import Flex from "components/Flex";
|
||||
import LoadingIndicator from "components/LoadingIndicator";
|
||||
import LoadingPlaceholder from "components/LoadingPlaceholder";
|
||||
import Notice from "components/Notice";
|
||||
import PageTitle from "components/PageTitle";
|
||||
import Time from "components/Time";
|
||||
@@ -67,7 +68,7 @@ type Props = {
|
||||
|
||||
@observer
|
||||
class DocumentScene extends React.Component<Props> {
|
||||
@observable editor: ?any;
|
||||
@observable editor = React.createRef();
|
||||
@observable isUploading: boolean = false;
|
||||
@observable isSaving: boolean = false;
|
||||
@observable isPublishing: boolean = false;
|
||||
@@ -380,7 +381,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
)}
|
||||
<MaxWidth
|
||||
archived={document.isArchived}
|
||||
tocVisible={ui.tocVisible}
|
||||
tocVisible={ui.tocVisible && readOnly}
|
||||
column
|
||||
auto
|
||||
>
|
||||
@@ -412,50 +413,52 @@ class DocumentScene extends React.Component<Props> {
|
||||
)}
|
||||
</Notice>
|
||||
)}
|
||||
<Flex auto={!readOnly}>
|
||||
{ui.tocVisible && readOnly && (
|
||||
<Contents
|
||||
headings={this.editor ? this.editor.getHeadings() : []}
|
||||
<React.Suspense fallback={<LoadingPlaceholder />}>
|
||||
<Flex auto={!readOnly}>
|
||||
{ui.tocVisible && readOnly && (
|
||||
<Contents
|
||||
headings={
|
||||
this.editor.current
|
||||
? this.editor.current.getHeadings()
|
||||
: []
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Editor
|
||||
id={document.id}
|
||||
innerRef={this.editor}
|
||||
isShare={isShare}
|
||||
isDraft={document.isDraft}
|
||||
template={document.isTemplate}
|
||||
key={[injectTemplate, disableEmbeds].join("-")}
|
||||
title={revision ? revision.title : this.title}
|
||||
document={document}
|
||||
value={readOnly ? value : undefined}
|
||||
defaultValue={value}
|
||||
disableEmbeds={disableEmbeds}
|
||||
onImageUploadStart={this.onImageUploadStart}
|
||||
onImageUploadStop={this.onImageUploadStop}
|
||||
onSearchLink={this.props.onSearchLink}
|
||||
onCreateLink={this.props.onCreateLink}
|
||||
onChangeTitle={this.onChangeTitle}
|
||||
onChange={this.onChange}
|
||||
onSave={this.onSave}
|
||||
onPublish={this.onPublish}
|
||||
onCancel={this.goBack}
|
||||
readOnly={readOnly}
|
||||
readOnlyWriteCheckboxes={readOnly && abilities.update}
|
||||
ui={this.props.ui}
|
||||
/>
|
||||
</Flex>
|
||||
{readOnly && !isShare && !revision && (
|
||||
<>
|
||||
<MarkAsViewed document={document} />
|
||||
<ReferencesWrapper isOnlyTitle={document.isOnlyTitle}>
|
||||
<References document={document} />
|
||||
</ReferencesWrapper>
|
||||
</>
|
||||
)}
|
||||
<Editor
|
||||
id={document.id}
|
||||
ref={(ref) => {
|
||||
if (ref) {
|
||||
this.editor = ref;
|
||||
}
|
||||
}}
|
||||
isShare={isShare}
|
||||
isDraft={document.isDraft}
|
||||
template={document.isTemplate}
|
||||
key={[injectTemplate, disableEmbeds].join("-")}
|
||||
title={revision ? revision.title : this.title}
|
||||
document={document}
|
||||
value={readOnly ? value : undefined}
|
||||
defaultValue={value}
|
||||
disableEmbeds={disableEmbeds}
|
||||
onImageUploadStart={this.onImageUploadStart}
|
||||
onImageUploadStop={this.onImageUploadStop}
|
||||
onSearchLink={this.props.onSearchLink}
|
||||
onCreateLink={this.props.onCreateLink}
|
||||
onChangeTitle={this.onChangeTitle}
|
||||
onChange={this.onChange}
|
||||
onSave={this.onSave}
|
||||
onPublish={this.onPublish}
|
||||
onCancel={this.goBack}
|
||||
readOnly={readOnly}
|
||||
readOnlyWriteCheckboxes={readOnly && abilities.update}
|
||||
ui={this.props.ui}
|
||||
/>
|
||||
</Flex>
|
||||
{readOnly && !isShare && !revision && (
|
||||
<>
|
||||
<MarkAsViewed document={document} />
|
||||
<ReferencesWrapper isOnlyTitle={document.isOnlyTitle}>
|
||||
<References document={document} />
|
||||
</ReferencesWrapper>
|
||||
</>
|
||||
)}
|
||||
</React.Suspense>
|
||||
</MaxWidth>
|
||||
</Container>
|
||||
</Background>
|
||||
|
||||
@@ -13,13 +13,11 @@ import DocumentsStore from "stores/DocumentsStore";
|
||||
import UiStore from "stores/UiStore";
|
||||
import Document from "models/Document";
|
||||
import Flex from "components/Flex";
|
||||
import Input from "components/Input";
|
||||
import { Outline } from "components/Input";
|
||||
import Labeled from "components/Labeled";
|
||||
import Modal from "components/Modal";
|
||||
import PathToDocument from "components/PathToDocument";
|
||||
|
||||
const MAX_RESULTS = 8;
|
||||
|
||||
type Props = {|
|
||||
document: Document,
|
||||
documents: DocumentsStore,
|
||||
@@ -36,14 +34,19 @@ class DocumentMove extends React.Component<Props> {
|
||||
|
||||
@computed
|
||||
get searchIndex() {
|
||||
const { collections } = this.props;
|
||||
const { collections, documents } = this.props;
|
||||
const paths = collections.pathsToDocuments;
|
||||
const index = new Search("id");
|
||||
index.addIndex("title");
|
||||
|
||||
// Build index
|
||||
const indexeableDocuments = [];
|
||||
paths.forEach((path) => indexeableDocuments.push(path));
|
||||
paths.forEach((path) => {
|
||||
const doc = documents.get(path.id);
|
||||
if (!doc || !doc.isTemplate) {
|
||||
indexeableDocuments.push(path);
|
||||
}
|
||||
});
|
||||
index.addDocuments(indexeableDocuments);
|
||||
|
||||
return index;
|
||||
@@ -136,35 +139,41 @@ class DocumentMove extends React.Component<Props> {
|
||||
</Section>
|
||||
|
||||
<Section column>
|
||||
<Labeled label="Choose a new location">
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search collections & documents…"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onChange={this.handleFilter}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</Labeled>
|
||||
<Flex column>
|
||||
<StyledArrowKeyNavigation
|
||||
mode={ArrowKeyNavigation.mode.VERTICAL}
|
||||
defaultActiveChildIndex={0}
|
||||
>
|
||||
{this.results.slice(0, MAX_RESULTS).map((result, index) => (
|
||||
<PathToDocument
|
||||
key={result.id}
|
||||
result={result}
|
||||
document={document}
|
||||
collection={collections.get(result.collectionId)}
|
||||
ref={(ref) =>
|
||||
index === 0 && this.setFirstDocumentRef(ref)
|
||||
}
|
||||
onSuccess={this.handleSuccess}
|
||||
/>
|
||||
))}
|
||||
</StyledArrowKeyNavigation>
|
||||
</Flex>
|
||||
<Labeled label="Choose a new location" />
|
||||
<NewLocation>
|
||||
<InputWrapper>
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search collections & documents…"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onChange={this.handleFilter}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</InputWrapper>
|
||||
|
||||
<Results>
|
||||
<Flex column>
|
||||
<StyledArrowKeyNavigation
|
||||
mode={ArrowKeyNavigation.mode.VERTICAL}
|
||||
defaultActiveChildIndex={0}
|
||||
>
|
||||
{this.results.map((result, index) => (
|
||||
<PathToDocument
|
||||
key={result.id}
|
||||
result={result}
|
||||
document={document}
|
||||
collection={collections.get(result.collectionId)}
|
||||
ref={(ref) =>
|
||||
index === 0 && this.setFirstDocumentRef(ref)
|
||||
}
|
||||
onSuccess={this.handleSuccess}
|
||||
/>
|
||||
))}
|
||||
</StyledArrowKeyNavigation>
|
||||
</Flex>
|
||||
</Results>
|
||||
</NewLocation>
|
||||
</Section>
|
||||
</Flex>
|
||||
)}
|
||||
@@ -173,6 +182,37 @@ class DocumentMove extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const InputWrapper = styled("div")`
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const Input = styled("input")`
|
||||
width: 100%;
|
||||
outline: none;
|
||||
background: none;
|
||||
border-radius: 4px;
|
||||
height: 30px;
|
||||
border: 0;
|
||||
color: ${(props) => props.theme.text};
|
||||
|
||||
&::placeholder {
|
||||
color: ${(props) => props.theme.placeholder};
|
||||
}
|
||||
`;
|
||||
|
||||
const NewLocation = styled(Outline)`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const Results = styled(Flex)`
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-height: 40vh;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
`;
|
||||
|
||||
const Section = styled(Flex)`
|
||||
margin-bottom: 24px;
|
||||
`;
|
||||
|
||||
@@ -11,7 +11,6 @@ import DocumentMetaWithViews from "components/DocumentMetaWithViews";
|
||||
import Editor from "components/Editor";
|
||||
import Flex from "components/Flex";
|
||||
import HoverPreview from "components/HoverPreview";
|
||||
import LoadingPlaceholder from "components/LoadingPlaceholder";
|
||||
import { documentHistoryUrl } from "utils/routeHelpers";
|
||||
|
||||
type Props = {
|
||||
@@ -22,33 +21,25 @@ type Props = {
|
||||
isDraft: boolean,
|
||||
isShare: boolean,
|
||||
readOnly?: boolean,
|
||||
innerRef: { current: any },
|
||||
};
|
||||
|
||||
@observer
|
||||
class DocumentEditor extends React.Component<Props> {
|
||||
@observable activeLinkEvent: ?MouseEvent;
|
||||
editor = React.createRef<any>();
|
||||
|
||||
focusAtStart = () => {
|
||||
if (this.editor.current) {
|
||||
this.editor.current.focusAtStart();
|
||||
if (this.props.innerRef.current) {
|
||||
this.props.innerRef.current.focusAtStart();
|
||||
}
|
||||
};
|
||||
|
||||
focusAtEnd = () => {
|
||||
if (this.editor.current) {
|
||||
this.editor.current.focusAtEnd();
|
||||
if (this.props.innerRef.current) {
|
||||
this.props.innerRef.current.focusAtEnd();
|
||||
}
|
||||
};
|
||||
|
||||
getHeadings = () => {
|
||||
if (this.editor.current) {
|
||||
return this.editor.current.getHeadings();
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
handleTitleKeyDown = (event: SyntheticKeyboardEvent<>) => {
|
||||
if (event.key === "Enter" || event.key === "Tab") {
|
||||
event.preventDefault();
|
||||
@@ -72,49 +63,46 @@ class DocumentEditor extends React.Component<Props> {
|
||||
isDraft,
|
||||
isShare,
|
||||
readOnly,
|
||||
innerRef,
|
||||
} = this.props;
|
||||
const { emoji } = parseTitle(title);
|
||||
const startsWithEmojiAndSpace = !!(emoji && title.startsWith(`${emoji} `));
|
||||
|
||||
return (
|
||||
<Flex auto column>
|
||||
<React.Suspense fallback={<LoadingPlaceholder />}>
|
||||
<Title
|
||||
type="text"
|
||||
onChange={onChangeTitle}
|
||||
onKeyDown={this.handleTitleKeyDown}
|
||||
placeholder={document.placeholder}
|
||||
value={!title && readOnly ? document.titleWithDefault : title}
|
||||
style={
|
||||
startsWithEmojiAndSpace ? { marginLeft: "-1.2em" } : undefined
|
||||
}
|
||||
readOnly={readOnly}
|
||||
autoFocus={!title}
|
||||
maxLength={100}
|
||||
<Title
|
||||
type="text"
|
||||
onChange={onChangeTitle}
|
||||
onKeyDown={this.handleTitleKeyDown}
|
||||
placeholder={document.placeholder}
|
||||
value={!title && readOnly ? document.titleWithDefault : title}
|
||||
style={startsWithEmojiAndSpace ? { marginLeft: "-1.2em" } : undefined}
|
||||
readOnly={readOnly}
|
||||
autoFocus={!title}
|
||||
maxLength={100}
|
||||
/>
|
||||
<DocumentMetaWithViews
|
||||
isDraft={isDraft}
|
||||
document={document}
|
||||
to={documentHistoryUrl(document)}
|
||||
/>
|
||||
<Editor
|
||||
ref={innerRef}
|
||||
autoFocus={title && !this.props.defaultValue}
|
||||
placeholder="…the rest is up to you"
|
||||
onHoverLink={this.handleLinkActive}
|
||||
scrollTo={window.location.hash}
|
||||
grow
|
||||
{...this.props}
|
||||
/>
|
||||
{!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />}
|
||||
{this.activeLinkEvent && !isShare && readOnly && (
|
||||
<HoverPreview
|
||||
node={this.activeLinkEvent.target}
|
||||
event={this.activeLinkEvent}
|
||||
onClose={this.handleLinkInactive}
|
||||
/>
|
||||
<DocumentMetaWithViews
|
||||
isDraft={isDraft}
|
||||
document={document}
|
||||
to={documentHistoryUrl(document)}
|
||||
/>
|
||||
<Editor
|
||||
ref={this.editor}
|
||||
autoFocus={title && !this.props.defaultValue}
|
||||
placeholder="…the rest is up to you"
|
||||
onHoverLink={this.handleLinkActive}
|
||||
scrollTo={window.location.hash}
|
||||
grow
|
||||
{...this.props}
|
||||
/>
|
||||
{!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />}
|
||||
{this.activeLinkEvent && !isShare && readOnly && (
|
||||
<HoverPreview
|
||||
node={this.activeLinkEvent.target}
|
||||
event={this.activeLinkEvent}
|
||||
onClose={this.handleLinkInactive}
|
||||
/>
|
||||
)}
|
||||
</React.Suspense>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import Document from "models/Document";
|
||||
import Button from "components/Button";
|
||||
import Flex from "components/Flex";
|
||||
import HelpText from "components/HelpText";
|
||||
import { collectionUrl } from "utils/routeHelpers";
|
||||
import { collectionUrl, documentUrl } from "utils/routeHelpers";
|
||||
|
||||
type Props = {
|
||||
history: RouterHistory,
|
||||
@@ -24,15 +24,27 @@ class DocumentDelete extends React.Component<Props> {
|
||||
@observable isDeleting: boolean;
|
||||
|
||||
handleSubmit = async (ev: SyntheticEvent<>) => {
|
||||
const { documents, document } = this.props;
|
||||
ev.preventDefault();
|
||||
this.isDeleting = true;
|
||||
|
||||
try {
|
||||
await this.props.document.delete();
|
||||
if (this.props.ui.activeDocumentId === this.props.document.id) {
|
||||
this.props.history.push(
|
||||
collectionUrl(this.props.document.collectionId)
|
||||
);
|
||||
await document.delete();
|
||||
|
||||
// only redirect if we're currently viewing the document that's deleted
|
||||
if (this.props.ui.activeDocumentId === document.id) {
|
||||
// If the document has a parent and it's available in the store then
|
||||
// redirect to it
|
||||
if (document.parentDocumentId) {
|
||||
const parent = documents.get(document.parentDocumentId);
|
||||
if (parent) {
|
||||
this.props.history.push(documentUrl(parent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, redirect to the collection home
|
||||
this.props.history.push(collectionUrl(document.collectionId));
|
||||
}
|
||||
this.props.onSubmit();
|
||||
} catch (err) {
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"@babel/preset-flow": "^7.10.4",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@rehooks/window-scroll-position": "^1.0.1",
|
||||
"@sentry/node": "^5.12.2",
|
||||
"@sentry/node": "^5.22.3",
|
||||
"@tippy.js/react": "^2.2.2",
|
||||
"@tommoor/remove-markdown": "0.3.1",
|
||||
"autotrack": "^2.4.1",
|
||||
@@ -138,7 +138,7 @@
|
||||
"react-portal": "^4.0.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-waypoint": "^9.0.2",
|
||||
"rich-markdown-editor": "^10.6.1",
|
||||
"rich-markdown-editor": "^10.6.5",
|
||||
"semver": "^7.3.2",
|
||||
"sequelize": "^6.3.4",
|
||||
"sequelize-cli": "^6.2.0",
|
||||
|
||||
@@ -1001,7 +1001,7 @@ router.post("documents.delete", auth(), async (ctx) => {
|
||||
const document = await Document.findByPk(id, { userId: user.id });
|
||||
authorize(user, "delete", document);
|
||||
|
||||
await document.delete();
|
||||
await document.delete(user.id);
|
||||
|
||||
await Event.create({
|
||||
name: "documents.delete",
|
||||
|
||||
@@ -17,7 +17,6 @@ if (process.env.AWS_ACCESS_KEY_ID) {
|
||||
"AWS_REGION",
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
"AWS_S3_UPLOAD_BUCKET_URL",
|
||||
"AWS_S3_UPLOAD_BUCKET_NAME",
|
||||
"AWS_S3_UPLOAD_MAX_SIZE",
|
||||
].forEach((key) => {
|
||||
if (!process.env[key]) {
|
||||
|
||||
@@ -570,7 +570,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: string) {
|
||||
const collection = await this.getCollection();
|
||||
|
||||
// check to see if the documents parent hasn't been archived also
|
||||
@@ -602,23 +602,27 @@ Document.prototype.unarchive = async function (userId) {
|
||||
};
|
||||
|
||||
// Delete a document, archived or otherwise.
|
||||
Document.prototype.delete = function (options) {
|
||||
return sequelize.transaction(async (transaction: Transaction): Promise<*> => {
|
||||
if (!this.archivedAt) {
|
||||
// delete any children and remove from the document structure
|
||||
const collection = await this.getCollection();
|
||||
if (collection) await collection.deleteDocument(this, { transaction });
|
||||
Document.prototype.delete = function (userId: string) {
|
||||
return sequelize.transaction(
|
||||
async (transaction: Transaction): Promise<Document> => {
|
||||
if (!this.archivedAt && !this.template) {
|
||||
// delete any children and remove from the document structure
|
||||
const collection = await this.getCollection();
|
||||
if (collection) await collection.deleteDocument(this, { transaction });
|
||||
}
|
||||
|
||||
await Revision.destroy({
|
||||
where: { documentId: this.id },
|
||||
transaction,
|
||||
});
|
||||
|
||||
this.lastModifiedById = userId;
|
||||
this.deletedAt = new Date();
|
||||
|
||||
await this.save({ transaction });
|
||||
return this;
|
||||
}
|
||||
|
||||
await Revision.destroy({
|
||||
where: { documentId: this.id },
|
||||
transaction,
|
||||
});
|
||||
|
||||
await this.destroy({ transaction, ...options });
|
||||
|
||||
return this;
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
Document.prototype.getTimestamp = function () {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
/* eslint-disable flowtype/require-valid-file-annotation */
|
||||
import { Document } from "../models";
|
||||
import { buildDocument, buildCollection, buildTeam } from "../test/factories";
|
||||
import {
|
||||
buildDocument,
|
||||
buildCollection,
|
||||
buildTeam,
|
||||
buildUser,
|
||||
} from "../test/factories";
|
||||
import { flushdb } from "../test/support";
|
||||
|
||||
beforeEach(() => flushdb());
|
||||
@@ -192,3 +197,16 @@ describe("#searchForTeam", () => {
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#delete", () => {
|
||||
test("should soft delete and set last modified", async () => {
|
||||
let document = await buildDocument();
|
||||
let user = await buildUser();
|
||||
|
||||
await document.delete(user.id);
|
||||
|
||||
document = await Document.findByPk(document.id, { paranoid: false });
|
||||
expect(document.lastModifiedById).toBe(user.id);
|
||||
expect(document.deletedAt).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>//inject-env//</script>
|
||||
<script src="https://browser.sentry-cdn.com/5.12.1/bundle.min.js"
|
||||
integrity="sha384-y+an4eARFKvjzOivf/Z7JtMJhaN6b+lLQ5oFbBbUwZNNVir39cYtkjW1r6Xjbxg3" crossorigin="anonymous">
|
||||
<script src="https://browser.sentry-cdn.com/5.22.3/bundle.min.js"
|
||||
integrity="sha384-A1qzcXXJWl+bzYr+r8AdFzSaLbdcbYRFmG37MEDKr4EYjtraUyoZ6UiMw31jHcV9" crossorigin="anonymous">
|
||||
</script>
|
||||
<script>
|
||||
if ('//inject-sentry-dsn//') {
|
||||
@@ -44,6 +44,7 @@
|
||||
'NotFoundError',
|
||||
'OfflineError',
|
||||
'UpdateRequiredError',
|
||||
'ChunkLoadError'
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,18 +4,18 @@ import * as Sentry from "@sentry/node";
|
||||
import AWS from "aws-sdk";
|
||||
import addHours from "date-fns/add_hours";
|
||||
import format from "date-fns/format";
|
||||
import invariant from "invariant";
|
||||
import fetch from "isomorphic-fetch";
|
||||
|
||||
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
|
||||
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
|
||||
const AWS_REGION = process.env.AWS_REGION;
|
||||
const AWS_S3_UPLOAD_BUCKET_NAME = process.env.AWS_S3_UPLOAD_BUCKET_NAME;
|
||||
const AWS_S3_UPLOAD_BUCKET_NAME = process.env.AWS_S3_UPLOAD_BUCKET_NAME || "";
|
||||
const AWS_S3_FORCE_PATH_STYLE = process.env.AWS_S3_FORCE_PATH_STYLE !== "false";
|
||||
|
||||
const s3 = new AWS.S3({
|
||||
s3ForcePathStyle: true,
|
||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
||||
s3ForcePathStyle: AWS_S3_FORCE_PATH_STYLE,
|
||||
accessKeyId: AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: AWS_SECRET_ACCESS_KEY,
|
||||
endpoint: new AWS.Endpoint(process.env.AWS_S3_UPLOAD_BUCKET_URL),
|
||||
signatureVersion: "v4",
|
||||
});
|
||||
@@ -84,9 +84,9 @@ export const publicS3Endpoint = (isServerUpload?: boolean) => {
|
||||
"localhost:"
|
||||
).replace(/\/$/, "");
|
||||
|
||||
return `${host}/${isServerUpload && isDocker ? "s3/" : ""}${
|
||||
process.env.AWS_S3_UPLOAD_BUCKET_NAME
|
||||
}`;
|
||||
return `${host}/${
|
||||
isServerUpload && isDocker ? "s3/" : ""
|
||||
}${AWS_S3_UPLOAD_BUCKET_NAME}`;
|
||||
};
|
||||
|
||||
export const uploadToS3FromUrl = async (
|
||||
@@ -94,8 +94,6 @@ export const uploadToS3FromUrl = async (
|
||||
key: string,
|
||||
acl: string
|
||||
) => {
|
||||
invariant(AWS_S3_UPLOAD_BUCKET_NAME, "AWS_S3_UPLOAD_BUCKET_NAME not set");
|
||||
|
||||
try {
|
||||
// $FlowIssue https://github.com/facebook/flow/issues/2171
|
||||
const res = await fetch(url);
|
||||
@@ -103,7 +101,7 @@ export const uploadToS3FromUrl = async (
|
||||
await s3
|
||||
.putObject({
|
||||
ACL: acl,
|
||||
Bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Bucket: AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Key: key,
|
||||
ContentType: res.headers["content-type"],
|
||||
ContentLength: res.headers["content-length"],
|
||||
@@ -126,18 +124,17 @@ export const uploadToS3FromUrl = async (
|
||||
export const deleteFromS3 = (key: string) => {
|
||||
return s3
|
||||
.deleteObject({
|
||||
Bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Bucket: AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Key: key,
|
||||
})
|
||||
.promise();
|
||||
};
|
||||
|
||||
export const getSignedImageUrl = async (key: string) => {
|
||||
invariant(AWS_S3_UPLOAD_BUCKET_NAME, "AWS_S3_UPLOAD_BUCKET_NAME not set");
|
||||
const isDocker = process.env.AWS_S3_UPLOAD_BUCKET_URL.match(/http:\/\/s3:/);
|
||||
|
||||
const params = {
|
||||
Bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Bucket: AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Key: key,
|
||||
Expires: 60,
|
||||
};
|
||||
@@ -149,7 +146,7 @@ export const getSignedImageUrl = async (key: string) => {
|
||||
|
||||
export const getImageByKey = async (key: string) => {
|
||||
const params = {
|
||||
Bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Bucket: AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Key: key,
|
||||
};
|
||||
|
||||
|
||||
175
yarn.lock
175
yarn.lock
@@ -1024,10 +1024,10 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@emotion/is-prop-valid@^0.8.3":
|
||||
version "0.8.7"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.7.tgz#803449993f436f9a6c67752251ea3fc492a1044c"
|
||||
integrity sha512-OPkKzUeiid0vEKjZqnGcy2mzxjIlCffin+L2C02pdz/bVlt5zZZE2VzO0D3XOPnH0NEeF21QNKSXiZphjr4xiQ==
|
||||
"@emotion/is-prop-valid@^0.8.8":
|
||||
version "0.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||
dependencies:
|
||||
"@emotion/memoize" "0.7.4"
|
||||
|
||||
@@ -1372,83 +1372,72 @@
|
||||
execa "^4.0.0"
|
||||
java-properties "^1.0.0"
|
||||
|
||||
"@sentry/apm@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.15.4.tgz#59af766d2bb4c9d98eda5ddba7a32a79ecc807a2"
|
||||
integrity sha512-gcW225Jls1ShyBXMWN6zZyuVJwBOIQ63sI+URI2NSFsdpBpdpZ8yennIm+oMlSfb25Nzt9SId7TRSjPhlSbTZQ==
|
||||
"@sentry/core@5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.22.3.tgz#030f435f2b518f282ba8bd954dac90cd70888bd7"
|
||||
integrity sha512-eGL5uUarw3o4i9QUb9JoFHnhriPpWCaqeaIBB06HUpdcvhrjoowcKZj1+WPec5lFg5XusE35vez7z/FPzmJUDw==
|
||||
dependencies:
|
||||
"@sentry/browser" "5.15.4"
|
||||
"@sentry/hub" "5.15.4"
|
||||
"@sentry/minimal" "5.15.4"
|
||||
"@sentry/types" "5.15.4"
|
||||
"@sentry/utils" "5.15.4"
|
||||
"@sentry/hub" "5.22.3"
|
||||
"@sentry/minimal" "5.22.3"
|
||||
"@sentry/types" "5.22.3"
|
||||
"@sentry/utils" "5.22.3"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/browser@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.15.4.tgz#5a7e7bad088556665ed8e69bceb0e18784e4f6c7"
|
||||
integrity sha512-l/auT1HtZM3KxjCGQHYO/K51ygnlcuOrM+7Ga8gUUbU9ZXDYw6jRi0+Af9aqXKmdDw1naNxr7OCSy6NBrLWVZw==
|
||||
"@sentry/hub@5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.22.3.tgz#08309a70d2ea8d5e313d05840c1711f34f2fffe5"
|
||||
integrity sha512-INo47m6N5HFEs/7GMP9cqxOIt7rmRxdERunA3H2L37owjcr77MwHVeeJ9yawRS6FMtbWXplgWTyTIWIYOuqVbw==
|
||||
dependencies:
|
||||
"@sentry/core" "5.15.4"
|
||||
"@sentry/types" "5.15.4"
|
||||
"@sentry/utils" "5.15.4"
|
||||
"@sentry/types" "5.22.3"
|
||||
"@sentry/utils" "5.22.3"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/core@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.15.4.tgz#08b617e093a636168be5aebad141d1f744217085"
|
||||
integrity sha512-9KP4NM4SqfV5NixpvAymC7Nvp36Zj4dU2fowmxiq7OIbzTxGXDhwuN/t0Uh8xiqlkpkQqSECZ1OjSFXrBldetQ==
|
||||
"@sentry/minimal@5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.22.3.tgz#706e4029ae5494123d3875c658ba8911aa5cc440"
|
||||
integrity sha512-HoINpYnVYCpNjn2XIPIlqH5o4BAITpTljXjtAftOx6Hzj+Opjg8tR8PWliyKDvkXPpc4kXK9D6TpEDw8MO0wZA==
|
||||
dependencies:
|
||||
"@sentry/hub" "5.15.4"
|
||||
"@sentry/minimal" "5.15.4"
|
||||
"@sentry/types" "5.15.4"
|
||||
"@sentry/utils" "5.15.4"
|
||||
"@sentry/hub" "5.22.3"
|
||||
"@sentry/types" "5.22.3"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/hub@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.15.4.tgz#cb64473725a60eec63b0be58ed1143eaaf894bee"
|
||||
integrity sha512-1XJ1SVqadkbUT4zLS0TVIVl99si7oHizLmghR8LMFl5wOkGEgehHSoOydQkIAX2C7sJmaF5TZ47ORBHgkqclUg==
|
||||
"@sentry/node@^5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.22.3.tgz#adea622eae6811e11edc8f34209c912caed91336"
|
||||
integrity sha512-TCCKO7hJKiQi1nGmJcQfvbbqv98P08LULh7pb/NaO5pV20t1FtICfGx8UMpORRDehbcAiYq/f7rPOF6X/Xl5iw==
|
||||
dependencies:
|
||||
"@sentry/types" "5.15.4"
|
||||
"@sentry/utils" "5.15.4"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/minimal@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.15.4.tgz#113f01fefb86b7830994c3dfa7ad4889ba7b2003"
|
||||
integrity sha512-GL4GZ3drS9ge+wmxkHBAMEwulaE7DMvAEfKQPDAjg2p3MfcCMhAYfuY4jJByAC9rg9OwBGGehz7UmhWMFjE0tw==
|
||||
dependencies:
|
||||
"@sentry/hub" "5.15.4"
|
||||
"@sentry/types" "5.15.4"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/node@^5.12.2":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.15.4.tgz#e7bc3962d321a12b633743200165ca5f1757cb68"
|
||||
integrity sha512-OfdhNEvOJZ55ZkCUcVgctjaZkOw7rmLzO5VyDTSgevA4uLsPaTNXSAeK2GSQBXc5J0KdRpNz4sSIyuxOS4Z7Vg==
|
||||
dependencies:
|
||||
"@sentry/apm" "5.15.4"
|
||||
"@sentry/core" "5.15.4"
|
||||
"@sentry/hub" "5.15.4"
|
||||
"@sentry/types" "5.15.4"
|
||||
"@sentry/utils" "5.15.4"
|
||||
cookie "^0.3.1"
|
||||
https-proxy-agent "^4.0.0"
|
||||
"@sentry/core" "5.22.3"
|
||||
"@sentry/hub" "5.22.3"
|
||||
"@sentry/tracing" "5.22.3"
|
||||
"@sentry/types" "5.22.3"
|
||||
"@sentry/utils" "5.22.3"
|
||||
cookie "^0.4.1"
|
||||
https-proxy-agent "^5.0.0"
|
||||
lru_map "^0.3.3"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/types@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.15.4.tgz#37f30e35b06e8e12ad1101f1beec3e9b88ca1aab"
|
||||
integrity sha512-quPHPpeAuwID48HLPmqBiyXE3xEiZLZ5D3CEbU3c3YuvvAg8qmfOOTI6z4Z3Eedi7flvYpnx3n7N3dXIEz30Eg==
|
||||
|
||||
"@sentry/utils@5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.15.4.tgz#02865ab3c9b745656cea0ab183767ec26c96f6e6"
|
||||
integrity sha512-lO8SLBjrUDGADl0LOkd55R5oL510d/1SaI08/IBHZCxCUwI4TiYo5EPECq8mrj3XGfgCyq9osw33bymRlIDuSQ==
|
||||
"@sentry/tracing@5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.22.3.tgz#9b5a376e3164c007a22e8642ec094104468cac0c"
|
||||
integrity sha512-Zp59kMCk5v56ZAyErqjv/QvGOWOQ5fRltzeVQVp8unIDTk6gEFXfhwPsYHOokJe1mfkmrgPDV6xAkYgtL3KCDQ==
|
||||
dependencies:
|
||||
"@sentry/types" "5.15.4"
|
||||
"@sentry/hub" "5.22.3"
|
||||
"@sentry/minimal" "5.22.3"
|
||||
"@sentry/types" "5.22.3"
|
||||
"@sentry/utils" "5.22.3"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/types@5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.22.3.tgz#d1d547b30ee8bd7771fa893af74c4f3d71f0fd18"
|
||||
integrity sha512-cv+VWK0YFgCVDvD1/HrrBWOWYG3MLuCUJRBTkV/Opdy7nkdNjhCAJQrEyMM9zX0sac8FKWKOHT0sykNh8KgmYw==
|
||||
|
||||
"@sentry/utils@5.22.3":
|
||||
version "5.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.22.3.tgz#e3bda3e789239eb16d436f768daa12829f33d18f"
|
||||
integrity sha512-AHNryXMBvIkIE+GQxTlmhBXD0Ksh+5w1SwM5qi6AttH+1qjWLvV6WB4+4pvVvEoS8t5F+WaVUZPQLmCCWp6zKw==
|
||||
dependencies:
|
||||
"@sentry/types" "5.22.3"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sindresorhus/is@^0.7.0":
|
||||
@@ -1808,11 +1797,6 @@ after@0.8.2:
|
||||
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
|
||||
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
|
||||
|
||||
agent-base@5:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
|
||||
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
|
||||
|
||||
agent-base@6:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a"
|
||||
@@ -3428,11 +3412,16 @@ convert-units@^2.3.4:
|
||||
lodash.foreach "2.3.x"
|
||||
lodash.keys "2.3.x"
|
||||
|
||||
cookie@0.3.1, cookie@^0.3.1:
|
||||
cookie@0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
|
||||
|
||||
cookie@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
|
||||
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
|
||||
|
||||
cookies@~0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90"
|
||||
@@ -5682,14 +5671,6 @@ https-browserify@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
https-proxy-agent@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
|
||||
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
|
||||
dependencies:
|
||||
agent-base "5"
|
||||
debug "4"
|
||||
|
||||
https-proxy-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||
@@ -9105,7 +9086,7 @@ prosemirror-tables@^1.0.0:
|
||||
prosemirror-transform "^1.2.1"
|
||||
prosemirror-view "^1.13.3"
|
||||
|
||||
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1:
|
||||
prosemirror-transform@1.2.5, prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.2.5.tgz#7a3e2c61fcdbaf1d0844a2a3bc34fc3524e9809c"
|
||||
integrity sha512-eqeIaxWtUfOnpA1ERrXCuSIMzqIJtL9Qrs5uJMCjY5RMSaH5o4pc390SAjn/IDPeIlw6auh0hCCXs3wRvGnQug==
|
||||
@@ -9847,10 +9828,10 @@ retry-as-promised@^3.2.0:
|
||||
dependencies:
|
||||
any-promise "^1.3.0"
|
||||
|
||||
rich-markdown-editor@^10.6.1:
|
||||
version "10.6.1"
|
||||
resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-10.6.1.tgz#22099c12b8b1e193f9523c16cb83ef0824c08d58"
|
||||
integrity sha512-HfjrNXanFwy6iy3dkNqOZF1siwm5tuou8B9y2gj0PcP73KJyQ/FoFPUSEZ/E3ttU45NJCARLvd8X5Qc2wdtLVA==
|
||||
rich-markdown-editor@^10.6.5:
|
||||
version "10.6.5"
|
||||
resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-10.6.5.tgz#b74ae2e7d05eaa3c8ef34744e5cb0ed2dbdb0958"
|
||||
integrity sha512-C/C+6L7BTXC4zSHgOYMljOQ3CvFt8zNCT829woKBHcDWSnXiUzpjgZZ4qEeNRlh/XJmqeFZYfqY+OzIMsVP2+Q==
|
||||
dependencies:
|
||||
copy-to-clipboard "^3.0.8"
|
||||
lodash "^4.17.11"
|
||||
@@ -9869,6 +9850,7 @@ rich-markdown-editor@^10.6.1:
|
||||
prosemirror-schema-list "^1.1.2"
|
||||
prosemirror-state "^1.3.3"
|
||||
prosemirror-tables "^1.0.0"
|
||||
prosemirror-transform "1.2.5"
|
||||
prosemirror-utils "^0.9.6"
|
||||
prosemirror-view "^1.14.11"
|
||||
react-medium-image-zoom "^3.0.16"
|
||||
@@ -9876,8 +9858,8 @@ rich-markdown-editor@^10.6.1:
|
||||
refractor "^2.10.1"
|
||||
slugify "^1.4.0"
|
||||
smooth-scroll-into-view-if-needed "^1.1.27"
|
||||
styled-components "^5.0.0"
|
||||
typescript "^3.7.5"
|
||||
styled-components "^5.1.0"
|
||||
typescript "3.7.5"
|
||||
|
||||
rimraf@2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
|
||||
version "2.7.1"
|
||||
@@ -10819,14 +10801,14 @@ styled-components-breakpoint@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/styled-components-breakpoint/-/styled-components-breakpoint-2.1.1.tgz#37c1b92b0e96c1bbc5d293724d7a114daaa15fca"
|
||||
integrity sha512-PkS7p3MkPJx/v930Q3MPJU8llfFJTxk8o009jl0p+OUFmVb2AlHmVclX1MBHSXk8sZYGoVTTVIPDuZCELi7QIg==
|
||||
|
||||
styled-components@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.0.1.tgz#57782a6471031abefb2db5820a1876ae853bc619"
|
||||
integrity sha512-E0xKTRIjTs4DyvC1MHu/EcCXIj6+ENCP8hP01koyoADF++WdBUOrSGwU1scJRw7/YaYOhDvvoad6VlMG+0j53A==
|
||||
styled-components@^5.0.0, styled-components@^5.1.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.1.1.tgz#96dfb02a8025794960863b9e8e365e3b6be5518d"
|
||||
integrity sha512-1ps8ZAYu2Husx+Vz8D+MvXwEwvMwFv+hqqUwhNlDN5ybg6A+3xyW1ECrAgywhvXapNfXiz79jJyU0x22z0FFTg==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@babel/traverse" "^7.4.5"
|
||||
"@emotion/is-prop-valid" "^0.8.3"
|
||||
"@emotion/is-prop-valid" "^0.8.8"
|
||||
"@emotion/stylis" "^0.8.4"
|
||||
"@emotion/unitless" "^0.7.4"
|
||||
babel-plugin-styled-components ">= 1"
|
||||
@@ -11316,7 +11298,12 @@ typescript-compiler@^1.4.1-2:
|
||||
resolved "https://registry.yarnpkg.com/typescript-compiler/-/typescript-compiler-1.4.1-2.tgz#ba4f7db22d91534a1929d90009dce161eb72fd3f"
|
||||
integrity sha1-uk99si2RU0oZKdkACdzhYety/T8=
|
||||
|
||||
typescript@^3.4, typescript@^3.7.5:
|
||||
typescript@3.7.5:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
|
||||
typescript@^3.4:
|
||||
version "3.9.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9"
|
||||
integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==
|
||||
|
||||
Reference in New Issue
Block a user