Merge main

This commit is contained in:
Tom Moor
2021-02-07 12:58:17 -08:00
233 changed files with 7243 additions and 4147 deletions

View File

@@ -1,27 +1,30 @@
// @flow
import * as Sentry from "@sentry/react";
import invariant from "invariant";
import { observable, action, computed, autorun, runInAction } from "mobx";
import { getCookie, setCookie, removeCookie } from "tiny-cookie";
import RootStore from "stores/RootStore";
import Policy from "models/Policy";
import Team from "models/Team";
import User from "models/User";
import env from "env";
import { client } from "utils/ApiClient";
import { getCookieDomain } from "utils/domains";
const AUTH_STORE = "AUTH_STORE";
const NO_REDIRECT_PATHS = ["/", "/create", "/home"];
type Service = {
type Service = {|
id: string,
name: string,
authUrl: string,
};
|};
type Config = {
type Config = {|
name?: string,
hostname?: string,
services: Service[],
};
|};
export default class AuthStore {
@observable user: ?User;
@@ -45,7 +48,6 @@ export default class AuthStore {
// no-op Safari private mode
}
setImmediate(() => this.fetchConfig());
this.rehydrate(data);
// persists this entire store to localstorage whenever any keys are changed
@@ -87,7 +89,7 @@ export default class AuthStore {
}
}
addPolicies = (policies) => {
addPolicies = (policies: Policy[]) => {
if (policies) {
policies.forEach((policy) => this.rootStore.policies.add(policy));
}
@@ -125,8 +127,8 @@ export default class AuthStore {
this.user = new User(user);
this.team = new Team(team);
if (window.Sentry) {
window.Sentry.configureScope(function (scope) {
if (env.SENTRY_DSN) {
Sentry.configureScope(function (scope) {
scope.setUser({ id: user.id });
scope.setExtra("team", team.name);
scope.setExtra("teamId", team.id);

View File

@@ -111,6 +111,15 @@ export default class DocumentsStore extends BaseStore<Document> {
);
}
rootInCollection(collectionId: string): Document[] {
const collection = this.rootStore.collections.get(collectionId);
if (!collection) {
return [];
}
return compact(collection.documents.map((node) => this.get(node.id)));
}
leastRecentlyUpdatedInCollection(collectionId: string): Document[] {
return orderBy(this.inCollection(collectionId), "updatedAt", "asc");
}
@@ -174,7 +183,13 @@ export default class DocumentsStore extends BaseStore<Document> {
return this.drafts().length;
}
drafts = (options = {}): Document[] => {
drafts = (
options: {
...PaginationParams,
dateFilter?: "day" | "week" | "month" | "year",
collectionId?: string,
} = {}
): Document[] => {
let drafts = filter(
orderBy(this.all, "updatedAt", "desc"),
(doc) => !doc.publishedAt
@@ -185,7 +200,7 @@ export default class DocumentsStore extends BaseStore<Document> {
drafts,
(draft) =>
new Date(draft.updatedAt) >=
subtractDate(new Date(), options.dateFilter)
subtractDate(new Date(), options.dateFilter || "year")
);
}
@@ -245,7 +260,7 @@ export default class DocumentsStore extends BaseStore<Document> {
@action
fetchNamedPage = async (
request: string = "list",
options: ?PaginationParams
options: ?Object
): Promise<?(Document[])> => {
this.isFetching = true;
@@ -338,10 +353,9 @@ export default class DocumentsStore extends BaseStore<Document> {
};
@action
searchTitles = async (query: string, options: PaginationParams = {}) => {
searchTitles = async (query: string) => {
const res = await client.get("/documents.search_titles", {
query,
...options,
});
invariant(res && res.data, "Search response should be available");
@@ -354,7 +368,15 @@ export default class DocumentsStore extends BaseStore<Document> {
@action
search = async (
query: string,
options: PaginationParams = {}
options: {
offset?: number,
limit?: number,
dateFilter?: "day" | "week" | "month" | "year",
includeArchived?: boolean,
includeDrafts?: boolean,
collectionId?: string,
userId?: string,
}
): Promise<SearchResult[]> => {
const compactedOptions = omitBy(options, (o) => !o);
const res = await client.get("/documents.search", {
@@ -453,7 +475,8 @@ export default class DocumentsStore extends BaseStore<Document> {
move = async (
documentId: string,
collectionId: string,
parentDocumentId: ?string
parentDocumentId: ?string,
index: ?number
) => {
this.movingDocumentId = documentId;
@@ -462,6 +485,7 @@ export default class DocumentsStore extends BaseStore<Document> {
id: documentId,
collectionId,
parentDocumentId,
index: index,
});
invariant(res && res.data, "Data not available");
@@ -599,10 +623,14 @@ export default class DocumentsStore extends BaseStore<Document> {
};
@action
restore = async (document: Document, options = {}) => {
restore = async (
document: Document,
options: { revisionId?: string, collectionId?: string } = {}
) => {
const res = await client.post("/documents.restore", {
id: document.id,
...options,
revisionId: options.revisionId,
collectionId: options.collectionId,
});
runInAction("Document#restore", () => {
invariant(res && res.data, "Data should be available");

View File

@@ -2,6 +2,7 @@
import { orderBy } from "lodash";
import { observable, action, autorun, computed } from "mobx";
import { v4 } from "uuid";
import { light as defaultTheme } from "shared/styles/theme";
import Collection from "models/Collection";
import Document from "models/Document";
import type { Toast } from "types";
@@ -23,8 +24,11 @@ class UiStore {
@observable editMode: boolean = false;
@observable tocVisible: boolean = false;
@observable mobileSidebarVisible: boolean = false;
@observable sidebarWidth: number;
@observable sidebarCollapsed: boolean = false;
@observable sidebarIsResizing: boolean = false;
@observable toasts: Map<string, Toast> = new Map();
lastToastId: string;
constructor() {
// Rehydrate
@@ -53,6 +57,7 @@ class UiStore {
// persisted keys
this.languagePromptDismissed = data.languagePromptDismissed;
this.sidebarCollapsed = data.sidebarCollapsed;
this.sidebarWidth = data.sidebarWidth || defaultTheme.sidebarWidth;
this.tocVisible = data.tocVisible;
this.theme = data.theme || "system";
@@ -93,6 +98,11 @@ class UiStore {
}
};
@action
setSidebarResizing = (sidebarIsResizing: boolean): void => {
this.sidebarIsResizing = sidebarIsResizing;
};
@action
setActiveCollection = (collection: Collection): void => {
this.activeCollectionId = collection.id;
@@ -109,6 +119,11 @@ class UiStore {
this.activeCollectionId = undefined;
};
@action
setSidebarWidth = (sidebarWidth: number): void => {
this.sidebarWidth = sidebarWidth;
};
@action
collapseSidebar = () => {
this.sidebarCollapsed = true;
@@ -167,20 +182,39 @@ class UiStore {
@action
showToast = (
message: string,
options?: {
type?: "warning" | "error" | "info" | "success",
options: {
type: "warning" | "error" | "info" | "success",
timeout?: number,
action?: {
text: string,
onClick: () => void,
},
} = {
type: "info",
}
) => {
if (!message) return;
const lastToast = this.toasts.get(this.lastToastId);
if (lastToast && lastToast.message === message) {
this.toasts.set(this.lastToastId, {
...lastToast,
reoccurring: lastToast.reoccurring ? ++lastToast.reoccurring : 1,
});
return;
}
const id = v4();
const createdAt = new Date().toISOString();
this.toasts.set(id, { message, createdAt, id, ...options });
this.toasts.set(id, {
id,
message,
createdAt,
type: options.type,
timeout: options.timeout,
action: options.action,
});
this.lastToastId = id;
return id;
};
@@ -208,6 +242,7 @@ class UiStore {
return JSON.stringify({
tocVisible: this.tocVisible,
sidebarCollapsed: this.sidebarCollapsed,
sidebarWidth: this.sidebarWidth,
languagePromptDismissed: this.languagePromptDismissed,
theme: this.theme,
});