fix: Load relationships on search page load (#6295)
This commit is contained in:
@@ -68,6 +68,10 @@ const DocumentBreadcrumb: React.FC<Props> = ({
|
|||||||
? collections.get(document.collectionId)
|
? collections.get(document.collectionId)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
void document.loadRelations();
|
||||||
|
}, [document]);
|
||||||
|
|
||||||
let collectionNode: MenuInternalLink | undefined;
|
let collectionNode: MenuInternalLink | undefined;
|
||||||
|
|
||||||
if (collection) {
|
if (collection) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { set, observable, action } from "mobx";
|
|||||||
import type Store from "~/stores/base/Store";
|
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";
|
||||||
|
import { getRelationsForModelClass } from "../decorators/Relation";
|
||||||
|
|
||||||
export default abstract class Model {
|
export default abstract class Model {
|
||||||
static modelName: string;
|
static modelName: string;
|
||||||
@@ -16,6 +17,7 @@ export default abstract class Model {
|
|||||||
@observable
|
@observable
|
||||||
isNew: boolean;
|
isNew: boolean;
|
||||||
|
|
||||||
|
@observable
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
@@ -29,6 +31,36 @@ export default abstract class Model {
|
|||||||
this.isNew = !this.id;
|
this.isNew = !this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures all the defined relations for the model are in memory
|
||||||
|
*
|
||||||
|
* @returns A promise that resolves when loading is complete.
|
||||||
|
*/
|
||||||
|
async loadRelations() {
|
||||||
|
const relations = getRelationsForModelClass(
|
||||||
|
this.constructor as typeof Model
|
||||||
|
);
|
||||||
|
if (!relations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const properties of relations.values()) {
|
||||||
|
const store = this.store.rootStore.getStoreForModelName(
|
||||||
|
properties.relationClassResolver().modelName
|
||||||
|
);
|
||||||
|
if ("fetch" in store) {
|
||||||
|
await store.fetch(this[properties.idKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the model to the server API
|
||||||
|
*
|
||||||
|
* @param params Specific fields to save, if not provided the model will be serialized
|
||||||
|
* @param options Options to pass to the store
|
||||||
|
* @returns A promise that resolves with the updated model
|
||||||
|
*/
|
||||||
save = async (
|
save = async (
|
||||||
params?: Record<string, any>,
|
params?: Record<string, any>,
|
||||||
options?: Record<string, string | boolean | number | undefined>
|
options?: Record<string, string | boolean | number | undefined>
|
||||||
@@ -93,7 +125,7 @@ export default abstract class Model {
|
|||||||
* Returns a plain object representation of fields on the model for
|
* Returns a plain object representation of fields on the model for
|
||||||
* persistence to the server API
|
* persistence to the server API
|
||||||
*
|
*
|
||||||
* @returns {Record<string, any>}
|
* @returns A plain object representation of the model
|
||||||
*/
|
*/
|
||||||
toAPI = (): Record<string, any> => {
|
toAPI = (): Record<string, any> => {
|
||||||
const fields = getFieldsForModel(this);
|
const fields = getFieldsForModel(this);
|
||||||
@@ -104,7 +136,7 @@ export default abstract class Model {
|
|||||||
* Returns a plain object representation of all the properties on the model
|
* Returns a plain object representation of all the properties on the model
|
||||||
* overrides the native toJSON method to avoid attempting to serialize store
|
* overrides the native toJSON method to avoid attempting to serialize store
|
||||||
*
|
*
|
||||||
* @returns {Record<string, any>}
|
* @returns A plain object representation of the model
|
||||||
*/
|
*/
|
||||||
toJSON() {
|
toJSON() {
|
||||||
const output: Partial<typeof this> = {};
|
const output: Partial<typeof this> = {};
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ export const getInverseRelationsForModelClass = (targetClass: typeof Model) => {
|
|||||||
return inverseRelations;
|
return inverseRelations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getRelationsForModelClass = (targetClass: typeof Model) =>
|
||||||
|
relations.get(targetClass.modelName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A decorator that records this key as a relation field on the model.
|
* A decorator that records this key as a relation field on the model.
|
||||||
* Properties decorated with @Relation will merge and read their data from
|
* Properties decorated with @Relation will merge and read their data from
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from "@shared/types";
|
} from "@shared/types";
|
||||||
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 RootStore from "./RootStore";
|
import RootStore from "./RootStore";
|
||||||
import Store from "./base/Store";
|
import Store from "./base/Store";
|
||||||
|
|
||||||
@@ -164,32 +163,10 @@ export default class CollectionsStore extends Store<Collection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async fetch(
|
async fetch(id: string, options?: { force: boolean }): Promise<Collection> {
|
||||||
id: string,
|
const model = await super.fetch(id, options);
|
||||||
options: Record<string, any> = {}
|
await model.fetchDocuments(options);
|
||||||
): Promise<Collection> {
|
return model;
|
||||||
const item = this.get(id) || this.getByUrl(id);
|
|
||||||
if (item && !options.force) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
this.isFetching = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await client.post(`/collections.info`, {
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
invariant(res?.data, "Collection not available");
|
|
||||||
this.addPolicies(res.policies);
|
|
||||||
return this.add(res.data);
|
|
||||||
} catch (err) {
|
|
||||||
if (err instanceof AuthorizationError || err instanceof NotFoundError) {
|
|
||||||
this.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
this.isFetching = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
|
|||||||
Reference in New Issue
Block a user