fix: Initials do not display on notification avatars (#5803)
This commit is contained in:
@@ -3,8 +3,8 @@ import { shallow } from "enzyme";
|
|||||||
import { TFunction } from "i18next";
|
import { TFunction } from "i18next";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { getI18n } from "react-i18next";
|
import { getI18n } from "react-i18next";
|
||||||
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/BaseStore";
|
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/base/Store";
|
||||||
import { runAllPromises } from "~/test/support";
|
import { runAllPromises } from "~/test/support";
|
||||||
import { Component as PaginatedList } from "./PaginatedList";
|
import { Component as PaginatedList } from "./PaginatedList";
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import * as React from "react";
|
|||||||
import { withTranslation, WithTranslation } from "react-i18next";
|
import { withTranslation, WithTranslation } from "react-i18next";
|
||||||
import { Waypoint } from "react-waypoint";
|
import { Waypoint } from "react-waypoint";
|
||||||
import { CompositeStateReturn } from "reakit/Composite";
|
import { CompositeStateReturn } from "reakit/Composite";
|
||||||
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/BaseStore";
|
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/base/Store";
|
||||||
import ArrowKeyNavigation from "~/components/ArrowKeyNavigation";
|
import ArrowKeyNavigation from "~/components/ArrowKeyNavigation";
|
||||||
import DelayedMount from "~/components/DelayedMount";
|
import DelayedMount from "~/components/DelayedMount";
|
||||||
import PlaceholderList from "~/components/List/Placeholder";
|
import PlaceholderList from "~/components/List/Placeholder";
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ class WebsocketProvider extends React.Component<Props> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.team?.updateFromJson(event);
|
auth.team?.updateData(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on(
|
this.socket.on(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import BaseModel from "~/models/BaseModel";
|
import Model from "~/models/base/Model";
|
||||||
import useStores from "./useStores";
|
import useStores from "./useStores";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,7 +9,7 @@ import useStores from "./useStores";
|
|||||||
* @param entity The model or model id
|
* @param entity The model or model id
|
||||||
* @returns The policy for the model
|
* @returns The policy for the model
|
||||||
*/
|
*/
|
||||||
export default function usePolicy(entity?: string | BaseModel | null) {
|
export default function usePolicy(entity?: string | Model | null) {
|
||||||
const { policies } = useStores();
|
const { policies } = useStores();
|
||||||
const triggered = React.useRef(false);
|
const triggered = React.useRef(false);
|
||||||
const entityId = entity
|
const entityId = entity
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class ApiKey extends BaseModel {
|
class ApiKey extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { computed, observable } from "mobx";
|
import { computed, observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class AuthenticationProvider extends BaseModel {
|
class AuthenticationProvider extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
import { sortNavigationNodes } from "@shared/utils/collections";
|
import { sortNavigationNodes } from "@shared/utils/collections";
|
||||||
import type CollectionsStore from "~/stores/CollectionsStore";
|
import type CollectionsStore from "~/stores/CollectionsStore";
|
||||||
import Document from "~/models/Document";
|
import Document from "~/models/Document";
|
||||||
import ParanoidModel from "~/models/ParanoidModel";
|
import ParanoidModel from "~/models/base/ParanoidModel";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { CollectionPermission } from "@shared/types";
|
import { CollectionPermission } from "@shared/types";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class CollectionGroupMembership extends BaseModel {
|
class CollectionGroupMembership extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
groupId: string;
|
groupId: string;
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import { computed, observable } from "mobx";
|
|||||||
import { now } from "mobx-utils";
|
import { now } from "mobx-utils";
|
||||||
import type { ProsemirrorData } from "@shared/types";
|
import type { ProsemirrorData } from "@shared/types";
|
||||||
import User from "~/models/User";
|
import User from "~/models/User";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
import Relation from "./decorators/Relation";
|
||||||
|
|
||||||
class Comment extends BaseModel {
|
class Comment extends Model {
|
||||||
/**
|
/**
|
||||||
* Map to keep track of which users are currently typing a reply in this
|
* Map to keep track of which users are currently typing a reply in this
|
||||||
* comments thread.
|
* comments thread.
|
||||||
@@ -40,18 +41,16 @@ class Comment extends BaseModel {
|
|||||||
@observable
|
@observable
|
||||||
documentId: string;
|
documentId: string;
|
||||||
|
|
||||||
createdAt: string;
|
@Relation(() => User)
|
||||||
|
|
||||||
createdBy: User;
|
createdBy: User;
|
||||||
|
|
||||||
createdById: string;
|
createdById: string;
|
||||||
|
|
||||||
resolvedAt: string;
|
resolvedAt: string;
|
||||||
|
|
||||||
|
@Relation(() => User)
|
||||||
resolvedBy: User;
|
resolvedBy: User;
|
||||||
|
|
||||||
updatedAt: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of users that are currently typing a reply in this comments thread.
|
* An array of users that are currently typing a reply in this comments thread.
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +59,7 @@ class Comment extends BaseModel {
|
|||||||
return Array.from(this.typingUsers.entries())
|
return Array.from(this.typingUsers.entries())
|
||||||
.filter(([, lastReceivedDate]) => lastReceivedDate > subSeconds(now(), 3))
|
.filter(([, lastReceivedDate]) => lastReceivedDate > subSeconds(now(), 3))
|
||||||
.map(([userId]) => this.store.rootStore.users.get(userId))
|
.map(([userId]) => this.store.rootStore.users.get(userId))
|
||||||
.filter(Boolean);
|
.filter(Boolean) as User[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { isRTL } from "@shared/utils/rtl";
|
|||||||
import DocumentsStore from "~/stores/DocumentsStore";
|
import DocumentsStore from "~/stores/DocumentsStore";
|
||||||
import User from "~/models/User";
|
import User from "~/models/User";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import ParanoidModel from "./ParanoidModel";
|
|
||||||
import View from "./View";
|
import View from "./View";
|
||||||
|
import ParanoidModel from "./base/ParanoidModel";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
type SaveOptions = {
|
type SaveOptions = {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import BaseModel from "./BaseModel";
|
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
|
import Relation from "./decorators/Relation";
|
||||||
|
|
||||||
class Event extends BaseModel {
|
class Event extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
name: string;
|
name: string;
|
||||||
@@ -18,8 +19,7 @@ class Event extends BaseModel {
|
|||||||
|
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
||||||
createdAt: string;
|
@Relation(() => User)
|
||||||
|
|
||||||
actor: User;
|
actor: User;
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import { FileOperationFormat, FileOperationType } from "@shared/types";
|
import { FileOperationFormat, FileOperationType } from "@shared/types";
|
||||||
import { bytesToHumanReadable } from "@shared/utils/files";
|
import { bytesToHumanReadable } from "@shared/utils/files";
|
||||||
import BaseModel from "./BaseModel";
|
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class FileOperation extends BaseModel {
|
class FileOperation extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
state: string;
|
state: string;
|
||||||
@@ -23,8 +23,6 @@ class FileOperation extends BaseModel {
|
|||||||
|
|
||||||
user: User;
|
user: User;
|
||||||
|
|
||||||
createdAt: string;
|
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
get sizeInMB(): string {
|
get sizeInMB(): string {
|
||||||
return bytesToHumanReadable(this.size);
|
return bytesToHumanReadable(this.size);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class Group extends BaseModel {
|
class Group extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
@@ -12,8 +12,6 @@ class Group extends BaseModel {
|
|||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
memberCount: number;
|
memberCount: number;
|
||||||
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Group;
|
export default Group;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import BaseModel from "./BaseModel";
|
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class GroupMembership extends BaseModel {
|
class GroupMembership extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import type {
|
|||||||
IntegrationSettings,
|
IntegrationSettings,
|
||||||
IntegrationType,
|
IntegrationType,
|
||||||
} from "@shared/types";
|
} from "@shared/types";
|
||||||
import BaseModel from "~/models/BaseModel";
|
import Model from "~/models/base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class Integration<T = unknown> extends BaseModel {
|
class Integration<T = unknown> extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
type: IntegrationType;
|
type: IntegrationType;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { CollectionPermission } from "@shared/types";
|
import { CollectionPermission } from "@shared/types";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class Membership extends BaseModel {
|
class Membership extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import {
|
|||||||
documentPath,
|
documentPath,
|
||||||
settingsPath,
|
settingsPath,
|
||||||
} from "~/utils/routeHelpers";
|
} from "~/utils/routeHelpers";
|
||||||
import BaseModel from "./BaseModel";
|
|
||||||
import Comment from "./Comment";
|
import Comment from "./Comment";
|
||||||
import Document from "./Document";
|
import Document from "./Document";
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
import Relation from "./decorators/Relation";
|
||||||
|
|
||||||
class Notification extends BaseModel {
|
class Notification extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
@@ -35,6 +36,7 @@ class Notification extends BaseModel {
|
|||||||
/**
|
/**
|
||||||
* The user that triggered the notification.
|
* The user that triggered the notification.
|
||||||
*/
|
*/
|
||||||
|
@Relation(() => User)
|
||||||
actor?: User;
|
actor?: User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,6 +47,7 @@ class Notification extends BaseModel {
|
|||||||
/**
|
/**
|
||||||
* The document that the notification is associated with.
|
* The document that the notification is associated with.
|
||||||
*/
|
*/
|
||||||
|
@Relation(() => Document)
|
||||||
document?: Document;
|
document?: Document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +58,7 @@ class Notification extends BaseModel {
|
|||||||
/**
|
/**
|
||||||
* The comment that the notification is associated with.
|
* The comment that the notification is associated with.
|
||||||
*/
|
*/
|
||||||
|
@Relation(() => Comment)
|
||||||
comment?: Comment;
|
comment?: Comment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,9 +141,9 @@ class Notification extends BaseModel {
|
|||||||
return this.document ? documentPath(this.document) : "";
|
return this.document ? documentPath(this.document) : "";
|
||||||
}
|
}
|
||||||
case NotificationEventType.CreateCollection: {
|
case NotificationEventType.CreateCollection: {
|
||||||
const collection = this.store.rootStore.documents.get(
|
const collection = this.collectionId
|
||||||
this.collectionId
|
? this.store.rootStore.documents.get(this.collectionId)
|
||||||
);
|
: undefined;
|
||||||
return collection ? collectionPath(collection.url) : "";
|
return collection ? collectionPath(collection.url) : "";
|
||||||
}
|
}
|
||||||
case NotificationEventType.MentionedInDocument: {
|
case NotificationEventType.MentionedInDocument: {
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import BaseModel from "./BaseModel";
|
|
||||||
|
|
||||||
export default abstract class ParanoidModel extends BaseModel {
|
|
||||||
deletedAt: string | undefined;
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class Pin extends BaseModel {
|
class Pin extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
documentId: string;
|
documentId: string;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class Policy extends BaseModel {
|
class Policy extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
abilities: Record<string, boolean>;
|
abilities: Record<string, boolean>;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import { isRTL } from "@shared/utils/rtl";
|
import { isRTL } from "@shared/utils/rtl";
|
||||||
import BaseModel from "./BaseModel";
|
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
|
import Relation from "./decorators/Relation";
|
||||||
|
|
||||||
class Revision extends BaseModel {
|
class Revision extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
documentId: string;
|
documentId: string;
|
||||||
@@ -20,8 +21,7 @@ class Revision extends BaseModel {
|
|||||||
/** HTML string representing the revision as a diff from the previous version */
|
/** HTML string representing the revision as a diff from the previous version */
|
||||||
html: string;
|
html: string;
|
||||||
|
|
||||||
createdAt: string;
|
@Relation(() => User)
|
||||||
|
|
||||||
createdBy: User;
|
createdBy: User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class SearchQuery extends BaseModel {
|
class SearchQuery extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
query: string;
|
query: string;
|
||||||
|
|
||||||
createdAt: string;
|
|
||||||
|
|
||||||
delete = async () => {
|
delete = async () => {
|
||||||
this.isSaving = true;
|
this.isSaving = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class Share extends BaseModel {
|
class Share extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import type StarsStore from "~/stores/StarsStore";
|
||||||
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class Star extends BaseModel {
|
class Star extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@Field
|
@Field
|
||||||
@@ -13,8 +14,7 @@ class Star extends BaseModel {
|
|||||||
|
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
|
|
||||||
createdAt: string;
|
store: StarsStore;
|
||||||
updatedAt: string;
|
|
||||||
|
|
||||||
next(): Star | undefined {
|
next(): Star | undefined {
|
||||||
const index = this.store.orderedData.indexOf(this);
|
const index = this.store.orderedData.indexOf(this);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subscription represents a request for a user to receive notifications for
|
* A subscription represents a request for a user to receive notifications for
|
||||||
* a document.
|
* a document.
|
||||||
*/
|
*/
|
||||||
class Subscription extends BaseModel {
|
class Subscription extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
@@ -21,9 +21,6 @@ class Subscription extends BaseModel {
|
|||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
event: string;
|
event: string;
|
||||||
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Subscription;
|
export default Subscription;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { computed, observable } from "mobx";
|
|||||||
import { TeamPreferenceDefaults } from "@shared/constants";
|
import { TeamPreferenceDefaults } from "@shared/constants";
|
||||||
import { TeamPreference, TeamPreferences } from "@shared/types";
|
import { TeamPreference, TeamPreferences } from "@shared/types";
|
||||||
import { stringToColor } from "@shared/utils/color";
|
import { stringToColor } from "@shared/utils/color";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class Team extends BaseModel {
|
class Team extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from "@shared/types";
|
} from "@shared/types";
|
||||||
import type { NotificationSettings } from "@shared/types";
|
import type { NotificationSettings } from "@shared/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import ParanoidModel from "./ParanoidModel";
|
import ParanoidModel from "./base/ParanoidModel";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class User extends ParanoidModel {
|
class User extends ParanoidModel {
|
||||||
@@ -96,7 +96,9 @@ class User extends ParanoidModel {
|
|||||||
get separateEditMode(): boolean {
|
get separateEditMode(): boolean {
|
||||||
return !this.getPreference(
|
return !this.getPreference(
|
||||||
UserPreference.SeamlessEdit,
|
UserPreference.SeamlessEdit,
|
||||||
this.store.rootStore.auth.team.getPreference(TeamPreference.SeamlessEdit)
|
this.store.rootStore.auth?.team?.getPreference(
|
||||||
|
TeamPreference.SeamlessEdit
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { action } from "mobx";
|
import { action } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
|
import Model from "./base/Model";
|
||||||
|
|
||||||
class View extends BaseModel {
|
class View extends Model {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
documentId: string;
|
documentId: string;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import BaseModel from "./BaseModel";
|
import Model from "./base/Model";
|
||||||
import Field from "./decorators/Field";
|
import Field from "./decorators/Field";
|
||||||
|
|
||||||
class WebhookSubscription extends BaseModel {
|
class WebhookSubscription extends Model {
|
||||||
@Field
|
@Field
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import pick from "lodash/pick";
|
import pick from "lodash/pick";
|
||||||
import { set, observable } from "mobx";
|
import { set, observable, action } from "mobx";
|
||||||
|
import type Store from "~/stores/base/Store";
|
||||||
import Logger from "~/utils/Logger";
|
import Logger from "~/utils/Logger";
|
||||||
import { getFieldsForModel } from "./decorators/Field";
|
import { getFieldsForModel } from "../decorators/Field";
|
||||||
|
|
||||||
export default abstract class BaseModel {
|
export default abstract class Model {
|
||||||
@observable
|
@observable
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@@ -17,12 +18,12 @@ export default abstract class BaseModel {
|
|||||||
|
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|
||||||
store: any;
|
store: Store<Model>;
|
||||||
|
|
||||||
constructor(fields: Record<string, any>, store: any) {
|
constructor(fields: Record<string, any>, store: Store<Model>) {
|
||||||
this.updateFromJson(fields);
|
|
||||||
this.isNew = !this.id;
|
|
||||||
this.store = store;
|
this.store = store;
|
||||||
|
this.updateData(fields);
|
||||||
|
this.isNew = !this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
save = async (
|
save = async (
|
||||||
@@ -59,10 +60,14 @@ export default abstract class BaseModel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateFromJson = (data: any) => {
|
updateData = action((data: any) => {
|
||||||
set(this, { ...data, isNew: false });
|
for (const key in data) {
|
||||||
|
this[key] = data[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isNew = false;
|
||||||
this.persistedAttributes = this.toAPI();
|
this.persistedAttributes = this.toAPI();
|
||||||
};
|
});
|
||||||
|
|
||||||
fetch = (options?: any) => this.store.fetch(this.id, options);
|
fetch = (options?: any) => this.store.fetch(this.id, options);
|
||||||
|
|
||||||
@@ -134,5 +139,5 @@ export default abstract class BaseModel {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected persistedAttributes: Partial<BaseModel> = {};
|
protected persistedAttributes: Partial<Model> = {};
|
||||||
}
|
}
|
||||||
5
app/models/base/ParanoidModel.ts
Normal file
5
app/models/base/ParanoidModel.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Model from "./Model";
|
||||||
|
|
||||||
|
export default abstract class ParanoidModel extends Model {
|
||||||
|
deletedAt: string | undefined;
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import type Model from "../base/Model";
|
||||||
|
|
||||||
const fields = new Map();
|
const fields = new Map();
|
||||||
|
|
||||||
export const getFieldsForModel = (target: any) =>
|
export const getFieldsForModel = (target: Model) =>
|
||||||
fields.get(target.constructor.name);
|
fields.get(target.constructor.name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
59
app/models/decorators/Relation.ts
Normal file
59
app/models/decorators/Relation.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import invariant from "invariant";
|
||||||
|
import type Model from "../base/Model";
|
||||||
|
|
||||||
|
type RelationOptions = {
|
||||||
|
/** Whether this relation is required */
|
||||||
|
required?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A decorator that records this key as a relation field on the model.
|
||||||
|
* Properties decorated with @Relation will merge and read their data from
|
||||||
|
* the associated store.
|
||||||
|
*
|
||||||
|
* @param classResolver A function that returns the class of the relation
|
||||||
|
* @param options Optional options for the relation definition
|
||||||
|
*/
|
||||||
|
export default function Relation<T extends typeof Model>(
|
||||||
|
classResolver: () => T,
|
||||||
|
options?: RelationOptions
|
||||||
|
) {
|
||||||
|
return function (target: any, propertyKey: string) {
|
||||||
|
const idKey = `${String(propertyKey)}Id`;
|
||||||
|
const relationClass = classResolver();
|
||||||
|
const relationClassName = relationClass.name;
|
||||||
|
|
||||||
|
Object.defineProperty(target, propertyKey, {
|
||||||
|
get() {
|
||||||
|
const id: string | undefined = this[idKey];
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const store =
|
||||||
|
this.store.rootStore[`${relationClassName.toLowerCase()}s`];
|
||||||
|
invariant(store, `Store for ${relationClassName} not found`);
|
||||||
|
|
||||||
|
return store.get(id);
|
||||||
|
},
|
||||||
|
set(newValue: Model | Partial<Model> | undefined) {
|
||||||
|
this[idKey] = newValue ? newValue.id : undefined;
|
||||||
|
|
||||||
|
if (newValue) {
|
||||||
|
const store =
|
||||||
|
this.store.rootStore[`${relationClassName.toLowerCase()}s`];
|
||||||
|
invariant(store, `Store for ${relationClassName} not found`);
|
||||||
|
|
||||||
|
store.add(newValue);
|
||||||
|
} else if (options?.required) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot set required ${String(propertyKey)} to undefined`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { PAGINATION_SYMBOL } from "~/stores/BaseStore";
|
import { PAGINATION_SYMBOL } from "~/stores/base/Store";
|
||||||
import Collection from "~/models/Collection";
|
import Collection from "~/models/Collection";
|
||||||
import User from "~/models/User";
|
import User from "~/models/User";
|
||||||
import Avatar from "~/components/Avatar";
|
import Avatar from "~/components/Avatar";
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function GroupNew({ onSubmit }: Props) {
|
|||||||
const { showToast } = useToasts();
|
const { showToast } = useToasts();
|
||||||
const [name, setName] = React.useState<string | undefined>();
|
const [name, setName] = React.useState<string | undefined>();
|
||||||
const [isSaving, setIsSaving] = React.useState(false);
|
const [isSaving, setIsSaving] = React.useState(false);
|
||||||
const [group, setGroup] = React.useState();
|
const [group, setGroup] = React.useState<Group | undefined>();
|
||||||
|
|
||||||
const handleSubmit = async (ev: React.SyntheticEvent) => {
|
const handleSubmit = async (ev: React.SyntheticEvent) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@@ -35,7 +35,8 @@ function GroupNew({ onSubmit }: Props) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setGroup(await group.save());
|
await group.save();
|
||||||
|
setGroup(group);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(err.message, {
|
showToast(err.message, {
|
||||||
type: "error",
|
type: "error",
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import styled from "styled-components";
|
|||||||
import breakpoint from "styled-components-breakpoint";
|
import breakpoint from "styled-components-breakpoint";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { DateFilter as TDateFilter } from "@shared/types";
|
import { DateFilter as TDateFilter } from "@shared/types";
|
||||||
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/BaseStore";
|
|
||||||
import { SearchParams } from "~/stores/DocumentsStore";
|
import { SearchParams } from "~/stores/DocumentsStore";
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import { DEFAULT_PAGINATION_LIMIT } from "~/stores/base/Store";
|
||||||
import ArrowKeyNavigation from "~/components/ArrowKeyNavigation";
|
import ArrowKeyNavigation from "~/components/ArrowKeyNavigation";
|
||||||
import DocumentListItem from "~/components/DocumentListItem";
|
import DocumentListItem from "~/components/DocumentListItem";
|
||||||
import Empty from "~/components/Empty";
|
import Empty from "~/components/Empty";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as React from "react";
|
|||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { PAGINATION_SYMBOL } from "~/stores/BaseStore";
|
import { PAGINATION_SYMBOL } from "~/stores/base/Store";
|
||||||
import User from "~/models/User";
|
import User from "~/models/User";
|
||||||
import Invite from "~/scenes/Invite";
|
import Invite from "~/scenes/Invite";
|
||||||
import { Action } from "~/components/Actions";
|
import { Action } from "~/components/Actions";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { LinkIcon, WarningIcon } from "outline-icons";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useTranslation, Trans } from "react-i18next";
|
import { useTranslation, Trans } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { PAGINATION_SYMBOL } from "~/stores/BaseStore";
|
import { PAGINATION_SYMBOL } from "~/stores/base/Store";
|
||||||
import Share from "~/models/Share";
|
import Share from "~/models/Share";
|
||||||
import Heading from "~/components/Heading";
|
import Heading from "~/components/Heading";
|
||||||
import Notice from "~/components/Notice";
|
import Notice from "~/components/Notice";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import ApiKey from "~/models/ApiKey";
|
import ApiKey from "~/models/ApiKey";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class ApiKeysStore extends BaseStore<ApiKey> {
|
export default class ApiKeysStore extends Store<ApiKey> {
|
||||||
actions = [RPCAction.List, RPCAction.Create, RPCAction.Delete];
|
actions = [RPCAction.List, RPCAction.Create, RPCAction.Delete];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ export default class AuthStore {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
rehydrate(data: PersistedData) {
|
rehydrate(data: PersistedData) {
|
||||||
this.user = data.user ? new User(data.user, this) : undefined;
|
this.user = data.user ? new User(data.user, this as any) : undefined;
|
||||||
this.team = data.team ? new Team(data.team, this) : undefined;
|
this.team = data.team ? new Team(data.team, this as any) : undefined;
|
||||||
this.collaborationToken = data.collaborationToken;
|
this.collaborationToken = data.collaborationToken;
|
||||||
this.lastSignedIn = getCookie("lastSignedIn");
|
this.lastSignedIn = getCookie("lastSignedIn");
|
||||||
this.addPolicies(data.policies);
|
this.addPolicies(data.policies);
|
||||||
@@ -188,8 +188,8 @@ export default class AuthStore {
|
|||||||
runInAction("AuthStore#fetch", () => {
|
runInAction("AuthStore#fetch", () => {
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
const { user, team } = res.data;
|
const { user, team } = res.data;
|
||||||
this.user = new User(user, this);
|
this.user = new User(user, this as any);
|
||||||
this.team = new Team(team, this);
|
this.team = new Team(team, this as any);
|
||||||
this.availableTeams = res.data.availableTeams;
|
this.availableTeams = res.data.availableTeams;
|
||||||
this.collaborationToken = res.data.collaborationToken;
|
this.collaborationToken = res.data.collaborationToken;
|
||||||
|
|
||||||
@@ -283,13 +283,13 @@ export default class AuthStore {
|
|||||||
const previousData = this.user?.toAPI();
|
const previousData = this.user?.toAPI();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.user?.updateFromJson(params);
|
this.user?.updateData(params);
|
||||||
const res = await client.post(`/users.update`, params);
|
const res = await client.post(`/users.update`, params);
|
||||||
invariant(res?.data, "User response not available");
|
invariant(res?.data, "User response not available");
|
||||||
this.user?.updateFromJson(res.data);
|
this.user?.updateData(res.data);
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.user?.updateFromJson(previousData);
|
this.user?.updateData(previousData);
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
this.isSaving = false;
|
this.isSaving = false;
|
||||||
@@ -310,13 +310,13 @@ export default class AuthStore {
|
|||||||
const previousData = this.team?.toAPI();
|
const previousData = this.team?.toAPI();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.team?.updateFromJson(params);
|
this.team?.updateData(params);
|
||||||
const res = await client.post(`/team.update`, params);
|
const res = await client.post(`/team.update`, params);
|
||||||
invariant(res?.data, "Team response not available");
|
invariant(res?.data, "Team response not available");
|
||||||
this.team?.updateFromJson(res.data);
|
this.team?.updateData(res.data);
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.team?.updateFromJson(previousData);
|
this.team?.updateData(previousData);
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
this.isSaving = false;
|
this.isSaving = false;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import AuthenticationProvider from "~/models/AuthenticationProvider";
|
import AuthenticationProvider from "~/models/AuthenticationProvider";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class AuthenticationProvidersStore extends BaseStore<AuthenticationProvider> {
|
export default class AuthenticationProvidersStore extends Store<AuthenticationProvider> {
|
||||||
actions = [RPCAction.List, RPCAction.Update];
|
actions = [RPCAction.List, RPCAction.Update];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { CollectionPermission } from "@shared/types";
|
|||||||
import CollectionGroupMembership from "~/models/CollectionGroupMembership";
|
import CollectionGroupMembership from "~/models/CollectionGroupMembership";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore, { PAGINATION_SYMBOL, RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { PAGINATION_SYMBOL, RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class CollectionGroupMembershipsStore extends BaseStore<CollectionGroupMembership> {
|
export default class CollectionGroupMembershipsStore extends Store<CollectionGroupMembership> {
|
||||||
actions = [RPCAction.Create, RPCAction.Delete];
|
actions = [RPCAction.Create, RPCAction.Delete];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import {
|
|||||||
import Collection from "~/models/Collection";
|
import Collection from "~/models/Collection";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import { AuthorizationError, NotFoundError } from "~/utils/errors";
|
import { AuthorizationError, NotFoundError } from "~/utils/errors";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
enum DocumentPathItemType {
|
enum DocumentPathItemType {
|
||||||
Collection = "collection",
|
Collection = "collection",
|
||||||
@@ -32,7 +32,7 @@ export type DocumentPath = DocumentPathItem & {
|
|||||||
path: DocumentPathItem[];
|
path: DocumentPathItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class CollectionsStore extends BaseStore<Collection> {
|
export default class CollectionsStore extends Store<Collection> {
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
super(rootStore, Collection);
|
super(rootStore, Collection);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import Comment from "~/models/Comment";
|
|||||||
import Document from "~/models/Document";
|
import Document from "~/models/Document";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
export default class CommentsStore extends BaseStore<Comment> {
|
export default class CommentsStore extends Store<Comment> {
|
||||||
apiEndpoint = "comments";
|
apiEndpoint = "comments";
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { subtractDate } from "@shared/utils/date";
|
|||||||
import { bytesToHumanReadable } from "@shared/utils/files";
|
import { bytesToHumanReadable } from "@shared/utils/files";
|
||||||
import naturalSort from "@shared/utils/naturalSort";
|
import naturalSort from "@shared/utils/naturalSort";
|
||||||
import { DocumentValidation } from "@shared/validations";
|
import { DocumentValidation } from "@shared/validations";
|
||||||
import BaseStore from "~/stores/BaseStore";
|
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import Store from "~/stores/base/Store";
|
||||||
import Document from "~/models/Document";
|
import Document from "~/models/Document";
|
||||||
import env from "~/env";
|
import env from "~/env";
|
||||||
import { FetchOptions, PaginationParams, SearchResult } from "~/types";
|
import { FetchOptions, PaginationParams, SearchResult } from "~/types";
|
||||||
@@ -38,7 +38,7 @@ type ImportOptions = {
|
|||||||
publish?: boolean;
|
publish?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class DocumentsStore extends BaseStore<Document> {
|
export default class DocumentsStore extends Store<Document> {
|
||||||
sharedCache: Map<
|
sharedCache: Map<
|
||||||
string,
|
string,
|
||||||
{ sharedTree: NavigationNode; team: PublicTeam } | undefined
|
{ sharedTree: NavigationNode; team: PublicTeam } | undefined
|
||||||
@@ -574,7 +574,7 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
invariant(res?.data, "Data should be available");
|
invariant(res?.data, "Data should be available");
|
||||||
const collection = this.getCollectionForDocument(document);
|
const collection = this.getCollectionForDocument(document);
|
||||||
if (collection) {
|
if (collection) {
|
||||||
collection.refresh();
|
await collection.refresh();
|
||||||
}
|
}
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
return this.add(res.data);
|
return this.add(res.data);
|
||||||
@@ -686,7 +686,7 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
const document = this.add(res.data.document);
|
const document = this.add(res.data.document);
|
||||||
const collection = this.getCollectionForDocument(document);
|
const collection = this.getCollectionForDocument(document);
|
||||||
collection?.updateFromJson(res.data.collection);
|
collection?.updateData(res.data.collection);
|
||||||
return document;
|
return document;
|
||||||
} finally {
|
} finally {
|
||||||
this.isSaving = false;
|
this.isSaving = false;
|
||||||
@@ -711,7 +711,7 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
|
|
||||||
const collection = this.getCollectionForDocument(document);
|
const collection = this.getCollectionForDocument(document);
|
||||||
if (collection) {
|
if (collection) {
|
||||||
collection.refresh();
|
await collection.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,12 +722,12 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
});
|
});
|
||||||
runInAction("Document#archive", () => {
|
runInAction("Document#archive", () => {
|
||||||
invariant(res?.data, "Data should be available");
|
invariant(res?.data, "Data should be available");
|
||||||
document.updateFromJson(res.data);
|
document.updateData(res.data);
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
});
|
});
|
||||||
const collection = this.getCollectionForDocument(document);
|
const collection = this.getCollectionForDocument(document);
|
||||||
if (collection) {
|
if (collection) {
|
||||||
collection.refresh();
|
await collection.refresh();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -746,12 +746,12 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
});
|
});
|
||||||
runInAction("Document#restore", () => {
|
runInAction("Document#restore", () => {
|
||||||
invariant(res?.data, "Data should be available");
|
invariant(res?.data, "Data should be available");
|
||||||
document.updateFromJson(res.data);
|
document.updateData(res.data);
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
});
|
});
|
||||||
const collection = this.getCollectionForDocument(document);
|
const collection = this.getCollectionForDocument(document);
|
||||||
if (collection) {
|
if (collection) {
|
||||||
collection.refresh();
|
await collection.refresh();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -764,9 +764,9 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
|
|
||||||
runInAction("Document#unpublish", () => {
|
runInAction("Document#unpublish", () => {
|
||||||
invariant(res?.data, "Data should be available");
|
invariant(res?.data, "Data should be available");
|
||||||
document.updateFromJson(res.data.document);
|
document.updateData(res.data.document);
|
||||||
const collection = this.getCollectionForDocument(document);
|
const collection = this.getCollectionForDocument(document);
|
||||||
collection?.updateFromJson(res.data.collection);
|
collection?.updateData(res.data.collection);
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import filter from "lodash/filter";
|
|||||||
import sortBy from "lodash/sortBy";
|
import sortBy from "lodash/sortBy";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import Event from "~/models/Event";
|
import Event from "~/models/Event";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class EventsStore extends BaseStore<Event> {
|
export default class EventsStore extends Store<Event> {
|
||||||
actions = [RPCAction.List];
|
actions = [RPCAction.List];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import orderBy from "lodash/orderBy";
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import { FileOperationType } from "@shared/types";
|
import { FileOperationType } from "@shared/types";
|
||||||
import FileOperation from "~/models/FileOperation";
|
import FileOperation from "~/models/FileOperation";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class FileOperationsStore extends BaseStore<FileOperation> {
|
export default class FileOperationsStore extends Store<FileOperation> {
|
||||||
actions = [RPCAction.List, RPCAction.Info, RPCAction.Delete];
|
actions = [RPCAction.List, RPCAction.Info, RPCAction.Delete];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { action, runInAction } from "mobx";
|
|||||||
import GroupMembership from "~/models/GroupMembership";
|
import GroupMembership from "~/models/GroupMembership";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class GroupMembershipsStore extends BaseStore<GroupMembership> {
|
export default class GroupMembershipsStore extends Store<GroupMembership> {
|
||||||
actions = [RPCAction.Create, RPCAction.Delete];
|
actions = [RPCAction.Create, RPCAction.Delete];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import naturalSort from "@shared/utils/naturalSort";
|
|||||||
import Group from "~/models/Group";
|
import Group from "~/models/Group";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
type FetchPageParams = PaginationParams & { query?: string };
|
type FetchPageParams = PaginationParams & { query?: string };
|
||||||
|
|
||||||
export default class GroupsStore extends BaseStore<Group> {
|
export default class GroupsStore extends Store<Group> {
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
super(rootStore, Group);
|
super(rootStore, Group);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import filter from "lodash/filter";
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import { IntegrationService } from "@shared/types";
|
import { IntegrationService } from "@shared/types";
|
||||||
import naturalSort from "@shared/utils/naturalSort";
|
import naturalSort from "@shared/utils/naturalSort";
|
||||||
import BaseStore from "~/stores/BaseStore";
|
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import Store from "~/stores/base/Store";
|
||||||
import Integration from "~/models/Integration";
|
import Integration from "~/models/Integration";
|
||||||
|
|
||||||
class IntegrationsStore extends BaseStore<Integration> {
|
class IntegrationsStore extends Store<Integration> {
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
super(rootStore, Integration);
|
super(rootStore, Integration);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { CollectionPermission } from "@shared/types";
|
|||||||
import Membership from "~/models/Membership";
|
import Membership from "~/models/Membership";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore, { PAGINATION_SYMBOL, RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { PAGINATION_SYMBOL, RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class MembershipsStore extends BaseStore<Membership> {
|
export default class MembershipsStore extends Store<Membership> {
|
||||||
actions = [RPCAction.Create, RPCAction.Delete];
|
actions = [RPCAction.Create, RPCAction.Delete];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { action, computed, runInAction } from "mobx";
|
|||||||
import Notification from "~/models/Notification";
|
import Notification from "~/models/Notification";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class NotificationsStore extends BaseStore<Notification> {
|
export default class NotificationsStore extends Store<Notification> {
|
||||||
actions = [RPCAction.List, RPCAction.Update];
|
actions = [RPCAction.List, RPCAction.Update];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { action, runInAction, computed } from "mobx";
|
|||||||
import Pin from "~/models/Pin";
|
import Pin from "~/models/Pin";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
type FetchParams = PaginationParams & { collectionId?: string };
|
type FetchParams = PaginationParams & { collectionId?: string };
|
||||||
|
|
||||||
export default class PinsStore extends BaseStore<Pin> {
|
export default class PinsStore extends Store<Pin> {
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
super(rootStore, Pin);
|
super(rootStore, Pin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import Policy from "~/models/Policy";
|
import Policy from "~/models/Policy";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
export default class PoliciesStore extends BaseStore<Policy> {
|
export default class PoliciesStore extends Store<Policy> {
|
||||||
actions = [];
|
actions = [];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import invariant from "invariant";
|
import invariant from "invariant";
|
||||||
import filter from "lodash/filter";
|
import filter from "lodash/filter";
|
||||||
import { action, runInAction } from "mobx";
|
import { action, runInAction } from "mobx";
|
||||||
import BaseStore, { RPCAction } from "~/stores/BaseStore";
|
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import Store, { RPCAction } from "~/stores/base/Store";
|
||||||
import Revision from "~/models/Revision";
|
import Revision from "~/models/Revision";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
|
|
||||||
export default class RevisionsStore extends BaseStore<Revision> {
|
export default class RevisionsStore extends Store<Revision> {
|
||||||
actions = [RPCAction.List, RPCAction.Info];
|
actions = [RPCAction.List, RPCAction.Info];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import uniqBy from "lodash/uniqBy";
|
import uniqBy from "lodash/uniqBy";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import SearchQuery from "~/models/SearchQuery";
|
import SearchQuery from "~/models/SearchQuery";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class SearchesStore extends BaseStore<SearchQuery> {
|
export default class SearchesStore extends Store<SearchQuery> {
|
||||||
actions = [RPCAction.List, RPCAction.Delete];
|
actions = [RPCAction.List, RPCAction.Delete];
|
||||||
|
|
||||||
apiEndpoint = "searches";
|
apiEndpoint = "searches";
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import sortBy from "lodash/sortBy";
|
|||||||
import { action, computed } from "mobx";
|
import { action, computed } from "mobx";
|
||||||
import Share from "~/models/Share";
|
import Share from "~/models/Share";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class SharesStore extends BaseStore<Share> {
|
export default class SharesStore extends Store<Share> {
|
||||||
actions = [
|
actions = [
|
||||||
RPCAction.Info,
|
RPCAction.Info,
|
||||||
RPCAction.List,
|
RPCAction.List,
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import { action, runInAction, computed } from "mobx";
|
|||||||
import Star from "~/models/Star";
|
import Star from "~/models/Star";
|
||||||
import { PaginationParams } from "~/types";
|
import { PaginationParams } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
export default class StarsStore extends BaseStore<Star> {
|
export default class StarsStore extends Store<Star> {
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
super(rootStore, Star);
|
super(rootStore, Star);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import Subscription from "~/models/Subscription";
|
import Subscription from "~/models/Subscription";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class SubscriptionsStore extends BaseStore<Subscription> {
|
export default class SubscriptionsStore extends Store<Subscription> {
|
||||||
actions = [RPCAction.List, RPCAction.Create, RPCAction.Delete];
|
actions = [RPCAction.List, RPCAction.Create, RPCAction.Delete];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { observable, computed, action, runInAction } from "mobx";
|
|||||||
import { UserRole } from "@shared/types";
|
import { UserRole } from "@shared/types";
|
||||||
import User from "~/models/User";
|
import User from "~/models/User";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store from "./base/Store";
|
||||||
|
|
||||||
export default class UsersStore extends BaseStore<User> {
|
export default class UsersStore extends Store<User> {
|
||||||
@observable
|
@observable
|
||||||
counts: {
|
counts: {
|
||||||
active: number;
|
active: number;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import find from "lodash/find";
|
|||||||
import orderBy from "lodash/orderBy";
|
import orderBy from "lodash/orderBy";
|
||||||
import reduce from "lodash/reduce";
|
import reduce from "lodash/reduce";
|
||||||
import View from "~/models/View";
|
import View from "~/models/View";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class ViewsStore extends BaseStore<View> {
|
export default class ViewsStore extends Store<View> {
|
||||||
actions = [RPCAction.List, RPCAction.Create];
|
actions = [RPCAction.List, RPCAction.Create];
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
constructor(rootStore: RootStore) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import WebhookSubscription from "~/models/WebhookSubscription";
|
import WebhookSubscription from "~/models/WebhookSubscription";
|
||||||
import BaseStore, { RPCAction } from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
|
import Store, { RPCAction } from "./base/Store";
|
||||||
|
|
||||||
export default class WebhookSubscriptionsStore extends BaseStore<WebhookSubscription> {
|
export default class WebhookSubscriptionsStore extends Store<WebhookSubscription> {
|
||||||
actions = [
|
actions = [
|
||||||
RPCAction.List,
|
RPCAction.List,
|
||||||
RPCAction.Create,
|
RPCAction.Create,
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import orderBy from "lodash/orderBy";
|
|||||||
import { observable, action, computed, runInAction } from "mobx";
|
import { observable, action, computed, runInAction } from "mobx";
|
||||||
import { Class } from "utility-types";
|
import { Class } from "utility-types";
|
||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
import BaseModel from "~/models/BaseModel";
|
|
||||||
import Policy from "~/models/Policy";
|
import Policy from "~/models/Policy";
|
||||||
|
import Model from "~/models/base/Model";
|
||||||
import { PaginationParams, PartialWithId } from "~/types";
|
import { PaginationParams, PartialWithId } from "~/types";
|
||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import { AuthorizationError, NotFoundError } from "~/utils/errors";
|
import { AuthorizationError, NotFoundError } from "~/utils/errors";
|
||||||
@@ -25,7 +25,7 @@ export const DEFAULT_PAGINATION_LIMIT = 25;
|
|||||||
|
|
||||||
export const PAGINATION_SYMBOL = Symbol.for("pagination");
|
export const PAGINATION_SYMBOL = Symbol.for("pagination");
|
||||||
|
|
||||||
export default abstract class BaseStore<T extends BaseModel> {
|
export default abstract class Store<T extends Model> {
|
||||||
@observable
|
@observable
|
||||||
data: Map<string, T> = new Map();
|
data: Map<string, T> = new Map();
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ export default abstract class BaseStore<T extends BaseModel> {
|
|||||||
const existingModel = this.data.get(item.id);
|
const existingModel = this.data.get(item.id);
|
||||||
|
|
||||||
if (existingModel) {
|
if (existingModel) {
|
||||||
existingModel.updateFromJson(item);
|
existingModel.updateData(item);
|
||||||
return existingModel;
|
return existingModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
import RootStore from "~/stores/RootStore";
|
import RootStore from "~/stores/RootStore";
|
||||||
|
import env from "~/env";
|
||||||
|
|
||||||
const stores = new RootStore();
|
const stores = new RootStore();
|
||||||
|
|
||||||
|
// Expose stores on window in development for easier debugging
|
||||||
|
if (env.ENVIRONMENT === "development") {
|
||||||
|
window.stores = stores;
|
||||||
|
}
|
||||||
|
|
||||||
export default stores;
|
export default stores;
|
||||||
|
|||||||
4
app/typings/window.d.ts
vendored
4
app/typings/window.d.ts
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
import type RootStore from "~/stores/RootStore";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
/**
|
/**
|
||||||
@@ -10,6 +12,8 @@ declare global {
|
|||||||
dataLayer: any[];
|
dataLayer: any[];
|
||||||
gtag: (...args: any[]) => void;
|
gtag: (...args: any[]) => void;
|
||||||
|
|
||||||
|
stores: RootStore;
|
||||||
|
|
||||||
DesktopBridge: {
|
DesktopBridge: {
|
||||||
/**
|
/**
|
||||||
* The name of the platform running on.
|
* The name of the platform running on.
|
||||||
|
|||||||
Reference in New Issue
Block a user