multi-content-type-relation 0.1.0 → 2.0.1
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/dist/_chunks/en-Bk9okOMP.js +32 -0
- package/dist/_chunks/en-Cj4T04Z2.mjs +32 -0
- package/dist/_chunks/fr-KHPiQOFP.mjs +32 -0
- package/dist/_chunks/fr-ZS3aTnjj.js +32 -0
- package/dist/_chunks/index-5liGVtQX.js +3566 -0
- package/dist/_chunks/index-CQ_pNHWj.js +335 -0
- package/dist/_chunks/index-Cyd6H1uV.mjs +336 -0
- package/dist/_chunks/index-D3M5NaOA.mjs +3564 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/admin/src/components/Input/InputContentSuggestions.d.ts +13 -0
- package/dist/admin/src/components/Input/MainInput.d.ts +16 -0
- package/dist/admin/src/components/Input/PublicationState.d.ts +6 -0
- package/dist/admin/src/components/Input/TableItem.d.ts +12 -0
- package/dist/admin/src/components/Input/index.d.ts +2 -0
- package/dist/admin/src/components/PluginIcon/index.d.ts +2 -0
- package/dist/admin/src/components/SidePanel/SidePanel.d.ts +7 -0
- package/dist/admin/src/helpers/content.d.ts +5 -0
- package/dist/admin/src/helpers/storage.d.ts +15 -0
- package/dist/admin/src/hooks/useSearchedEntries.d.ts +6 -0
- package/dist/admin/src/hooks/useTranslate.d.ts +4 -0
- package/dist/admin/src/index.d.ts +9 -0
- package/dist/admin/src/interface.d.ts +33 -0
- package/dist/admin/src/pluginId.d.ts +2 -0
- package/dist/server/index.js +506 -25
- package/dist/server/index.mjs +509 -0
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/config/index.d.ts +13 -0
- package/dist/server/src/content-types/index.d.ts +35 -0
- package/dist/server/src/content-types/mctr-relation/index.d.ts +33 -0
- package/dist/server/src/content-types/mctr-relation/schema.d.ts +31 -0
- package/dist/server/src/controllers/controller.d.ts +27 -0
- package/dist/server/src/controllers/index.d.ts +28 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/helpers/index.d.ts +2 -0
- package/dist/server/src/index.d.ts +113 -0
- package/dist/server/src/interface.d.ts +42 -0
- package/dist/server/src/middlewares/index.d.ts +4 -0
- package/dist/server/src/middlewares/middleware.d.ts +2 -0
- package/dist/server/src/policies/index.d.ts +2 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/routes/index.d.ts +18 -0
- package/dist/server/src/services/index.d.ts +8 -0
- package/dist/server/src/services/service.d.ts +7 -0
- package/dist/server/src/utils.d.ts +3 -0
- package/package.json +55 -27
- package/TODO.md +0 -4
- package/admin/src/components/Input/InputContentSuggestions.tsx +0 -162
- package/admin/src/components/Input/MainInput.tsx +0 -135
- package/admin/src/components/Input/PublicationState.tsx +0 -28
- package/admin/src/components/Input/TableItem.tsx +0 -109
- package/admin/src/components/Input/index.tsx +0 -27
- package/admin/src/components/PluginIcon/index.tsx +0 -12
- package/admin/src/helpers/content.ts +0 -60
- package/admin/src/helpers/storage.ts +0 -32
- package/admin/src/hooks/useSearchedEntries.ts +0 -41
- package/admin/src/index.tsx +0 -140
- package/admin/src/interface.ts +0 -37
- package/admin/src/pluginId.ts +0 -5
- package/admin/src/translations/en.json +0 -1
- package/admin/src/translations/fr.json +0 -1
- package/admin/src/utils/getTrad.ts +0 -5
- package/dist/server/bootstrap.js +0 -5
- package/dist/server/config/index.js +0 -27
- package/dist/server/content-types/index.js +0 -3
- package/dist/server/controllers/controller.js +0 -92
- package/dist/server/controllers/index.js +0 -9
- package/dist/server/destroy.js +0 -5
- package/dist/server/interface.js +0 -2
- package/dist/server/middlewares/index.js +0 -9
- package/dist/server/middlewares/middleware.js +0 -163
- package/dist/server/policies/index.js +0 -3
- package/dist/server/register.js +0 -15
- package/dist/server/routes/index.js +0 -29
- package/dist/server/services/index.js +0 -9
- package/dist/server/services/service.js +0 -8
- package/dist/server/utils.js +0 -15
- package/dist/tsconfig.server.tsbuildinfo +0 -1
- package/server/bootstrap.ts +0 -5
- package/server/config/index.ts +0 -28
- package/server/content-types/index.ts +0 -1
- package/server/controllers/controller.ts +0 -107
- package/server/controllers/index.ts +0 -5
- package/server/destroy.ts +0 -5
- package/server/index.ts +0 -23
- package/server/interface.ts +0 -50
- package/server/middlewares/index.ts +0 -5
- package/server/middlewares/middleware.ts +0 -197
- package/server/policies/index.ts +0 -1
- package/server/register.ts +0 -14
- package/server/routes/index.ts +0 -27
- package/server/services/index.ts +0 -5
- package/server/services/service.ts +0 -11
- package/server/utils.ts +0 -14
- package/strapi-admin.js +0 -3
- package/strapi-server.js +0 -3
- package/tsconfig.json +0 -20
- package/tsconfig.server.json +0 -25
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from "react"
|
|
2
|
-
import { Tr, Td, Typography, IconButton } from "@strapi/design-system"
|
|
3
|
-
import { Trash, Plus, Drag, Eye } from "@strapi/icons"
|
|
4
|
-
import { PublicationState } from "./PublicationState"
|
|
5
|
-
import { useSortable } from "@dnd-kit/sortable"
|
|
6
|
-
import { CSS } from "@dnd-kit/utilities"
|
|
7
|
-
|
|
8
|
-
import { SelectedEntry } from "../../interface"
|
|
9
|
-
import { getContentTypeForUid, getContentTypes } from "../../helpers/storage"
|
|
10
|
-
import { useLocation } from "react-router-dom"
|
|
11
|
-
|
|
12
|
-
type Props = {
|
|
13
|
-
entry: SelectedEntry
|
|
14
|
-
type: "suggestion" | "selected"
|
|
15
|
-
uniqueId: number
|
|
16
|
-
onAdd?(entry: SelectedEntry): void
|
|
17
|
-
onDelete?(entry: SelectedEntry): void
|
|
18
|
-
disabled?: boolean
|
|
19
|
-
sortable?: boolean
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const TableItem = ({ entry, type, uniqueId, disabled, onAdd, onDelete, sortable }: Props) => {
|
|
23
|
-
const entryIdentifier = useMemo(() => `${uniqueId}-${entry.uid}-${entry.item.id}`, [entry])
|
|
24
|
-
const contentType = getContentTypeForUid(entry.uid)
|
|
25
|
-
const location = useLocation()
|
|
26
|
-
|
|
27
|
-
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: entryIdentifier })
|
|
28
|
-
|
|
29
|
-
const trueRef = document.querySelector(`[data-tableitem="${entryIdentifier}"]`)
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (!trueRef) return
|
|
32
|
-
|
|
33
|
-
setNodeRef(trueRef as HTMLElement)
|
|
34
|
-
}, [trueRef])
|
|
35
|
-
|
|
36
|
-
const style = {
|
|
37
|
-
transform: CSS.Transform.toString(transform),
|
|
38
|
-
transition
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const [currentLocale, setCurrentLocale] = useState("")
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
const searchParams = new URLSearchParams(location.search)
|
|
44
|
-
const locale = searchParams.get("plugins[i18n][locale]")
|
|
45
|
-
if (!locale) return
|
|
46
|
-
setCurrentLocale(locale)
|
|
47
|
-
}, [location])
|
|
48
|
-
|
|
49
|
-
const goToEntry = () => {
|
|
50
|
-
if (!currentLocale) return
|
|
51
|
-
|
|
52
|
-
const contentTypes = window.sessionStorage.getItem("mctr::content_types")
|
|
53
|
-
|
|
54
|
-
if (contentTypes) {
|
|
55
|
-
try {
|
|
56
|
-
const parsedContentTypes = JSON.parse(contentTypes)
|
|
57
|
-
if (Array.isArray(parsedContentTypes)) {
|
|
58
|
-
const contentType = parsedContentTypes.find((ct) => ct.uid === entry.uid)
|
|
59
|
-
if (contentType) {
|
|
60
|
-
const kind = contentType.kind
|
|
61
|
-
let url = `/admin/content-manager/${kind}/${entry.uid}`
|
|
62
|
-
if (kind === "collectionType") {
|
|
63
|
-
url += `/${entry.item.id}`
|
|
64
|
-
}
|
|
65
|
-
url += `?plugins[i18n][locale]=${currentLocale}`
|
|
66
|
-
|
|
67
|
-
window.open(url, "_blank")
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
} catch (e) {
|
|
72
|
-
console.error("[MRCT] Failed to retrieve content types")
|
|
73
|
-
}
|
|
74
|
-
} else {
|
|
75
|
-
alert("An error occured, please try to refresh the page")
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<Tr style={style} {...attributes} {...listeners} data-tableitem={entryIdentifier}>
|
|
81
|
-
<Td>{type === "selected" ? <IconButton icon={<Drag />} noBorder /> : null}</Td>
|
|
82
|
-
<Td>
|
|
83
|
-
<Typography color="neutral800">{entry.item[entry.searchableField]}</Typography>
|
|
84
|
-
</Td>
|
|
85
|
-
<Td>
|
|
86
|
-
<Typography color="neutral800">{entry.item.id}</Typography>
|
|
87
|
-
</Td>
|
|
88
|
-
<Td>
|
|
89
|
-
<Typography color="neutral800">{entry.displayName}</Typography>
|
|
90
|
-
</Td>
|
|
91
|
-
<Td>
|
|
92
|
-
<PublicationState
|
|
93
|
-
isPublished={!!entry.item.publishedAt}
|
|
94
|
-
hasDraftAndPublish={contentType?.options?.draftAndPublish}
|
|
95
|
-
/>
|
|
96
|
-
</Td>
|
|
97
|
-
<Td>
|
|
98
|
-
<div style={{ display: "flex" }}>
|
|
99
|
-
<IconButton label="Go to entry" onClick={goToEntry} icon={<Eye />} style={{ "margin-right": "5px" }} />
|
|
100
|
-
{type === "suggestion" ? (
|
|
101
|
-
<IconButton label="Add" onClick={() => onAdd!(entry)} icon={<Plus />} disabled={disabled} />
|
|
102
|
-
) : type === "selected" ? (
|
|
103
|
-
<IconButton label="Delete" onClick={() => onDelete!(entry)} icon={<Trash />} />
|
|
104
|
-
) : null}
|
|
105
|
-
</div>
|
|
106
|
-
</Td>
|
|
107
|
-
</Tr>
|
|
108
|
-
)
|
|
109
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from "react"
|
|
2
|
-
|
|
3
|
-
import { MainInput } from "./MainInput"
|
|
4
|
-
|
|
5
|
-
export default function Index(props) {
|
|
6
|
-
const attribute = useMemo(() => {
|
|
7
|
-
if (!props.attribute) return props.attribute
|
|
8
|
-
|
|
9
|
-
if (!props.attribute.options) return props.attribute
|
|
10
|
-
|
|
11
|
-
if (!props.attribute.options.contentTypes) return props.attribute
|
|
12
|
-
|
|
13
|
-
const contentTypes = Object.keys(props.attribute.options.contentTypes).filter(
|
|
14
|
-
(key) => props.attribute.options.contentTypes[key]
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
...props.attribute,
|
|
19
|
-
options: {
|
|
20
|
-
...props.attribute.options,
|
|
21
|
-
contentTypes: contentTypes.join(",")
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}, [props.attribute])
|
|
25
|
-
|
|
26
|
-
return <MainInput {...props} attribute={attribute} />
|
|
27
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { getFetchClient } from "@strapi/helper-plugin"
|
|
2
|
-
|
|
3
|
-
import pluginId from "../pluginId"
|
|
4
|
-
import { FormattedStrapiEntry, MatchingContent, MatchingContentResponse, SelectedEntry } from "../interface"
|
|
5
|
-
|
|
6
|
-
export const fetchMatchingContent = async (
|
|
7
|
-
keyword: string,
|
|
8
|
-
contentTypes: string,
|
|
9
|
-
locale: string
|
|
10
|
-
): Promise<MatchingContentResponse> => {
|
|
11
|
-
const { post } = getFetchClient()
|
|
12
|
-
const response = await post(`/${pluginId}/get-content`, {
|
|
13
|
-
contentTypes: contentTypes.split(","),
|
|
14
|
-
keyword,
|
|
15
|
-
locale
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const data = response.data as MatchingContent[]
|
|
19
|
-
|
|
20
|
-
if (!data) throw new Error("No data returned from API")
|
|
21
|
-
|
|
22
|
-
const total = data.reduce((accumulator, option) => {
|
|
23
|
-
if (!option.results) return accumulator
|
|
24
|
-
|
|
25
|
-
return accumulator + option.results.length
|
|
26
|
-
}, 0)
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
data,
|
|
30
|
-
total
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const formatToStrapiField = (entries: SelectedEntry[]) => {
|
|
35
|
-
if (entries.length === 0) return ""
|
|
36
|
-
|
|
37
|
-
return JSON.stringify(entries.map((entry) => ({ uid: entry.uid, id: entry.item.id, MRCT: true })).filter(Boolean))
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export const validateCurrentRelations = async (entries: FormattedStrapiEntry[]) => {
|
|
41
|
-
const { post } = getFetchClient()
|
|
42
|
-
|
|
43
|
-
const response = await post(`/${pluginId}/validate-relations`, {
|
|
44
|
-
entries
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
return response.data as SelectedEntry[]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export const listContentTypes = async () => {
|
|
51
|
-
try {
|
|
52
|
-
const { get } = getFetchClient()
|
|
53
|
-
const response = await get(`/${pluginId}/list-content-types`)
|
|
54
|
-
|
|
55
|
-
return response.data
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.error(error)
|
|
58
|
-
return []
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export type LightContentType = {
|
|
2
|
-
apiName: string
|
|
3
|
-
attributes: Record<string, Record<string, unknown>>[]
|
|
4
|
-
collectionName: string
|
|
5
|
-
globalId: string
|
|
6
|
-
modelName: string
|
|
7
|
-
modelType: string
|
|
8
|
-
options?: { draftAndPublish?: boolean }
|
|
9
|
-
uid: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const STORAGE_KEY = "mctr::content_types"
|
|
13
|
-
|
|
14
|
-
export function getContentTypes() {
|
|
15
|
-
const raw = sessionStorage.getItem(STORAGE_KEY)
|
|
16
|
-
|
|
17
|
-
return raw ? (JSON.parse(raw) as LightContentType[]) : undefined
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function getContentTypeForUid(uid: string) {
|
|
21
|
-
const contentTypes = getContentTypes()
|
|
22
|
-
|
|
23
|
-
if (!Array.isArray(contentTypes)) return
|
|
24
|
-
|
|
25
|
-
return contentTypes.find((contentType) => contentType.uid === uid)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function setContentTypes(contentTypes: LightContentType[]) {
|
|
29
|
-
const stringified = JSON.stringify(contentTypes)
|
|
30
|
-
|
|
31
|
-
sessionStorage.setItem(STORAGE_KEY, stringified)
|
|
32
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo, useState } from "react"
|
|
2
|
-
|
|
3
|
-
import { MatchingContent } from "../interface"
|
|
4
|
-
import { fetchMatchingContent } from "../helpers/content"
|
|
5
|
-
|
|
6
|
-
export function useSearchedEntries(keyword: string, contentTypes: string, locale: string) {
|
|
7
|
-
const [loading, setLoading] = useState(false)
|
|
8
|
-
const [results, setResults] = useState<MatchingContent[]>([])
|
|
9
|
-
const [total, setTotal] = useState(0)
|
|
10
|
-
|
|
11
|
-
async function fetchEntries() {
|
|
12
|
-
setResults([])
|
|
13
|
-
setTotal(0)
|
|
14
|
-
|
|
15
|
-
if (loading || !keyword) return
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const { data, total } = await fetchMatchingContent(keyword, contentTypes, locale)
|
|
19
|
-
|
|
20
|
-
setResults(data)
|
|
21
|
-
setTotal(total)
|
|
22
|
-
} finally {
|
|
23
|
-
setLoading(false)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
const timeout = setTimeout(() => fetchEntries(), 500)
|
|
29
|
-
|
|
30
|
-
return () => clearTimeout(timeout)
|
|
31
|
-
}, [keyword])
|
|
32
|
-
|
|
33
|
-
return useMemo(
|
|
34
|
-
() => ({
|
|
35
|
-
loading,
|
|
36
|
-
results,
|
|
37
|
-
total
|
|
38
|
-
}),
|
|
39
|
-
[results, total]
|
|
40
|
-
)
|
|
41
|
-
}
|
package/admin/src/index.tsx
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import React, { ComponentType } from "react"
|
|
2
|
-
import { prefixPluginTranslations, CustomField } from "@strapi/helper-plugin"
|
|
3
|
-
|
|
4
|
-
import pluginPkg from "../../package.json"
|
|
5
|
-
|
|
6
|
-
import PluginIcon from "./components/PluginIcon"
|
|
7
|
-
import pluginId from "./pluginId"
|
|
8
|
-
import getTrad from "./utils/getTrad"
|
|
9
|
-
import { listContentTypes } from "./helpers/content"
|
|
10
|
-
import { setContentTypes } from "./helpers/storage"
|
|
11
|
-
|
|
12
|
-
const name = pluginPkg.strapi.name
|
|
13
|
-
|
|
14
|
-
export default {
|
|
15
|
-
async register(app) {
|
|
16
|
-
const contentTypes = await listContentTypes()
|
|
17
|
-
setContentTypes(contentTypes)
|
|
18
|
-
|
|
19
|
-
app.customFields.register({
|
|
20
|
-
name,
|
|
21
|
-
pluginId,
|
|
22
|
-
type: "richtext",
|
|
23
|
-
intlLabel: {
|
|
24
|
-
id: "multi-content-type-relation.text-ai.label",
|
|
25
|
-
defaultMessage: "Multi Content Type Relation"
|
|
26
|
-
},
|
|
27
|
-
intlDescription: {
|
|
28
|
-
id: "multi-content-type-relation.text-ai.description",
|
|
29
|
-
defaultMessage: "Write content types separated by commas"
|
|
30
|
-
},
|
|
31
|
-
icon: PluginIcon, // don't forget to create/import your icon component
|
|
32
|
-
components: {
|
|
33
|
-
Input: async () =>
|
|
34
|
-
import(/* webpackChunkName: "input-component" */ "./components/Input") as unknown as ComponentType
|
|
35
|
-
},
|
|
36
|
-
inputSize: {
|
|
37
|
-
default: 12,
|
|
38
|
-
isResizable: false
|
|
39
|
-
},
|
|
40
|
-
options: {
|
|
41
|
-
base: [
|
|
42
|
-
/*
|
|
43
|
-
Declare settings to be added to the "Base settings" section
|
|
44
|
-
of the field in the Content-Type Builder
|
|
45
|
-
*/
|
|
46
|
-
{
|
|
47
|
-
sectionTitle: {
|
|
48
|
-
id: "multi-content-type-relation.text-ai.length",
|
|
49
|
-
defaultMessage: "Content types"
|
|
50
|
-
},
|
|
51
|
-
items: contentTypes.map((contentType) => {
|
|
52
|
-
const value = contentType.info.singularName
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
intlLabel: {
|
|
56
|
-
id: `multi-content-type-relation.options.${contentType.uid}`,
|
|
57
|
-
defaultMessage: contentType.info.displayName
|
|
58
|
-
},
|
|
59
|
-
type: "checkbox",
|
|
60
|
-
name: `options.contentTypes.${value}`
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
],
|
|
65
|
-
advanced: [
|
|
66
|
-
{
|
|
67
|
-
sectionTitle: {
|
|
68
|
-
id: "global.settings",
|
|
69
|
-
defaultMessage: "Settings"
|
|
70
|
-
},
|
|
71
|
-
items: [
|
|
72
|
-
{
|
|
73
|
-
name: "required",
|
|
74
|
-
type: "checkbox",
|
|
75
|
-
intlLabel: {
|
|
76
|
-
id: getTrad("content-type-relation-select.options.advanced.requiredField"),
|
|
77
|
-
defaultMessage: "Required field"
|
|
78
|
-
},
|
|
79
|
-
description: {
|
|
80
|
-
id: getTrad("content-type-relation-select.options.advanced.requiredField.description"),
|
|
81
|
-
defaultMessage: "You won't be able to create an entry if this field is empty"
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: "options.min",
|
|
86
|
-
type: "number",
|
|
87
|
-
intlLabel: {
|
|
88
|
-
id: getTrad("content-type-relation-select.options.advanced.minField"),
|
|
89
|
-
defaultMessage: "Minimum values"
|
|
90
|
-
},
|
|
91
|
-
description: {
|
|
92
|
-
id: getTrad("content-type-relation-select.options.advanced.minField.description"),
|
|
93
|
-
defaultMessage: "Minimum number of entries"
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
name: "options.max",
|
|
98
|
-
type: "number",
|
|
99
|
-
intlLabel: {
|
|
100
|
-
id: getTrad("content-type-relation-select.options.advanced.maxField"),
|
|
101
|
-
defaultMessage: "Maximum values"
|
|
102
|
-
},
|
|
103
|
-
description: {
|
|
104
|
-
id: getTrad("content-type-relation-select.options.advanced.maxField.description"),
|
|
105
|
-
defaultMessage: "Maximum number of entries"
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
]
|
|
111
|
-
}
|
|
112
|
-
} as CustomField)
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
bootstrap(app: any) {},
|
|
116
|
-
|
|
117
|
-
async registerTrads(app: any) {
|
|
118
|
-
const { locales } = app
|
|
119
|
-
|
|
120
|
-
const importedTrads = await Promise.all(
|
|
121
|
-
(locales as any[]).map((locale) => {
|
|
122
|
-
return import(`./translations/${locale}.json`)
|
|
123
|
-
.then(({ default: data }) => {
|
|
124
|
-
return {
|
|
125
|
-
data: prefixPluginTranslations(data, pluginId),
|
|
126
|
-
locale
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
.catch(() => {
|
|
130
|
-
return {
|
|
131
|
-
data: {},
|
|
132
|
-
locale
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
return Promise.resolve(importedTrads)
|
|
139
|
-
}
|
|
140
|
-
}
|
package/admin/src/interface.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export type PluginOption = {
|
|
2
|
-
options: {
|
|
3
|
-
min: number
|
|
4
|
-
max: number
|
|
5
|
-
contentTypes: string
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type MatchingContent = {
|
|
10
|
-
uid: string
|
|
11
|
-
displayName: string
|
|
12
|
-
searchableField: string
|
|
13
|
-
results: {
|
|
14
|
-
id: string
|
|
15
|
-
[key: string]: any
|
|
16
|
-
}[]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type MatchingContentResponse = {
|
|
20
|
-
data: MatchingContent[]
|
|
21
|
-
total: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type SelectedEntry = {
|
|
25
|
-
displayName: string
|
|
26
|
-
searchableField: string
|
|
27
|
-
uid: string
|
|
28
|
-
item: {
|
|
29
|
-
id: string
|
|
30
|
-
[key: string]: any
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type FormattedStrapiEntry = {
|
|
35
|
-
uid: string
|
|
36
|
-
id: string
|
|
37
|
-
}
|
package/admin/src/pluginId.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
package/dist/server/bootstrap.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = {
|
|
4
|
-
default: ({ env }) => {
|
|
5
|
-
return {
|
|
6
|
-
recursive: {
|
|
7
|
-
enabled: false,
|
|
8
|
-
maxDepth: 1
|
|
9
|
-
},
|
|
10
|
-
debug: false
|
|
11
|
-
};
|
|
12
|
-
},
|
|
13
|
-
validator(config) {
|
|
14
|
-
if (typeof config.recursive !== "object") {
|
|
15
|
-
throw new Error("recursive must be an object");
|
|
16
|
-
}
|
|
17
|
-
if (typeof config.recursive.enabled !== "boolean") {
|
|
18
|
-
throw new Error("recursive.enabled must be a boolean");
|
|
19
|
-
}
|
|
20
|
-
if (typeof config.recursive.maxDepth !== "number") {
|
|
21
|
-
throw new Error("recursive.maxDepth must be a number");
|
|
22
|
-
}
|
|
23
|
-
if (typeof config.debug !== "boolean") {
|
|
24
|
-
throw new Error("Debug must be a boolean");
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = ({ strapi }) => ({
|
|
4
|
-
getMatchingContent(ctx) {
|
|
5
|
-
const contentTypes = strapi.contentTypes;
|
|
6
|
-
const body = ctx.request.body;
|
|
7
|
-
const requestedContentTypes = body.contentTypes;
|
|
8
|
-
const keyword = body.keyword;
|
|
9
|
-
const locale = body.locale;
|
|
10
|
-
const mapping = requestedContentTypes.reduce((accumulator, contentType) => {
|
|
11
|
-
Object.keys(contentTypes).forEach((model) => {
|
|
12
|
-
const strapiContentType = contentTypes[model];
|
|
13
|
-
if (strapiContentType.info.singularName === contentType || strapiContentType.info.pluralName === contentType) {
|
|
14
|
-
accumulator[contentType] = {
|
|
15
|
-
uid: model,
|
|
16
|
-
displayName: contentTypes[model].info.displayName,
|
|
17
|
-
searchableField: strapi
|
|
18
|
-
.plugin("multi-content-type-relation")
|
|
19
|
-
.service("service")
|
|
20
|
-
.getFirstStringFieldInContentType(contentTypes[model])
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
return accumulator;
|
|
25
|
-
}, {});
|
|
26
|
-
const promises = Object.keys(mapping).map((contentType) => {
|
|
27
|
-
const uid = mapping[contentType].uid;
|
|
28
|
-
return strapi
|
|
29
|
-
.entityService.findMany(uid, {
|
|
30
|
-
filters: {
|
|
31
|
-
[mapping[contentType].searchableField]: {
|
|
32
|
-
$containsi: keyword
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
locale
|
|
36
|
-
})
|
|
37
|
-
.then((results) => {
|
|
38
|
-
var _a;
|
|
39
|
-
let contents = Array.isArray(results) ? results : typeof results === "object" && results ? [results] : [];
|
|
40
|
-
const contentTypeDefinition = strapi.contentType(uid);
|
|
41
|
-
if ((_a = contentTypeDefinition === null || contentTypeDefinition === void 0 ? void 0 : contentTypeDefinition.options) === null || _a === void 0 ? void 0 : _a.draftAndPublish) {
|
|
42
|
-
contents = contents.filter((content) => content.publishedAt !== null);
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
uid,
|
|
46
|
-
displayName: mapping[contentType].displayName,
|
|
47
|
-
searchableField: mapping[contentType].searchableField,
|
|
48
|
-
results: contents
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
return Promise.all(promises);
|
|
53
|
-
},
|
|
54
|
-
validateRelations: async function (ctx) {
|
|
55
|
-
const contentTypes = strapi.contentTypes;
|
|
56
|
-
const body = ctx.request.body;
|
|
57
|
-
const entries = body.entries;
|
|
58
|
-
const promises = entries.map((entry) => {
|
|
59
|
-
return strapi
|
|
60
|
-
.entityService.findOne(entry.uid, entry.id, { populate: "deep" })
|
|
61
|
-
.then((result) => {
|
|
62
|
-
return {
|
|
63
|
-
uid: entry.uid,
|
|
64
|
-
result
|
|
65
|
-
};
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
const responses = await Promise.all(promises);
|
|
69
|
-
return responses
|
|
70
|
-
.map((response) => {
|
|
71
|
-
return {
|
|
72
|
-
displayName: contentTypes[response.uid].info.displayName,
|
|
73
|
-
uid: response.uid,
|
|
74
|
-
searchableField: strapi
|
|
75
|
-
.plugin("multi-content-type-relation")
|
|
76
|
-
.service("service")
|
|
77
|
-
.getFirstStringFieldInContentType(contentTypes[response.uid]),
|
|
78
|
-
item: response.result
|
|
79
|
-
};
|
|
80
|
-
})
|
|
81
|
-
.filter((entry) => entry.item);
|
|
82
|
-
},
|
|
83
|
-
listContentTypes: async function (ctx) {
|
|
84
|
-
const contentTypes = [];
|
|
85
|
-
for (const contentType of Object.values(strapi.contentTypes)) {
|
|
86
|
-
if ((contentType.kind === "collectionType" || contentType.kind === "singleType") && !contentType.plugin) {
|
|
87
|
-
contentTypes.push(contentType);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return contentTypes;
|
|
91
|
-
}
|
|
92
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const controller_1 = __importDefault(require("./controller"));
|
|
7
|
-
exports.default = {
|
|
8
|
-
controller: controller_1.default
|
|
9
|
-
};
|
package/dist/server/destroy.js
DELETED
package/dist/server/interface.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const middleware_1 = __importDefault(require("./middleware"));
|
|
7
|
-
exports.default = {
|
|
8
|
-
middleware: middleware_1.default
|
|
9
|
-
};
|