strapi-plugin-i-relate-to-this 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/admin/index.js +72 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/index.mjs +73 -0
- package/dist/admin/index.mjs.map +1 -0
- package/dist/server/index.js +198 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +196 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# strapi-plugin-i-relate-to-this
|
|
2
|
+
|
|
3
|
+
List unidirectional relations (in components) to the current content entity.
|
|
4
|
+
|
|
5
|
+
## What does this do
|
|
6
|
+
|
|
7
|
+
Uni-directional relations are only visible on one side of the relation. This plugin will create a list of content entities that have a uni relation to the current entity.
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
Strapi 5 allows you to relate (from source) to draft content (the target). When you publish that (target) related entity, it is not directly synced to the published version of the (source) entity that relates to it. It (the target) will remain unpublished until you publish the (source) entity.
|
|
12
|
+
|
|
13
|
+
Imagine having hunderds of relations to some campaign which ends, you unpublish it, and next month you publish it again. Good luck finding all uni-relations inside of components to it. This plugin will help you!
|
|
14
|
+
|
|
15
|
+
This plugin lists all entities that have uni-relations (deeply nested in DZs/components) to the current entity you are editing. It will warn you (⚠) when the (source) entity is published but the related (target) entity does not contain the relation in their published version.
|
|
16
|
+
|
|
17
|
+
## Help wanted
|
|
18
|
+
|
|
19
|
+
Currently, I have been focussing on getting the data from the db. The UI isn't pretty. Feel free to make a PR to make it pretty, or to improve the lookup logic. Thanks <3
|
|
20
|
+
|
|
21
|
+
## TODO
|
|
22
|
+
|
|
23
|
+
- Create a pretty UI
|
|
24
|
+
- Maybe I should not auto-load the list, but have a button that requests it. (there's a lot of db queries happening to get this data)
|
|
25
|
+
|
|
26
|
+
## Related issues
|
|
27
|
+
|
|
28
|
+
https://github.com/strapi/strapi/issues/23460
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
3
|
+
const react = require("react");
|
|
4
|
+
const reactIntl = require("react-intl");
|
|
5
|
+
const reactRouterDom = require("react-router-dom");
|
|
6
|
+
const designSystem = require("@strapi/design-system");
|
|
7
|
+
const admin = require("@strapi/strapi/admin");
|
|
8
|
+
const List = () => {
|
|
9
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
10
|
+
const { id, slug } = reactRouterDom.useParams();
|
|
11
|
+
const [params] = reactRouterDom.useSearchParams();
|
|
12
|
+
const { toggleNotification } = admin.useNotification();
|
|
13
|
+
const [items, setItems] = react.useState([]);
|
|
14
|
+
const status = params.get("status") || "draft";
|
|
15
|
+
const getter = react.useCallback(async () => {
|
|
16
|
+
const { get } = admin.getFetchClient();
|
|
17
|
+
let response;
|
|
18
|
+
const endpoint = `/i-relate-to-this/list/${slug}/${id}/${status}`;
|
|
19
|
+
try {
|
|
20
|
+
response = await get(endpoint, { id });
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return toggleNotification({
|
|
23
|
+
type: "warning",
|
|
24
|
+
message: formatMessage({
|
|
25
|
+
id: "Failed to load list",
|
|
26
|
+
defaultMessage: error
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
setItems(response.data.items);
|
|
31
|
+
return null;
|
|
32
|
+
}, [formatMessage, id, toggleNotification, slug, status, setItems]);
|
|
33
|
+
react.useEffect(() => {
|
|
34
|
+
if (id && id !== "create") {
|
|
35
|
+
getter();
|
|
36
|
+
}
|
|
37
|
+
}, [id, getter]);
|
|
38
|
+
return items.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
39
|
+
"Links:",
|
|
40
|
+
items.map(({
|
|
41
|
+
documentId,
|
|
42
|
+
title,
|
|
43
|
+
uid,
|
|
44
|
+
contentTypeDisplayName,
|
|
45
|
+
isPublished
|
|
46
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
47
|
+
designSystem.Link,
|
|
48
|
+
{
|
|
49
|
+
href: `/admin/content-manager/collection-types/${uid}/${documentId}`,
|
|
50
|
+
children: [
|
|
51
|
+
!isPublished && "⚠",
|
|
52
|
+
" ",
|
|
53
|
+
contentTypeDisplayName,
|
|
54
|
+
": ",
|
|
55
|
+
title || documentId
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
) }, documentId))
|
|
59
|
+
] });
|
|
60
|
+
};
|
|
61
|
+
const index = {
|
|
62
|
+
bootstrap(app) {
|
|
63
|
+
app.getPlugin("content-manager").injectComponent("editView", "right-links", {
|
|
64
|
+
name: "it-relates-to-me-list",
|
|
65
|
+
Component: List
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
register() {
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
module.exports = index;
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../admin/src/components/list.jsx","../../admin/src/index.js"],"sourcesContent":["import React, { useEffect, useCallback, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useParams, useSearchParams } from 'react-router-dom';\nimport { Link } from '@strapi/design-system';\nimport {\n getFetchClient,\n useNotification,\n} from '@strapi/strapi/admin';\n\nconst useThisCode = true;\n\nconst List = () => {\n const { formatMessage } = useIntl();\n const { id, slug } = useParams();\n const [params] = useSearchParams();\n const { toggleNotification } = useNotification();\n const [items, setItems] = useState([]);\n const status = params.get('status') || 'draft';\n\n const getter = useCallback(async () => {\n const { get } = getFetchClient();\n let response;\n const endpoint = `/i-relate-to-this/list/${slug}/${id}/${status}`;\n try {\n response = await get(endpoint, { id });\n } catch (error) {\n return toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'Failed to load list',\n defaultMessage: error,\n }),\n });\n }\n setItems(response.data.items);\n return null;\n }, [formatMessage, id, toggleNotification, slug, status, setItems]);\n\n useEffect(() => {\n // single types don't have an id\n // on create there are never relations\n if (useThisCode && id && id !== 'create') {\n getter();\n }\n }, [id, getter]);\n\n if (!useThisCode) {\n return null;\n }\n\n return items.length > 0 && (\n <div>\n Links:\n {items.map(({\n documentId,\n title,\n uid,\n contentTypeDisplayName,\n isPublished,\n }) => (\n <div key={documentId}>\n <Link\n href={`/admin/content-manager/collection-types/${uid}/${documentId}`}\n >\n {!isPublished && '⚠'} {contentTypeDisplayName}: {title || documentId}\n </Link>\n </div>\n ))}\n </div>\n );\n};\n\nexport default List;\n","import List from './components/list';\n\nexport default {\n bootstrap(app) {\n // execute some bootstrap code\n app.getPlugin('content-manager').injectComponent('editView', 'right-links', {\n name: 'it-relates-to-me-list',\n Component: List,\n });\n },\n register() {}\n};\n"],"names":["useIntl","useParams","useSearchParams","useNotification","useState","useCallback","getFetchClient","useEffect","jsxs","Link"],"mappings":";;;;;;;AAWA,MAAM,OAAO,MAAM;AACjB,QAAM,EAAE,cAAA,IAAkBA,kBAAA;AAC1B,QAAM,EAAE,IAAI,KAAA,IAASC,yBAAA;AACrB,QAAM,CAAC,MAAM,IAAIC,+BAAA;AACjB,QAAM,EAAE,mBAAA,IAAuBC,sBAAA;AAC/B,QAAM,CAAC,OAAO,QAAQ,IAAIC,MAAAA,SAAS,CAAA,CAAE;AACrC,QAAM,SAAS,OAAO,IAAI,QAAQ,KAAK;AAEvC,QAAM,SAASC,MAAAA,YAAY,YAAY;AACrC,UAAM,EAAE,IAAA,IAAQC,qBAAA;AAChB,QAAI;AACJ,UAAM,WAAW,0BAA0B,IAAI,IAAI,EAAE,IAAI,MAAM;AAC/D,QAAI;AACF,iBAAW,MAAM,IAAI,UAAU,EAAE,IAAI;AAAA,IACvC,SAAS,OAAO;AACd,aAAO,mBAAmB;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,cAAc;AAAA,UACrB,IAAI;AAAA,UACJ,gBAAgB;AAAA,QAAA,CACjB;AAAA,MAAA,CACF;AAAA,IACH;AACA,aAAS,SAAS,KAAK,KAAK;AAC5B,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,IAAI,oBAAoB,MAAM,QAAQ,QAAQ,CAAC;AAElEC,QAAAA,UAAU,MAAM;AAGd,QAAmB,MAAM,OAAO,UAAU;AACxC,aAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,IAAI,MAAM,CAAC;AAMf,SAAO,MAAM,SAAS,KACpBC,2BAAAA,KAAC,OAAA,EAAI,UAAA;AAAA,IAAA;AAAA,IAEF,MAAM,IAAI,CAAC;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,qCAEC,OAAA,EACC,UAAAA,2BAAAA;AAAAA,MAACC,aAAAA;AAAAA,MAAA;AAAA,QACC,MAAM,2CAA2C,GAAG,IAAI,UAAU;AAAA,QAEjE,UAAA;AAAA,UAAA,CAAC,eAAe;AAAA,UAAI;AAAA,UAAE;AAAA,UAAuB;AAAA,UAAG,SAAS;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,EAC5D,GALQ,UAMV,CACD;AAAA,EAAA,GACH;AAEJ;ACpEA,MAAA,QAAe;AAAA,EACb,UAAU,KAAK;AAEb,QAAI,UAAU,iBAAiB,EAAE,gBAAgB,YAAY,eAAe;AAAA,MAC1E,MAAM;AAAA,MACN,WAAW;AAAA,IACjB,CAAK;AAAA,EACH;AAAA,EACA,WAAW;AAAA,EAAC;AACd;;"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback, useEffect } from "react";
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
4
|
+
import { useParams, useSearchParams } from "react-router-dom";
|
|
5
|
+
import { Link } from "@strapi/design-system";
|
|
6
|
+
import { useNotification, getFetchClient } from "@strapi/strapi/admin";
|
|
7
|
+
const List = () => {
|
|
8
|
+
const { formatMessage } = useIntl();
|
|
9
|
+
const { id, slug } = useParams();
|
|
10
|
+
const [params] = useSearchParams();
|
|
11
|
+
const { toggleNotification } = useNotification();
|
|
12
|
+
const [items, setItems] = useState([]);
|
|
13
|
+
const status = params.get("status") || "draft";
|
|
14
|
+
const getter = useCallback(async () => {
|
|
15
|
+
const { get } = getFetchClient();
|
|
16
|
+
let response;
|
|
17
|
+
const endpoint = `/i-relate-to-this/list/${slug}/${id}/${status}`;
|
|
18
|
+
try {
|
|
19
|
+
response = await get(endpoint, { id });
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return toggleNotification({
|
|
22
|
+
type: "warning",
|
|
23
|
+
message: formatMessage({
|
|
24
|
+
id: "Failed to load list",
|
|
25
|
+
defaultMessage: error
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
setItems(response.data.items);
|
|
30
|
+
return null;
|
|
31
|
+
}, [formatMessage, id, toggleNotification, slug, status, setItems]);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (id && id !== "create") {
|
|
34
|
+
getter();
|
|
35
|
+
}
|
|
36
|
+
}, [id, getter]);
|
|
37
|
+
return items.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
38
|
+
"Links:",
|
|
39
|
+
items.map(({
|
|
40
|
+
documentId,
|
|
41
|
+
title,
|
|
42
|
+
uid,
|
|
43
|
+
contentTypeDisplayName,
|
|
44
|
+
isPublished
|
|
45
|
+
}) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
|
|
46
|
+
Link,
|
|
47
|
+
{
|
|
48
|
+
href: `/admin/content-manager/collection-types/${uid}/${documentId}`,
|
|
49
|
+
children: [
|
|
50
|
+
!isPublished && "⚠",
|
|
51
|
+
" ",
|
|
52
|
+
contentTypeDisplayName,
|
|
53
|
+
": ",
|
|
54
|
+
title || documentId
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
) }, documentId))
|
|
58
|
+
] });
|
|
59
|
+
};
|
|
60
|
+
const index = {
|
|
61
|
+
bootstrap(app) {
|
|
62
|
+
app.getPlugin("content-manager").injectComponent("editView", "right-links", {
|
|
63
|
+
name: "it-relates-to-me-list",
|
|
64
|
+
Component: List
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
register() {
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
index as default
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../admin/src/components/list.jsx","../../admin/src/index.js"],"sourcesContent":["import React, { useEffect, useCallback, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useParams, useSearchParams } from 'react-router-dom';\nimport { Link } from '@strapi/design-system';\nimport {\n getFetchClient,\n useNotification,\n} from '@strapi/strapi/admin';\n\nconst useThisCode = true;\n\nconst List = () => {\n const { formatMessage } = useIntl();\n const { id, slug } = useParams();\n const [params] = useSearchParams();\n const { toggleNotification } = useNotification();\n const [items, setItems] = useState([]);\n const status = params.get('status') || 'draft';\n\n const getter = useCallback(async () => {\n const { get } = getFetchClient();\n let response;\n const endpoint = `/i-relate-to-this/list/${slug}/${id}/${status}`;\n try {\n response = await get(endpoint, { id });\n } catch (error) {\n return toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'Failed to load list',\n defaultMessage: error,\n }),\n });\n }\n setItems(response.data.items);\n return null;\n }, [formatMessage, id, toggleNotification, slug, status, setItems]);\n\n useEffect(() => {\n // single types don't have an id\n // on create there are never relations\n if (useThisCode && id && id !== 'create') {\n getter();\n }\n }, [id, getter]);\n\n if (!useThisCode) {\n return null;\n }\n\n return items.length > 0 && (\n <div>\n Links:\n {items.map(({\n documentId,\n title,\n uid,\n contentTypeDisplayName,\n isPublished,\n }) => (\n <div key={documentId}>\n <Link\n href={`/admin/content-manager/collection-types/${uid}/${documentId}`}\n >\n {!isPublished && '⚠'} {contentTypeDisplayName}: {title || documentId}\n </Link>\n </div>\n ))}\n </div>\n );\n};\n\nexport default List;\n","import List from './components/list';\n\nexport default {\n bootstrap(app) {\n // execute some bootstrap code\n app.getPlugin('content-manager').injectComponent('editView', 'right-links', {\n name: 'it-relates-to-me-list',\n Component: List,\n });\n },\n register() {}\n};\n"],"names":[],"mappings":";;;;;;AAWA,MAAM,OAAO,MAAM;AACjB,QAAM,EAAE,cAAA,IAAkB,QAAA;AAC1B,QAAM,EAAE,IAAI,KAAA,IAAS,UAAA;AACrB,QAAM,CAAC,MAAM,IAAI,gBAAA;AACjB,QAAM,EAAE,mBAAA,IAAuB,gBAAA;AAC/B,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,CAAA,CAAE;AACrC,QAAM,SAAS,OAAO,IAAI,QAAQ,KAAK;AAEvC,QAAM,SAAS,YAAY,YAAY;AACrC,UAAM,EAAE,IAAA,IAAQ,eAAA;AAChB,QAAI;AACJ,UAAM,WAAW,0BAA0B,IAAI,IAAI,EAAE,IAAI,MAAM;AAC/D,QAAI;AACF,iBAAW,MAAM,IAAI,UAAU,EAAE,IAAI;AAAA,IACvC,SAAS,OAAO;AACd,aAAO,mBAAmB;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,cAAc;AAAA,UACrB,IAAI;AAAA,UACJ,gBAAgB;AAAA,QAAA,CACjB;AAAA,MAAA,CACF;AAAA,IACH;AACA,aAAS,SAAS,KAAK,KAAK;AAC5B,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,IAAI,oBAAoB,MAAM,QAAQ,QAAQ,CAAC;AAElE,YAAU,MAAM;AAGd,QAAmB,MAAM,OAAO,UAAU;AACxC,aAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,IAAI,MAAM,CAAC;AAMf,SAAO,MAAM,SAAS,KACpB,qBAAC,OAAA,EAAI,UAAA;AAAA,IAAA;AAAA,IAEF,MAAM,IAAI,CAAC;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,0BAEC,OAAA,EACC,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAM,2CAA2C,GAAG,IAAI,UAAU;AAAA,QAEjE,UAAA;AAAA,UAAA,CAAC,eAAe;AAAA,UAAI;AAAA,UAAE;AAAA,UAAuB;AAAA,UAAG,SAAS;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,EAC5D,GALQ,UAMV,CACD;AAAA,EAAA,GACH;AAEJ;ACpEA,MAAA,QAAe;AAAA,EACb,UAAU,KAAK;AAEb,QAAI,UAAU,iBAAiB,EAAE,gBAAgB,YAAY,eAAe;AAAA,MAC1E,MAAM;AAAA,MACN,WAAW;AAAA,IACjB,CAAK;AAAA,EACH;AAAA,EACA,WAAW;AAAA,EAAC;AACd;"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const snakeCase = require("lodash.snakecase");
|
|
3
|
+
const mergeWith = require("lodash.mergewith");
|
|
4
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
5
|
+
const snakeCase__default = /* @__PURE__ */ _interopDefault(snakeCase);
|
|
6
|
+
const mergeWith__default = /* @__PURE__ */ _interopDefault(mergeWith);
|
|
7
|
+
const bootstrap = ({ strapi: strapi2 }) => {
|
|
8
|
+
};
|
|
9
|
+
const destroy = ({ strapi: strapi2 }) => {
|
|
10
|
+
};
|
|
11
|
+
const register = ({ strapi: strapi2 }) => {
|
|
12
|
+
};
|
|
13
|
+
const config = {
|
|
14
|
+
default: {},
|
|
15
|
+
validator() {
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const contentTypes = {};
|
|
19
|
+
const controller = ({ strapi: strapi2 }) => ({
|
|
20
|
+
async getunirelations(ctx) {
|
|
21
|
+
const { id, contentType, status } = ctx.request.params;
|
|
22
|
+
const response = await strapi2.service("plugin::i-relate-to-this.service").getunirelations(contentType, id, status);
|
|
23
|
+
if (!response) {
|
|
24
|
+
ctx.body = { success: false };
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
ctx.body = {
|
|
28
|
+
success: true,
|
|
29
|
+
items: response
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const controllers = {
|
|
34
|
+
controller
|
|
35
|
+
};
|
|
36
|
+
const middlewares = {};
|
|
37
|
+
const policies = {};
|
|
38
|
+
const adminRoutes = [
|
|
39
|
+
{
|
|
40
|
+
method: "GET",
|
|
41
|
+
path: "/list/:contentType/:id/:status",
|
|
42
|
+
handler: "controller.getunirelations"
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
const routes = {
|
|
46
|
+
admin: {
|
|
47
|
+
type: "admin",
|
|
48
|
+
routes: adminRoutes
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function customizer(objValue, srcValue) {
|
|
52
|
+
if (Array.isArray(objValue)) {
|
|
53
|
+
return objValue.includes(srcValue[0]) ? objValue : objValue.concat(srcValue[0]);
|
|
54
|
+
}
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
const search = async (id, status, parent) => {
|
|
58
|
+
const modelsWithRelationsToMe = Object.values({ ...strapi.contentTypes, ...strapi.components }).reduce((total, model) => {
|
|
59
|
+
const {
|
|
60
|
+
attributes
|
|
61
|
+
} = model;
|
|
62
|
+
const relations = Object.entries(attributes).reduce((acc, [key, {
|
|
63
|
+
type,
|
|
64
|
+
target,
|
|
65
|
+
inversedBy,
|
|
66
|
+
mappedBy,
|
|
67
|
+
component,
|
|
68
|
+
components
|
|
69
|
+
}]) => {
|
|
70
|
+
if (key === "localizations") {
|
|
71
|
+
return acc;
|
|
72
|
+
}
|
|
73
|
+
if (
|
|
74
|
+
// only uni relations
|
|
75
|
+
!(type === "relation" && target === parent.uid && !inversedBy && !mappedBy) && !(type === "component" && component === parent.uid) && !(type === "dynamiczone" && components?.includes(parent.uid))
|
|
76
|
+
) {
|
|
77
|
+
return acc;
|
|
78
|
+
}
|
|
79
|
+
return acc.concat({
|
|
80
|
+
key,
|
|
81
|
+
type,
|
|
82
|
+
...model
|
|
83
|
+
});
|
|
84
|
+
}, []);
|
|
85
|
+
return total.concat(relations);
|
|
86
|
+
}, []);
|
|
87
|
+
const lookups = modelsWithRelationsToMe.reduce(async (acc, {
|
|
88
|
+
key,
|
|
89
|
+
type,
|
|
90
|
+
...model
|
|
91
|
+
}) => {
|
|
92
|
+
const {
|
|
93
|
+
collectionName,
|
|
94
|
+
modelName
|
|
95
|
+
} = model;
|
|
96
|
+
const relationIdColumn = type === "relation" ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(
|
|
97
|
+
snakeCase__default.default(modelName)
|
|
98
|
+
) : "entity_id";
|
|
99
|
+
const parentIdColumn = type === "relation" ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(
|
|
100
|
+
snakeCase__default.default(parent.modelName)
|
|
101
|
+
) : "cmp_id";
|
|
102
|
+
const tableName = type === "relation" ? `${snakeCase__default.default(`${collectionName} ${key} lnk`)}` : `${collectionName}_cmps`;
|
|
103
|
+
const relationsInTable = await strapi.db.getConnection(tableName).where({
|
|
104
|
+
[parentIdColumn]: id,
|
|
105
|
+
...type === "relation" ? {} : {
|
|
106
|
+
component_type: parent.uid
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
if (relationsInTable.length === 0) {
|
|
110
|
+
return acc;
|
|
111
|
+
}
|
|
112
|
+
const itemsForThisCollection = relationsInTable.reduce(async (deepacc, item) => {
|
|
113
|
+
const prev = await deepacc;
|
|
114
|
+
if (model.uid.startsWith("api::") || model.uid.startsWith("plugin::")) {
|
|
115
|
+
return mergeWith__default.default(prev, {
|
|
116
|
+
[model.uid]: {
|
|
117
|
+
info: model.info,
|
|
118
|
+
items: [item[relationIdColumn]]
|
|
119
|
+
}
|
|
120
|
+
}, customizer);
|
|
121
|
+
}
|
|
122
|
+
const next = await search(item[relationIdColumn], status, model);
|
|
123
|
+
return mergeWith__default.default(prev, next, customizer);
|
|
124
|
+
}, {});
|
|
125
|
+
return mergeWith__default.default(await acc, await itemsForThisCollection, customizer);
|
|
126
|
+
}, {});
|
|
127
|
+
return lookups;
|
|
128
|
+
};
|
|
129
|
+
const service = ({ strapi: strapi2 }) => ({
|
|
130
|
+
async getunirelations(contentType, documentId, status = "draft") {
|
|
131
|
+
console.log("running service");
|
|
132
|
+
const ct = strapi2.contentType(contentType);
|
|
133
|
+
const entity = await strapi2.documents(contentType).findOne({
|
|
134
|
+
documentId,
|
|
135
|
+
fields: ["id"],
|
|
136
|
+
status
|
|
137
|
+
});
|
|
138
|
+
const relatedEntries = await search(entity.id, status, ct);
|
|
139
|
+
let publishedDocumentIds = [];
|
|
140
|
+
if (status === "draft") {
|
|
141
|
+
const entityPub = await strapi2.documents(contentType).findOne({
|
|
142
|
+
documentId,
|
|
143
|
+
fields: ["id"],
|
|
144
|
+
status: "published"
|
|
145
|
+
});
|
|
146
|
+
if (entityPub) {
|
|
147
|
+
const relatedEntriesPub = await search(entityPub.id, status, ct);
|
|
148
|
+
publishedDocumentIds = (await Object.entries(relatedEntriesPub).reduce(async (acc, [
|
|
149
|
+
uid,
|
|
150
|
+
{ items }
|
|
151
|
+
]) => {
|
|
152
|
+
const prev = await acc;
|
|
153
|
+
const entries = await strapi2.documents(uid).findMany({
|
|
154
|
+
filters: { id: { $in: items } },
|
|
155
|
+
status: "published",
|
|
156
|
+
fields: ["documentId"]
|
|
157
|
+
});
|
|
158
|
+
return prev.concat(entries);
|
|
159
|
+
}, [])).map(({ documentId: dId }) => dId);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const result = await Object.entries(relatedEntries).reduce(async (acc, [
|
|
163
|
+
uid,
|
|
164
|
+
{ items, info }
|
|
165
|
+
]) => {
|
|
166
|
+
const prev = await acc;
|
|
167
|
+
const entries = (await strapi2.documents(uid).findMany({
|
|
168
|
+
filters: { id: { $in: items } },
|
|
169
|
+
status
|
|
170
|
+
})).map((entry) => ({
|
|
171
|
+
uid,
|
|
172
|
+
contentTypeDisplayName: info.displayName,
|
|
173
|
+
title: entry.title || entry.name,
|
|
174
|
+
documentId: entry.documentId,
|
|
175
|
+
isPublished: status === "published" || publishedDocumentIds.includes(entry.documentId)
|
|
176
|
+
}));
|
|
177
|
+
return prev.concat(entries);
|
|
178
|
+
}, []);
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const services = {
|
|
183
|
+
service
|
|
184
|
+
};
|
|
185
|
+
const index = {
|
|
186
|
+
bootstrap,
|
|
187
|
+
destroy,
|
|
188
|
+
register,
|
|
189
|
+
config,
|
|
190
|
+
controllers,
|
|
191
|
+
contentTypes,
|
|
192
|
+
middlewares,
|
|
193
|
+
policies,
|
|
194
|
+
routes,
|
|
195
|
+
services
|
|
196
|
+
};
|
|
197
|
+
module.exports = index;
|
|
198
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../server/src/bootstrap.js","../../server/src/destroy.js","../../server/src/register.js","../../server/src/config/index.js","../../server/src/content-types/index.js","../../server/src/controllers/controller.js","../../server/src/controllers/index.js","../../server/src/middlewares/index.js","../../server/src/policies/index.js","../../server/src/routes/admin.js","../../server/src/routes/index.js","../../server/src/services/service.js","../../server/src/services/index.js","../../server/src/index.js"],"sourcesContent":["const bootstrap = ({ strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","const destroy = ({ strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","const register = ({ strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","export default {};\n","const controller = ({ strapi }) => ({\n async getunirelations(ctx) {\n const { id, contentType, status } = ctx.request.params;\n const response = await strapi.service('plugin::i-relate-to-this.service').getunirelations(contentType, id, status);\n if (!response) {\n ctx.body = { success: false };\n return;\n }\n ctx.body = {\n success: true,\n items: response,\n };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/list/:contentType/:id/:status',\n handler: 'controller.getunirelations',\n }\n];\n","import adminRoutes from './admin';\n\nconst routes = {\n admin: {\n type: 'admin',\n routes: adminRoutes,\n },\n};\n\nexport default routes;\n","\nimport snakeCase from 'lodash.snakecase';\nimport mergeWith from 'lodash.mergewith';\n\nfunction customizer(objValue, srcValue) {\n if (Array.isArray(objValue)) {\n // we hard assume only one item is added to the array\n return objValue.includes(srcValue[0]) ? objValue : objValue.concat(srcValue[0]);\n }\n return undefined;\n}\n\nconst search = async (id, status, parent) => {\n const modelsWithRelationsToMe = Object\n .values({ ...strapi.contentTypes, ...strapi.components })\n .reduce((total, model) => {\n const {\n attributes,\n } = model;\n const relations = Object.entries(attributes).reduce((acc, [key, {\n type,\n target,\n inversedBy,\n mappedBy,\n component,\n components,\n }]) => {\n // localizations is always a relation to self\n if (key === 'localizations') {\n return acc;\n }\n if (\n // only uni relations\n !(type === 'relation' && target === parent.uid && !inversedBy && !mappedBy)\n && !(type === 'component' && component === parent.uid)\n && !(type === 'dynamiczone' && components?.includes(parent.uid))\n ) {\n return acc;\n }\n return acc.concat({\n key,\n type,\n ...model,\n });\n }, []);\n return total.concat(relations);\n }, []);\n\n const lookups = modelsWithRelationsToMe.reduce(async (acc, {\n key,\n type,\n ...model\n }) => {\n const {\n collectionName,\n modelName,\n } = model;\n const relationIdColumn = type === 'relation' ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(\n snakeCase(modelName),\n ) : 'entity_id';\n const parentIdColumn = type === 'relation' ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(\n snakeCase(parent.modelName),\n ) : 'cmp_id';\n const tableName = type === 'relation'\n ? `${snakeCase(`${collectionName} ${key} lnk`)}`\n : `${collectionName}_cmps`; // not snaked cased!\n\n // find this item in the db\n // console.log(`getting ${relationIdColumn} for ${parentIdColumn} ${id} from ${tableName}`);\n const relationsInTable = await strapi.db.getConnection(tableName).where({\n [parentIdColumn]: id,\n ...(type === 'relation' ? {} : {\n component_type: parent.uid,\n }),\n });\n\n // not related in this db, skip\n if (relationsInTable.length === 0) {\n return acc;\n }\n\n const itemsForThisCollection = relationsInTable.reduce(async (deepacc, item) => {\n const prev = await deepacc;\n // we've reached our endpoint if:\n if (model.uid.startsWith('api::') || model.uid.startsWith('plugin::')) {\n // make sure we dont have duplicates\n return mergeWith(prev, {\n [model.uid]: {\n info: model.info,\n items: [item[relationIdColumn]],\n },\n }, customizer);\n }\n // still a component, keep searching deeper\n const next = await search(item[relationIdColumn], status, model);\n return mergeWith(prev, next, customizer);\n }, {});\n\n // acc is the list of models, add the current found model ids\n return mergeWith(await acc, await itemsForThisCollection, customizer);\n }, {});\n\n return lookups;\n};\n\nconst service = ({ strapi }) => ({\n async getunirelations(contentType, documentId, status = 'draft') {\n console.log('running service');\n const ct = strapi.contentType(contentType);\n\n // find the db id by documentId\n const entity = await strapi.documents(contentType).findOne({\n documentId,\n fields: ['id'],\n status,\n });\n // go fetch all related items to me\n const relatedEntries = await search(entity.id, status, ct);\n\n let publishedDocumentIds = [];\n if (status === 'draft') {\n // find the db id by documentId\n const entityPub = await strapi.documents(contentType).findOne({\n documentId,\n fields: ['id'],\n status: 'published',\n });\n\n // current document could be draft and have no published version\n if (entityPub) {\n // go fetch all related items to me in published\n const relatedEntriesPub = await search(entityPub.id, status, ct);\n publishedDocumentIds = (await Object.entries(relatedEntriesPub).reduce(async (acc, [\n uid,\n { items },\n ]) => {\n const prev = await acc;\n const entries = (await strapi.documents(uid).findMany({\n filters: { id: { $in: items } },\n status: 'published',\n fields: ['documentId'],\n }));\n // add all entries for all models together\n return prev.concat(entries);\n }, [])).map(({ documentId: dId }) => dId);\n }\n }\n\n // convert results into a list of elements for the UI\n const result = await Object.entries(relatedEntries).reduce(async (acc, [\n uid,\n { items, info },\n ]) => {\n const prev = await acc;\n // // find all entries for this model\n const entries = (await strapi.documents(uid).findMany({\n filters: { id: { $in: items } },\n status,\n }))\n // create an output for the UI\n .map((entry) => ({\n uid,\n contentTypeDisplayName: info.displayName,\n title: entry.title || entry.name,\n documentId: entry.documentId,\n isPublished: status === 'published' || publishedDocumentIds.includes(entry.documentId),\n }));\n // add all entries for all models together\n return prev.concat(entries);\n }, []);\n\n return result;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n bootstrap,\n destroy,\n register,\n\n config,\n controllers,\n contentTypes,\n middlewares,\n policies,\n routes,\n services,\n};\n"],"names":["strapi","snakeCase","mergeWith"],"mappings":"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"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import snakeCase from "lodash.snakecase";
|
|
2
|
+
import mergeWith from "lodash.mergewith";
|
|
3
|
+
const bootstrap = ({ strapi: strapi2 }) => {
|
|
4
|
+
};
|
|
5
|
+
const destroy = ({ strapi: strapi2 }) => {
|
|
6
|
+
};
|
|
7
|
+
const register = ({ strapi: strapi2 }) => {
|
|
8
|
+
};
|
|
9
|
+
const config = {
|
|
10
|
+
default: {},
|
|
11
|
+
validator() {
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const contentTypes = {};
|
|
15
|
+
const controller = ({ strapi: strapi2 }) => ({
|
|
16
|
+
async getunirelations(ctx) {
|
|
17
|
+
const { id, contentType, status } = ctx.request.params;
|
|
18
|
+
const response = await strapi2.service("plugin::i-relate-to-this.service").getunirelations(contentType, id, status);
|
|
19
|
+
if (!response) {
|
|
20
|
+
ctx.body = { success: false };
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
ctx.body = {
|
|
24
|
+
success: true,
|
|
25
|
+
items: response
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
const controllers = {
|
|
30
|
+
controller
|
|
31
|
+
};
|
|
32
|
+
const middlewares = {};
|
|
33
|
+
const policies = {};
|
|
34
|
+
const adminRoutes = [
|
|
35
|
+
{
|
|
36
|
+
method: "GET",
|
|
37
|
+
path: "/list/:contentType/:id/:status",
|
|
38
|
+
handler: "controller.getunirelations"
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
const routes = {
|
|
42
|
+
admin: {
|
|
43
|
+
type: "admin",
|
|
44
|
+
routes: adminRoutes
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
function customizer(objValue, srcValue) {
|
|
48
|
+
if (Array.isArray(objValue)) {
|
|
49
|
+
return objValue.includes(srcValue[0]) ? objValue : objValue.concat(srcValue[0]);
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
const search = async (id, status, parent) => {
|
|
54
|
+
const modelsWithRelationsToMe = Object.values({ ...strapi.contentTypes, ...strapi.components }).reduce((total, model) => {
|
|
55
|
+
const {
|
|
56
|
+
attributes
|
|
57
|
+
} = model;
|
|
58
|
+
const relations = Object.entries(attributes).reduce((acc, [key, {
|
|
59
|
+
type,
|
|
60
|
+
target,
|
|
61
|
+
inversedBy,
|
|
62
|
+
mappedBy,
|
|
63
|
+
component,
|
|
64
|
+
components
|
|
65
|
+
}]) => {
|
|
66
|
+
if (key === "localizations") {
|
|
67
|
+
return acc;
|
|
68
|
+
}
|
|
69
|
+
if (
|
|
70
|
+
// only uni relations
|
|
71
|
+
!(type === "relation" && target === parent.uid && !inversedBy && !mappedBy) && !(type === "component" && component === parent.uid) && !(type === "dynamiczone" && components?.includes(parent.uid))
|
|
72
|
+
) {
|
|
73
|
+
return acc;
|
|
74
|
+
}
|
|
75
|
+
return acc.concat({
|
|
76
|
+
key,
|
|
77
|
+
type,
|
|
78
|
+
...model
|
|
79
|
+
});
|
|
80
|
+
}, []);
|
|
81
|
+
return total.concat(relations);
|
|
82
|
+
}, []);
|
|
83
|
+
const lookups = modelsWithRelationsToMe.reduce(async (acc, {
|
|
84
|
+
key,
|
|
85
|
+
type,
|
|
86
|
+
...model
|
|
87
|
+
}) => {
|
|
88
|
+
const {
|
|
89
|
+
collectionName,
|
|
90
|
+
modelName
|
|
91
|
+
} = model;
|
|
92
|
+
const relationIdColumn = type === "relation" ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(
|
|
93
|
+
snakeCase(modelName)
|
|
94
|
+
) : "entity_id";
|
|
95
|
+
const parentIdColumn = type === "relation" ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(
|
|
96
|
+
snakeCase(parent.modelName)
|
|
97
|
+
) : "cmp_id";
|
|
98
|
+
const tableName = type === "relation" ? `${snakeCase(`${collectionName} ${key} lnk`)}` : `${collectionName}_cmps`;
|
|
99
|
+
const relationsInTable = await strapi.db.getConnection(tableName).where({
|
|
100
|
+
[parentIdColumn]: id,
|
|
101
|
+
...type === "relation" ? {} : {
|
|
102
|
+
component_type: parent.uid
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
if (relationsInTable.length === 0) {
|
|
106
|
+
return acc;
|
|
107
|
+
}
|
|
108
|
+
const itemsForThisCollection = relationsInTable.reduce(async (deepacc, item) => {
|
|
109
|
+
const prev = await deepacc;
|
|
110
|
+
if (model.uid.startsWith("api::") || model.uid.startsWith("plugin::")) {
|
|
111
|
+
return mergeWith(prev, {
|
|
112
|
+
[model.uid]: {
|
|
113
|
+
info: model.info,
|
|
114
|
+
items: [item[relationIdColumn]]
|
|
115
|
+
}
|
|
116
|
+
}, customizer);
|
|
117
|
+
}
|
|
118
|
+
const next = await search(item[relationIdColumn], status, model);
|
|
119
|
+
return mergeWith(prev, next, customizer);
|
|
120
|
+
}, {});
|
|
121
|
+
return mergeWith(await acc, await itemsForThisCollection, customizer);
|
|
122
|
+
}, {});
|
|
123
|
+
return lookups;
|
|
124
|
+
};
|
|
125
|
+
const service = ({ strapi: strapi2 }) => ({
|
|
126
|
+
async getunirelations(contentType, documentId, status = "draft") {
|
|
127
|
+
console.log("running service");
|
|
128
|
+
const ct = strapi2.contentType(contentType);
|
|
129
|
+
const entity = await strapi2.documents(contentType).findOne({
|
|
130
|
+
documentId,
|
|
131
|
+
fields: ["id"],
|
|
132
|
+
status
|
|
133
|
+
});
|
|
134
|
+
const relatedEntries = await search(entity.id, status, ct);
|
|
135
|
+
let publishedDocumentIds = [];
|
|
136
|
+
if (status === "draft") {
|
|
137
|
+
const entityPub = await strapi2.documents(contentType).findOne({
|
|
138
|
+
documentId,
|
|
139
|
+
fields: ["id"],
|
|
140
|
+
status: "published"
|
|
141
|
+
});
|
|
142
|
+
if (entityPub) {
|
|
143
|
+
const relatedEntriesPub = await search(entityPub.id, status, ct);
|
|
144
|
+
publishedDocumentIds = (await Object.entries(relatedEntriesPub).reduce(async (acc, [
|
|
145
|
+
uid,
|
|
146
|
+
{ items }
|
|
147
|
+
]) => {
|
|
148
|
+
const prev = await acc;
|
|
149
|
+
const entries = await strapi2.documents(uid).findMany({
|
|
150
|
+
filters: { id: { $in: items } },
|
|
151
|
+
status: "published",
|
|
152
|
+
fields: ["documentId"]
|
|
153
|
+
});
|
|
154
|
+
return prev.concat(entries);
|
|
155
|
+
}, [])).map(({ documentId: dId }) => dId);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const result = await Object.entries(relatedEntries).reduce(async (acc, [
|
|
159
|
+
uid,
|
|
160
|
+
{ items, info }
|
|
161
|
+
]) => {
|
|
162
|
+
const prev = await acc;
|
|
163
|
+
const entries = (await strapi2.documents(uid).findMany({
|
|
164
|
+
filters: { id: { $in: items } },
|
|
165
|
+
status
|
|
166
|
+
})).map((entry) => ({
|
|
167
|
+
uid,
|
|
168
|
+
contentTypeDisplayName: info.displayName,
|
|
169
|
+
title: entry.title || entry.name,
|
|
170
|
+
documentId: entry.documentId,
|
|
171
|
+
isPublished: status === "published" || publishedDocumentIds.includes(entry.documentId)
|
|
172
|
+
}));
|
|
173
|
+
return prev.concat(entries);
|
|
174
|
+
}, []);
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
const services = {
|
|
179
|
+
service
|
|
180
|
+
};
|
|
181
|
+
const index = {
|
|
182
|
+
bootstrap,
|
|
183
|
+
destroy,
|
|
184
|
+
register,
|
|
185
|
+
config,
|
|
186
|
+
controllers,
|
|
187
|
+
contentTypes,
|
|
188
|
+
middlewares,
|
|
189
|
+
policies,
|
|
190
|
+
routes,
|
|
191
|
+
services
|
|
192
|
+
};
|
|
193
|
+
export {
|
|
194
|
+
index as default
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../server/src/bootstrap.js","../../server/src/destroy.js","../../server/src/register.js","../../server/src/config/index.js","../../server/src/content-types/index.js","../../server/src/controllers/controller.js","../../server/src/controllers/index.js","../../server/src/middlewares/index.js","../../server/src/policies/index.js","../../server/src/routes/admin.js","../../server/src/routes/index.js","../../server/src/services/service.js","../../server/src/services/index.js","../../server/src/index.js"],"sourcesContent":["const bootstrap = ({ strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","const destroy = ({ strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","const register = ({ strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","export default {};\n","const controller = ({ strapi }) => ({\n async getunirelations(ctx) {\n const { id, contentType, status } = ctx.request.params;\n const response = await strapi.service('plugin::i-relate-to-this.service').getunirelations(contentType, id, status);\n if (!response) {\n ctx.body = { success: false };\n return;\n }\n ctx.body = {\n success: true,\n items: response,\n };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/list/:contentType/:id/:status',\n handler: 'controller.getunirelations',\n }\n];\n","import adminRoutes from './admin';\n\nconst routes = {\n admin: {\n type: 'admin',\n routes: adminRoutes,\n },\n};\n\nexport default routes;\n","\nimport snakeCase from 'lodash.snakecase';\nimport mergeWith from 'lodash.mergewith';\n\nfunction customizer(objValue, srcValue) {\n if (Array.isArray(objValue)) {\n // we hard assume only one item is added to the array\n return objValue.includes(srcValue[0]) ? objValue : objValue.concat(srcValue[0]);\n }\n return undefined;\n}\n\nconst search = async (id, status, parent) => {\n const modelsWithRelationsToMe = Object\n .values({ ...strapi.contentTypes, ...strapi.components })\n .reduce((total, model) => {\n const {\n attributes,\n } = model;\n const relations = Object.entries(attributes).reduce((acc, [key, {\n type,\n target,\n inversedBy,\n mappedBy,\n component,\n components,\n }]) => {\n // localizations is always a relation to self\n if (key === 'localizations') {\n return acc;\n }\n if (\n // only uni relations\n !(type === 'relation' && target === parent.uid && !inversedBy && !mappedBy)\n && !(type === 'component' && component === parent.uid)\n && !(type === 'dynamiczone' && components?.includes(parent.uid))\n ) {\n return acc;\n }\n return acc.concat({\n key,\n type,\n ...model,\n });\n }, []);\n return total.concat(relations);\n }, []);\n\n const lookups = modelsWithRelationsToMe.reduce(async (acc, {\n key,\n type,\n ...model\n }) => {\n const {\n collectionName,\n modelName,\n } = model;\n const relationIdColumn = type === 'relation' ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(\n snakeCase(modelName),\n ) : 'entity_id';\n const parentIdColumn = type === 'relation' ? strapi.db.metadata.identifiers.getJoinColumnAttributeIdName(\n snakeCase(parent.modelName),\n ) : 'cmp_id';\n const tableName = type === 'relation'\n ? `${snakeCase(`${collectionName} ${key} lnk`)}`\n : `${collectionName}_cmps`; // not snaked cased!\n\n // find this item in the db\n // console.log(`getting ${relationIdColumn} for ${parentIdColumn} ${id} from ${tableName}`);\n const relationsInTable = await strapi.db.getConnection(tableName).where({\n [parentIdColumn]: id,\n ...(type === 'relation' ? {} : {\n component_type: parent.uid,\n }),\n });\n\n // not related in this db, skip\n if (relationsInTable.length === 0) {\n return acc;\n }\n\n const itemsForThisCollection = relationsInTable.reduce(async (deepacc, item) => {\n const prev = await deepacc;\n // we've reached our endpoint if:\n if (model.uid.startsWith('api::') || model.uid.startsWith('plugin::')) {\n // make sure we dont have duplicates\n return mergeWith(prev, {\n [model.uid]: {\n info: model.info,\n items: [item[relationIdColumn]],\n },\n }, customizer);\n }\n // still a component, keep searching deeper\n const next = await search(item[relationIdColumn], status, model);\n return mergeWith(prev, next, customizer);\n }, {});\n\n // acc is the list of models, add the current found model ids\n return mergeWith(await acc, await itemsForThisCollection, customizer);\n }, {});\n\n return lookups;\n};\n\nconst service = ({ strapi }) => ({\n async getunirelations(contentType, documentId, status = 'draft') {\n console.log('running service');\n const ct = strapi.contentType(contentType);\n\n // find the db id by documentId\n const entity = await strapi.documents(contentType).findOne({\n documentId,\n fields: ['id'],\n status,\n });\n // go fetch all related items to me\n const relatedEntries = await search(entity.id, status, ct);\n\n let publishedDocumentIds = [];\n if (status === 'draft') {\n // find the db id by documentId\n const entityPub = await strapi.documents(contentType).findOne({\n documentId,\n fields: ['id'],\n status: 'published',\n });\n\n // current document could be draft and have no published version\n if (entityPub) {\n // go fetch all related items to me in published\n const relatedEntriesPub = await search(entityPub.id, status, ct);\n publishedDocumentIds = (await Object.entries(relatedEntriesPub).reduce(async (acc, [\n uid,\n { items },\n ]) => {\n const prev = await acc;\n const entries = (await strapi.documents(uid).findMany({\n filters: { id: { $in: items } },\n status: 'published',\n fields: ['documentId'],\n }));\n // add all entries for all models together\n return prev.concat(entries);\n }, [])).map(({ documentId: dId }) => dId);\n }\n }\n\n // convert results into a list of elements for the UI\n const result = await Object.entries(relatedEntries).reduce(async (acc, [\n uid,\n { items, info },\n ]) => {\n const prev = await acc;\n // // find all entries for this model\n const entries = (await strapi.documents(uid).findMany({\n filters: { id: { $in: items } },\n status,\n }))\n // create an output for the UI\n .map((entry) => ({\n uid,\n contentTypeDisplayName: info.displayName,\n title: entry.title || entry.name,\n documentId: entry.documentId,\n isPublished: status === 'published' || publishedDocumentIds.includes(entry.documentId),\n }));\n // add all entries for all models together\n return prev.concat(entries);\n }, []);\n\n return result;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n bootstrap,\n destroy,\n register,\n\n config,\n controllers,\n contentTypes,\n middlewares,\n policies,\n routes,\n services,\n};\n"],"names":["strapi"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.0.0",
|
|
3
|
+
"keywords": [],
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"exports": {
|
|
6
|
+
"./package.json": "./package.json",
|
|
7
|
+
"./strapi-admin": {
|
|
8
|
+
"source": "./admin/src/index.js",
|
|
9
|
+
"import": "./dist/admin/index.mjs",
|
|
10
|
+
"require": "./dist/admin/index.js",
|
|
11
|
+
"default": "./dist/admin/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./strapi-server": {
|
|
14
|
+
"source": "./server/src/index.js",
|
|
15
|
+
"import": "./dist/server/index.mjs",
|
|
16
|
+
"require": "./dist/server/index.js",
|
|
17
|
+
"default": "./dist/server/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "strapi-plugin build",
|
|
25
|
+
"watch": "strapi-plugin watch",
|
|
26
|
+
"watch:link": "strapi-plugin watch:link",
|
|
27
|
+
"verify": "strapi-plugin verify"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@strapi/design-system": "^2.0.0-rc.29",
|
|
31
|
+
"@strapi/icons": "^2.0.0-rc.29",
|
|
32
|
+
"react-intl": "^7.1.11",
|
|
33
|
+
"lodash.mergewith": "^4.6.2",
|
|
34
|
+
"lodash.snakecase": "^4.1.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@strapi/strapi": "^5.23.4",
|
|
38
|
+
"@strapi/sdk-plugin": "^5.3.2",
|
|
39
|
+
"prettier": "^3.6.2",
|
|
40
|
+
"react": "^18.3.1",
|
|
41
|
+
"react-dom": "^18.3.1",
|
|
42
|
+
"react-router-dom": "^6.30.1",
|
|
43
|
+
"styled-components": "^6.1.19"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@strapi/strapi": "^5.23.4",
|
|
47
|
+
"@strapi/sdk-plugin": "^5.3.2",
|
|
48
|
+
"react": "^18.3.1",
|
|
49
|
+
"react-dom": "^18.3.1",
|
|
50
|
+
"react-router-dom": "^6.30.1",
|
|
51
|
+
"styled-components": "^6.1.19"
|
|
52
|
+
},
|
|
53
|
+
"strapi": {
|
|
54
|
+
"kind": "plugin",
|
|
55
|
+
"name": "i-relate-to-this",
|
|
56
|
+
"displayName": "I relate to this",
|
|
57
|
+
"description": "List unidirectional relations (in components) to the current entity"
|
|
58
|
+
},
|
|
59
|
+
"name": "strapi-plugin-i-relate-to-this",
|
|
60
|
+
"description": "List unidirectional relations (in components) to the current entity",
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"author": "Laurens Kling <laurens@goedideemedia.nl>"
|
|
63
|
+
}
|