Merge main
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user