@webbio/strapi-plugin-page-builder 0.12.8-platform → 0.14.0-platform
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 +13 -1
- package/admin/src/api/page-type-exists.ts +44 -0
- package/admin/src/api/search-filtered-entity.ts +27 -7
- package/admin/src/components/EditView/CollectionTypeSettings/index.tsx +17 -6
- package/admin/src/components/EditView/Details/styles.ts +11 -1
- package/admin/src/components/PageFilters/filters.tsx +18 -10
- package/admin/src/components/PlatformFilteredSelectField/Multi/index.tsx +21 -13
- package/admin/src/components/PlatformFilteredSelectField/Single/index.tsx +42 -22
- package/admin/src/components/PlatformFilteredSelectField/hooks/useRelationLoad.tsx +1 -1
- package/admin/src/components/PlatformFilteredSelectField/index.tsx +7 -1
- package/admin/src/components/PlatformFilteredSelectField/styles.tsx +20 -1
- package/admin/src/components/PlatformFilteredSelectField/utils/get-condition-filters.ts +82 -0
- package/admin/src/components/PlatformFilteredSelectField/utils/relation-helper.ts +28 -9
- package/admin/src/components/StrapiCore/admin/admin/src/content-manager/components/Relations/RelationInput.tsx +41 -15
- package/admin/src/utils/hooks/useQueryParams.ts +52 -0
- package/admin/src/utils/isJson.ts +9 -0
- package/dist/package.json +1 -1
- package/dist/server/bootstrap/permissions.js +19 -16
- package/dist/server/controllers/private-content.js +1 -1
- package/dist/tsconfig.server.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/server/bootstrap/permissions.ts +21 -17
- package/server/controllers/private-content.ts +1 -1
package/README.md
CHANGED
|
@@ -137,7 +137,19 @@ Ik wil een lijst van vacature relaties selecteren. Deze vacatures moeten van het
|
|
|
137
137
|
// (Default: true). Disables result filtering by globally selected platform
|
|
138
138
|
"disablePlatformFilter": boolean,
|
|
139
139
|
// (Default: false) Hides id of the entity that is edited if it's the same as the targetField uid. So if this is enabled on a vacancy entity and also targets other vacancies, the current vacancy that is edited will not be shown.
|
|
140
|
-
"hideSameEntity": boolean
|
|
140
|
+
"hideSameEntity": boolean,
|
|
141
|
+
// (Default: ['title']) Defines searchable fields
|
|
142
|
+
"searchableFields": string[],
|
|
143
|
+
// If set the field will show a subtitle with the value that results in following this path.
|
|
144
|
+
"subTitlePath": string,
|
|
145
|
+
// Conditional filters add the posibility to who results based on values from other fields.
|
|
146
|
+
// For now this only works for fields on the same level as the targetfield.
|
|
147
|
+
// The value found will be replacing the '${value}' string.
|
|
148
|
+
"conditionalFilters": {
|
|
149
|
+
"targetField": string,
|
|
150
|
+
"targetFieldKey": string,
|
|
151
|
+
"filter": [{ "title": { "$contains": "${value}" } }]
|
|
152
|
+
}[];
|
|
141
153
|
}
|
|
142
154
|
},
|
|
143
155
|
"type": "customField",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from 'react-query';
|
|
2
|
+
|
|
3
|
+
import { useFetchClient } from '@strapi/helper-plugin';
|
|
4
|
+
|
|
5
|
+
type PageTypeExistsQueryParams = {
|
|
6
|
+
uid: string;
|
|
7
|
+
fetchClient?: any;
|
|
8
|
+
platformId: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const QUERY_KEY = 'pageTypeExists';
|
|
12
|
+
|
|
13
|
+
const fetchPageTypeExists = async ({ fetchClient, uid, platformId }: PageTypeExistsQueryParams): Promise<boolean> => {
|
|
14
|
+
try {
|
|
15
|
+
if (!uid) {
|
|
16
|
+
throw new Error('No uid');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!platformId) {
|
|
20
|
+
throw new Error('No platformId');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const { get } = fetchClient;
|
|
24
|
+
const result = await get('/content-manager/collection-types/api::page-type.page-type?page=1&pageSize=999');
|
|
25
|
+
|
|
26
|
+
const pageTypeExists = result?.data?.results.some(
|
|
27
|
+
(entity: Record<string, any>) => entity?.platform?.id === platformId && entity.uid === uid
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return Boolean(pageTypeExists);
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const usePageTypeExists = (params: PageTypeExistsQueryParams, options?: UseQueryOptions<boolean, Error>) => {
|
|
37
|
+
const fetchClient = useFetchClient();
|
|
38
|
+
|
|
39
|
+
return useQuery<boolean, Error>(
|
|
40
|
+
[QUERY_KEY, params?.uid, params.platformId],
|
|
41
|
+
() => fetchPageTypeExists({ ...params, fetchClient }),
|
|
42
|
+
options
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { useQuery, UseQueryOptions } from 'react-query';
|
|
2
2
|
import orderBy from 'lodash/orderBy';
|
|
3
|
+
import objGet from 'lodash/get';
|
|
3
4
|
|
|
4
5
|
import { useFetchClient } from '@strapi/helper-plugin';
|
|
5
6
|
import qs from 'qs';
|
|
7
|
+
import { getConditionalFilters } from '../components/PlatformFilteredSelectField/utils/get-condition-filters';
|
|
6
8
|
|
|
7
9
|
export type SearchFilteredEntitiesResult = {
|
|
8
10
|
pagination: {
|
|
@@ -17,6 +19,7 @@ export type SearchFilteredEntitiesResult = {
|
|
|
17
19
|
href: string;
|
|
18
20
|
publicationState?: string | false;
|
|
19
21
|
publishedAt?: string;
|
|
22
|
+
subTitle?: string;
|
|
20
23
|
}[];
|
|
21
24
|
};
|
|
22
25
|
|
|
@@ -29,6 +32,10 @@ type SearchFilteredEntitiesQueryParams = {
|
|
|
29
32
|
platformTitle?: string;
|
|
30
33
|
notIds?: number[];
|
|
31
34
|
customFilters?: Record<string, any>[];
|
|
35
|
+
searchableFields?: string[];
|
|
36
|
+
subTitlePath?: string;
|
|
37
|
+
mainFieldName?: string;
|
|
38
|
+
conditionalFilters?: Record<string, any>[];
|
|
32
39
|
};
|
|
33
40
|
|
|
34
41
|
const QUERY_KEY = 'filteredEntities';
|
|
@@ -41,24 +48,34 @@ export const getSearchFilteredEntities = async ({
|
|
|
41
48
|
searchQuery,
|
|
42
49
|
platformTitle,
|
|
43
50
|
notIds,
|
|
44
|
-
customFilters
|
|
51
|
+
customFilters,
|
|
52
|
+
searchableFields = ['title'],
|
|
53
|
+
subTitlePath,
|
|
54
|
+
mainFieldName = 'title',
|
|
55
|
+
conditionalFilters = []
|
|
45
56
|
}: SearchFilteredEntitiesQueryParams): Promise<SearchFilteredEntitiesResult> => {
|
|
46
57
|
try {
|
|
47
58
|
const { get } = fetchClient;
|
|
48
59
|
const notIdFilters = notIds && notIds.length > 0 ? notIds.map((id) => ({ id: { $ne: id } })) : [];
|
|
49
60
|
const customFilterObject = Array.isArray(customFilters) ? customFilters : [];
|
|
50
61
|
|
|
62
|
+
const fieldFilters = searchableFields.map((field) => ({ [field]: { $containsi: searchQuery } }));
|
|
63
|
+
|
|
51
64
|
const filters = qs.stringify({
|
|
52
65
|
page,
|
|
53
66
|
pageSize: 20,
|
|
54
67
|
locale,
|
|
55
|
-
|
|
56
|
-
_q: searchQuery || undefined,
|
|
68
|
+
// _q is a fuzzy search with sometimes unexpected results
|
|
69
|
+
// _q: searchQuery || undefined,
|
|
57
70
|
filters: {
|
|
58
71
|
$and: [
|
|
59
|
-
{ platform: { title: { $
|
|
72
|
+
{ platform: { title: { $eq: platformTitle || undefined } } },
|
|
73
|
+
{
|
|
74
|
+
$or: fieldFilters
|
|
75
|
+
},
|
|
60
76
|
...notIdFilters,
|
|
61
|
-
...customFilterObject
|
|
77
|
+
...customFilterObject,
|
|
78
|
+
...conditionalFilters
|
|
62
79
|
]
|
|
63
80
|
}
|
|
64
81
|
});
|
|
@@ -74,12 +91,15 @@ export const getSearchFilteredEntities = async ({
|
|
|
74
91
|
return false;
|
|
75
92
|
};
|
|
76
93
|
|
|
94
|
+
const subTitle = subTitlePath ? objGet(result, subTitlePath) : undefined;
|
|
95
|
+
|
|
77
96
|
return {
|
|
78
97
|
id: result.id,
|
|
79
|
-
title: result
|
|
98
|
+
title: result?.[mainFieldName],
|
|
80
99
|
publicationState: getPublicationState(),
|
|
81
100
|
publishedAt: result?.publishedAt,
|
|
82
|
-
href: `/content-manager/collectionType/${uid}/${result.id}
|
|
101
|
+
href: `/content-manager/collectionType/${uid}/${result.id}`,
|
|
102
|
+
subTitle: typeof subTitle === 'string' || typeof subTitle === 'number' ? String(subTitle) : ''
|
|
83
103
|
};
|
|
84
104
|
}
|
|
85
105
|
);
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
|
|
4
|
-
import { Flex } from '@strapi/design-system';
|
|
5
|
-
import { Link } from '@strapi/icons';
|
|
4
|
+
import { Flex, Typography, Link } from '@strapi/design-system';
|
|
5
|
+
import { Link as LinkIcon } from '@strapi/icons';
|
|
6
6
|
|
|
7
7
|
import { Wrapper } from '../wrapper';
|
|
8
8
|
import { CreatePageButton } from './CreatePageButton';
|
|
9
9
|
import { PAGE_TYPE_PAGE, PAGE_UID } from '../../../../../shared/utils/constants';
|
|
10
10
|
import { usePlatformFormData } from '../../../utils/hooks/usePlatformFormData';
|
|
11
11
|
import S from '../Details/styles';
|
|
12
|
+
import { usePageTypeExists } from '../../../api/page-type-exists';
|
|
12
13
|
|
|
13
14
|
interface CollectionTypeSettingsProps {
|
|
14
15
|
onlyPlatform?: boolean;
|
|
@@ -20,8 +21,11 @@ export const CollectionTypeSettings = ({ onlyPlatform }: CollectionTypeSettingsP
|
|
|
20
21
|
const { layout, isCreatingEntry, initialData, modifiedData, onChange } = form;
|
|
21
22
|
const isUserCreatedContentType = layout.uid.startsWith('api::');
|
|
22
23
|
const [linkedPage, setLinkedPage] = useState<Record<string, any> | undefined>(initialData.page?.[0]);
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const { data: pageTypeExists, isLoading: isLoadingPageTypeExists } = usePageTypeExists({
|
|
25
|
+
uid: layout.uid,
|
|
26
|
+
platformId: selectedPlatform?.id
|
|
27
|
+
});
|
|
28
|
+
const showCreatePageButton = !linkedPage && isUserCreatedContentType && !isCreatingEntry && !isLoadingPlatform;
|
|
25
29
|
const url = generateLink(linkedPage?.id, initialData?.locale);
|
|
26
30
|
|
|
27
31
|
useEffect(() => {
|
|
@@ -50,7 +54,14 @@ export const CollectionTypeSettings = ({ onlyPlatform }: CollectionTypeSettingsP
|
|
|
50
54
|
{!isCreatingEntry && !onlyPlatform && (
|
|
51
55
|
<Wrapper title="Gekoppelde pagina">
|
|
52
56
|
<Flex direction="column" gap={4} width="100%" alignItems="start">
|
|
53
|
-
{
|
|
57
|
+
{!pageTypeExists && !linkedPage && !isLoadingPageTypeExists && (
|
|
58
|
+
<S.InfoType variant="pi" textColor="neutral800">
|
|
59
|
+
Er bestaat nog geen{' '}
|
|
60
|
+
<Link to="/content-manager/collectionType/api::page-type.page-type">pagina type</Link> voor dit content
|
|
61
|
+
type.
|
|
62
|
+
</S.InfoType>
|
|
63
|
+
)}
|
|
64
|
+
{showCreatePageButton && selectedPlatform && (pageTypeExists || linkedPage) && (
|
|
54
65
|
<CreatePageButton onCreatedPage={(page) => setLinkedPage(page)} selectedPlatform={selectedPlatform} />
|
|
55
66
|
)}
|
|
56
67
|
|
|
@@ -61,7 +72,7 @@ export const CollectionTypeSettings = ({ onlyPlatform }: CollectionTypeSettingsP
|
|
|
61
72
|
</S.SubtleType>
|
|
62
73
|
<S.EntityLinkWrapper variant="pi" textColor="neutral800">
|
|
63
74
|
<S.EntityLink title={linkedPage?.title || '-'} to={url} variant="pi">
|
|
64
|
-
<
|
|
75
|
+
<LinkIcon />
|
|
65
76
|
{linkedPage?.title || '-'}
|
|
66
77
|
</S.EntityLink>
|
|
67
78
|
</S.EntityLinkWrapper>
|
|
@@ -8,6 +8,15 @@ const SubtleType = styled(Typography)`
|
|
|
8
8
|
`}
|
|
9
9
|
`;
|
|
10
10
|
|
|
11
|
+
const InfoType = styled(Typography)`
|
|
12
|
+
${({ theme }) => css`
|
|
13
|
+
&,
|
|
14
|
+
a span {
|
|
15
|
+
font-size: ${theme.fontSizes[1]};
|
|
16
|
+
}
|
|
17
|
+
`}
|
|
18
|
+
`;
|
|
19
|
+
|
|
11
20
|
const EntityLinkWrapper = styled(Typography)`
|
|
12
21
|
${({ _theme }) => css`
|
|
13
22
|
display: flex;
|
|
@@ -45,7 +54,8 @@ const DetailsStyles = {
|
|
|
45
54
|
SubtleType,
|
|
46
55
|
EntityLink,
|
|
47
56
|
EntityLinkWrapper,
|
|
48
|
-
EditLink
|
|
57
|
+
EditLink,
|
|
58
|
+
InfoType
|
|
49
59
|
};
|
|
50
60
|
|
|
51
61
|
export default DetailsStyles;
|
|
@@ -2,7 +2,6 @@ import { useEffect, useMemo } from 'react';
|
|
|
2
2
|
import set from 'lodash/set';
|
|
3
3
|
|
|
4
4
|
import { Stack } from '@strapi/design-system';
|
|
5
|
-
import { useQueryParams } from '@strapi/helper-plugin';
|
|
6
5
|
|
|
7
6
|
import PageTypeFilter from './PageTypeFilter';
|
|
8
7
|
import { PAGE_TYPE_PAGE, PLATFORM } from '../../../../shared/utils/constants';
|
|
@@ -12,13 +11,14 @@ import { PageType } from '../../api/platform-page-types';
|
|
|
12
11
|
import { useGetPageTypesForPlatform } from '../../api/platform-page-types';
|
|
13
12
|
import { useDefaultPlatformFromLocalStorage } from '../../utils/hooks/useDefaultPlatformFromLocalStorage';
|
|
14
13
|
import { useHideOverviewFilterTags } from '../../utils/hooks/useHideOverviewFilterTags';
|
|
14
|
+
import { useQueryParams } from '../../utils/hooks/useQueryParams';
|
|
15
15
|
|
|
16
16
|
interface PageFiltersProps {
|
|
17
17
|
hidePageType?: boolean;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const PageFilters = ({ hidePageType }: PageFiltersProps) => {
|
|
21
|
-
const [{ query }, setQuery] = useQueryParams()
|
|
21
|
+
const [{ query }, setQuery] = useQueryParams();
|
|
22
22
|
const { selectedPlatform: globalSelectedPlatform } = useDefaultPlatformFromLocalStorage();
|
|
23
23
|
useHideOverviewFilterTags();
|
|
24
24
|
const { data: platforms } = useGetPlatforms({});
|
|
@@ -50,19 +50,27 @@ const PageFilters = ({ hidePageType }: PageFiltersProps) => {
|
|
|
50
50
|
|
|
51
51
|
const removedFilters = removeFiltersFromQuery({ filters: currentFilters }, filterCategoryToRemove);
|
|
52
52
|
|
|
53
|
-
setQuery(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
setQuery(
|
|
54
|
+
{
|
|
55
|
+
page: 1,
|
|
56
|
+
filters: removedFilters
|
|
57
|
+
},
|
|
58
|
+
undefined,
|
|
59
|
+
'replace'
|
|
60
|
+
);
|
|
57
61
|
};
|
|
58
62
|
|
|
59
63
|
const removeFilters = (filterCategory: string) => {
|
|
60
64
|
const filters = removeFiltersFromQuery(query, filterCategory);
|
|
61
65
|
|
|
62
|
-
setQuery(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
setQuery(
|
|
67
|
+
{
|
|
68
|
+
page: 1,
|
|
69
|
+
filters
|
|
70
|
+
},
|
|
71
|
+
undefined,
|
|
72
|
+
'replace'
|
|
73
|
+
);
|
|
66
74
|
};
|
|
67
75
|
|
|
68
76
|
const handlePlatformSelect = (platformTitle: string) => {
|
|
@@ -14,7 +14,7 @@ import { useGetLocaleFromUrl } from '../../../utils/hooks/useGetLocaleFromUrl';
|
|
|
14
14
|
import { getSearchFilteredEntities } from '../../../api/search-filtered-entity';
|
|
15
15
|
import RelationHelper, { IPlatformFilteredSelectFieldProps } from '../utils/relation-helper';
|
|
16
16
|
import { getTranslation } from '../utils/get-translations';
|
|
17
|
-
import {
|
|
17
|
+
import { getConditionalFilters } from '../utils/get-condition-filters';
|
|
18
18
|
|
|
19
19
|
const PAGE = 1;
|
|
20
20
|
|
|
@@ -25,8 +25,6 @@ export interface IMultiPlatformFilteredSelectFieldProps extends IPlatformFiltere
|
|
|
25
25
|
isCloningEntry?: boolean;
|
|
26
26
|
totalRelations: number;
|
|
27
27
|
relationsFromModifiedData?: Record<string, any>[];
|
|
28
|
-
selectedPlatform?: Platform;
|
|
29
|
-
hiddenId?: number[];
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
const MultiPlatformFilteredSelectField = ({
|
|
@@ -43,7 +41,8 @@ const MultiPlatformFilteredSelectField = ({
|
|
|
43
41
|
totalRelations,
|
|
44
42
|
relationsFromModifiedData,
|
|
45
43
|
selectedPlatform,
|
|
46
|
-
hiddenId
|
|
44
|
+
hiddenId,
|
|
45
|
+
disabled
|
|
47
46
|
}: IMultiPlatformFilteredSelectFieldProps) => {
|
|
48
47
|
const fetchClient = useFetchClient();
|
|
49
48
|
const {
|
|
@@ -73,12 +72,8 @@ const MultiPlatformFilteredSelectField = ({
|
|
|
73
72
|
|
|
74
73
|
const { formatMessage } = useIntl();
|
|
75
74
|
|
|
76
|
-
const { targetAttributes, targetFieldValue, targetField } = RelationHelper.getTargetAttributes(
|
|
77
|
-
name,
|
|
78
|
-
attribute,
|
|
79
|
-
modifiedData,
|
|
80
|
-
layout,
|
|
81
|
-
allLayoutData
|
|
75
|
+
const { targetAttributes, targetFieldValue, targetField, relationMainFieldName } = RelationHelper.getTargetAttributes(
|
|
76
|
+
{ fieldName: name, attribute, modifiedData, layout, allLayoutData }
|
|
82
77
|
);
|
|
83
78
|
|
|
84
79
|
const label = intlLabel?.id
|
|
@@ -94,6 +89,14 @@ const MultiPlatformFilteredSelectField = ({
|
|
|
94
89
|
}, [targetFieldValue]);
|
|
95
90
|
|
|
96
91
|
const getItems = async (inputValue?: string) => {
|
|
92
|
+
const conditionalFilters = getConditionalFilters({
|
|
93
|
+
fieldName: name,
|
|
94
|
+
allLayoutData,
|
|
95
|
+
attribute,
|
|
96
|
+
layout,
|
|
97
|
+
modifiedData
|
|
98
|
+
});
|
|
99
|
+
|
|
97
100
|
const entities = await getSearchFilteredEntities({
|
|
98
101
|
fetchClient,
|
|
99
102
|
page: PAGE,
|
|
@@ -102,7 +105,11 @@ const MultiPlatformFilteredSelectField = ({
|
|
|
102
105
|
searchQuery: inputValue,
|
|
103
106
|
platformTitle: attribute?.pluginOptions?.filteredSelect?.disablePlatformFilter ? '' : selectedPlatform?.title,
|
|
104
107
|
notIds: [...(selectedResults?.data || []).map((x: Record<string, any>) => x.id), ...(hiddenId || [])],
|
|
105
|
-
customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters
|
|
108
|
+
customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters,
|
|
109
|
+
searchableFields: attribute?.pluginOptions?.filteredSelect?.searchableFields,
|
|
110
|
+
subTitlePath: attribute?.pluginOptions?.filteredSelect?.subTitlePath,
|
|
111
|
+
mainFieldName: relationMainFieldName,
|
|
112
|
+
conditionalFilters
|
|
106
113
|
});
|
|
107
114
|
|
|
108
115
|
const mapped = entities?.results.map((x) => ({
|
|
@@ -110,7 +117,8 @@ const MultiPlatformFilteredSelectField = ({
|
|
|
110
117
|
mainField: x.title,
|
|
111
118
|
href: x?.href,
|
|
112
119
|
publicationState: x.publicationState,
|
|
113
|
-
publishedAt: x.publishedAt
|
|
120
|
+
publishedAt: x.publishedAt,
|
|
121
|
+
subTitle: x.subTitle
|
|
114
122
|
}));
|
|
115
123
|
|
|
116
124
|
// @ts-expect-error data is fine
|
|
@@ -202,7 +210,7 @@ const MultiPlatformFilteredSelectField = ({
|
|
|
202
210
|
hint={hint || ''}
|
|
203
211
|
labelAction={labelAction}
|
|
204
212
|
required={required}
|
|
205
|
-
disabled={!selectedPlatform}
|
|
213
|
+
disabled={!selectedPlatform || disabled}
|
|
206
214
|
/>
|
|
207
215
|
);
|
|
208
216
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import debounce from 'lodash/debounce';
|
|
4
|
+
import objGet from 'lodash/get';
|
|
4
5
|
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
|
|
5
6
|
import { useSelector } from 'react-redux';
|
|
6
|
-
import { Field } from '@strapi/design-system';
|
|
7
|
+
import { Field, Flex } from '@strapi/design-system';
|
|
7
8
|
import { useFetchClient } from '@strapi/helper-plugin';
|
|
8
9
|
import { Link } from '@strapi/icons';
|
|
9
10
|
|
|
@@ -14,17 +15,15 @@ import { getSearchFilteredEntities } from '../../../api/search-filtered-entity';
|
|
|
14
15
|
import S from './../styles';
|
|
15
16
|
import getTrad from '../../../utils/getTrad';
|
|
16
17
|
import RelationHelper, { IPlatformFilteredSelectFieldProps } from '../utils/relation-helper';
|
|
17
|
-
import {
|
|
18
|
+
import { getConditionalFilters } from '../utils/get-condition-filters';
|
|
18
19
|
|
|
19
|
-
export interface ISinglePlatformFilteredSelectFieldProps extends IPlatformFilteredSelectFieldProps {
|
|
20
|
-
selectedPlatform?: Platform;
|
|
21
|
-
hiddenId?: number[];
|
|
22
|
-
}
|
|
20
|
+
export interface ISinglePlatformFilteredSelectFieldProps extends IPlatformFilteredSelectFieldProps {}
|
|
23
21
|
|
|
24
22
|
interface CustomReactSelectValue extends Omit<IReactSelectValue, 'initialSelected'> {
|
|
25
23
|
href?: string;
|
|
26
24
|
publicationState?: string | false;
|
|
27
25
|
publishedAt?: string;
|
|
26
|
+
subTitle?: string;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
const SEARCH_DEBOUNCE_MS = 150;
|
|
@@ -38,7 +37,8 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
38
37
|
intlLabel,
|
|
39
38
|
name,
|
|
40
39
|
selectedPlatform,
|
|
41
|
-
hiddenId
|
|
40
|
+
hiddenId,
|
|
41
|
+
disabled
|
|
42
42
|
}: ISinglePlatformFilteredSelectFieldProps) => {
|
|
43
43
|
const fetchClient = useFetchClient();
|
|
44
44
|
const { onChange, initialData, modifiedData, isCreatingEntry, layout, allLayoutData } =
|
|
@@ -53,12 +53,8 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
53
53
|
|
|
54
54
|
const { formatMessage } = useIntl();
|
|
55
55
|
|
|
56
|
-
const { targetAttributes, targetFieldValue, targetField } = RelationHelper.getTargetAttributes(
|
|
57
|
-
name,
|
|
58
|
-
attribute,
|
|
59
|
-
modifiedData,
|
|
60
|
-
layout,
|
|
61
|
-
allLayoutData
|
|
56
|
+
const { targetAttributes, targetFieldValue, targetField, relationMainFieldName } = RelationHelper.getTargetAttributes(
|
|
57
|
+
{ fieldName: name, attribute, modifiedData, layout, allLayoutData }
|
|
62
58
|
);
|
|
63
59
|
|
|
64
60
|
const label = intlLabel?.id
|
|
@@ -70,7 +66,10 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
70
66
|
: '';
|
|
71
67
|
|
|
72
68
|
useEffect(() => {
|
|
73
|
-
const initialSelect = getInitialSelectItem(
|
|
69
|
+
const initialSelect = getInitialSelectItem(
|
|
70
|
+
targetFieldValue?.[0],
|
|
71
|
+
attribute?.pluginOptions?.filteredSelect?.subTitlePath
|
|
72
|
+
);
|
|
74
73
|
|
|
75
74
|
setSelected(initialSelect);
|
|
76
75
|
}, [targetFieldValue]);
|
|
@@ -108,6 +107,14 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
108
107
|
};
|
|
109
108
|
|
|
110
109
|
const getItems = async (inputValue?: string, platformTitle?: string): Promise<CustomReactSelectValue[]> => {
|
|
110
|
+
const conditionalFilters = getConditionalFilters({
|
|
111
|
+
fieldName: name,
|
|
112
|
+
allLayoutData,
|
|
113
|
+
attribute,
|
|
114
|
+
layout,
|
|
115
|
+
modifiedData
|
|
116
|
+
});
|
|
117
|
+
|
|
111
118
|
const pages = await getSearchFilteredEntities({
|
|
112
119
|
fetchClient,
|
|
113
120
|
page: PAGE,
|
|
@@ -116,7 +123,11 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
116
123
|
searchQuery: inputValue,
|
|
117
124
|
platformTitle: attribute?.pluginOptions?.filteredSelect?.disablePlatformFilter ? '' : platformTitle,
|
|
118
125
|
customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters,
|
|
119
|
-
notIds: hiddenId
|
|
126
|
+
notIds: hiddenId,
|
|
127
|
+
searchableFields: attribute?.pluginOptions?.filteredSelect?.searchableFields,
|
|
128
|
+
subTitlePath: attribute?.pluginOptions?.filteredSelect?.subTitlePath,
|
|
129
|
+
mainFieldName: relationMainFieldName,
|
|
130
|
+
conditionalFilters
|
|
120
131
|
});
|
|
121
132
|
|
|
122
133
|
return pages?.results.map((x) => ({
|
|
@@ -124,7 +135,8 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
124
135
|
label: x.title,
|
|
125
136
|
href: x?.href,
|
|
126
137
|
publicationState: x.publicationState,
|
|
127
|
-
publishedAt: x.publishedAt
|
|
138
|
+
publishedAt: x.publishedAt,
|
|
139
|
+
subTitle: x.subTitle
|
|
128
140
|
}));
|
|
129
141
|
};
|
|
130
142
|
|
|
@@ -153,9 +165,9 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
153
165
|
onChange={handleChange}
|
|
154
166
|
value={selected}
|
|
155
167
|
defaultOptions
|
|
156
|
-
hideSelectedOptions
|
|
168
|
+
// hideSelectedOptions
|
|
157
169
|
labelAction={labelAction}
|
|
158
|
-
isDisabled={!selectedPlatform}
|
|
170
|
+
isDisabled={!selectedPlatform || disabled}
|
|
159
171
|
afterInput={
|
|
160
172
|
<S.LinkToPage
|
|
161
173
|
title={formatMessage({ id: getTrad('platformFilteredSelect.linkToEntity.label') })}
|
|
@@ -172,25 +184,33 @@ const SinglePlatformFilteredSelectField = ({
|
|
|
172
184
|
);
|
|
173
185
|
};
|
|
174
186
|
|
|
175
|
-
const CustomOption = (props: OptionProps<CustomReactSelectValue, false>) => {
|
|
187
|
+
export const CustomOption = (props: OptionProps<CustomReactSelectValue, false>) => {
|
|
176
188
|
return (
|
|
177
189
|
<components.Option {...props}>
|
|
178
190
|
<S.CustomOption>
|
|
179
191
|
{props.data?.publicationState && <S.CustomOptionStatus publicationState={props.data?.publicationState} />}
|
|
180
|
-
|
|
192
|
+
|
|
193
|
+
<Flex direction="column" alignItems="start" gap={1}>
|
|
194
|
+
{props.children}
|
|
195
|
+
{props.data?.subTitle && <S.CustomOptionSubTitle>{props.data?.subTitle}</S.CustomOptionSubTitle>}
|
|
196
|
+
</Flex>
|
|
181
197
|
</S.CustomOption>
|
|
182
198
|
</components.Option>
|
|
183
199
|
);
|
|
184
200
|
};
|
|
185
201
|
|
|
186
|
-
const getInitialSelectItem = (
|
|
202
|
+
const getInitialSelectItem = (
|
|
203
|
+
initialValue?: Record<string, any>,
|
|
204
|
+
subTitlePath?: string
|
|
205
|
+
): SingleValue<CustomReactSelectValue | null> =>
|
|
187
206
|
initialValue?.id
|
|
188
207
|
? {
|
|
189
208
|
value: String(initialValue?.id),
|
|
190
209
|
label: initialValue?.title ?? '',
|
|
191
210
|
href: initialValue?.href,
|
|
192
211
|
publicationState: initialValue.publicationState,
|
|
193
|
-
publishedAt: initialValue.publishedAt
|
|
212
|
+
publishedAt: initialValue.publishedAt,
|
|
213
|
+
subTitle: subTitlePath ? objGet(initialValue, subTitlePath) : ''
|
|
194
214
|
}
|
|
195
215
|
: null;
|
|
196
216
|
|
|
@@ -24,7 +24,7 @@ const useRelationLoad = ({ name, attribute }: IRelationLoadProps) => {
|
|
|
24
24
|
const entityId = origin || modifiedData.id;
|
|
25
25
|
|
|
26
26
|
const { componentUid, componentId, relationMainFieldName, targetAttributes, targetField, targetFieldName } =
|
|
27
|
-
RelationHelper.getTargetAttributes(fieldName, attribute, modifiedData, layout, allLayoutData);
|
|
27
|
+
RelationHelper.getTargetAttributes({ fieldName, attribute, modifiedData, layout, allLayoutData });
|
|
28
28
|
|
|
29
29
|
const nameSplit = targetFieldName.split('.');
|
|
30
30
|
const isComponentRelation = Boolean(componentUid);
|
|
@@ -13,7 +13,13 @@ const PlatformFilteredSelectField = (props: IPlatformFilteredSelectFieldProps) =
|
|
|
13
13
|
const { modifiedData, layout, allLayoutData } = form;
|
|
14
14
|
const { selectedPlatform } = usePlatformFormData(form);
|
|
15
15
|
const { relations, isCloningEntry, totalRelations, relationsFromModifiedData } = useRelationLoad(props);
|
|
16
|
-
const { targetAttributes } = RelationHelper.getTargetAttributes(
|
|
16
|
+
const { targetAttributes } = RelationHelper.getTargetAttributes({
|
|
17
|
+
fieldName: name,
|
|
18
|
+
attribute,
|
|
19
|
+
modifiedData,
|
|
20
|
+
layout,
|
|
21
|
+
allLayoutData
|
|
22
|
+
});
|
|
17
23
|
const toOneRelation = ['oneWay', 'oneToOne', 'manyToOne', 'oneToManyMorph', 'oneToOneMorph'].includes(
|
|
18
24
|
targetAttributes?.relation || ''
|
|
19
25
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import styled, { css } from 'styled-components';
|
|
2
|
-
import { Box, Link, Typography } from '@strapi/design-system';
|
|
2
|
+
import { Box, Link, Flex, Typography } from '@strapi/design-system';
|
|
3
3
|
|
|
4
4
|
const EntityLinkWrapper = styled(Typography)`
|
|
5
5
|
${({ _theme }) => css`
|
|
@@ -31,12 +31,29 @@ const CustomOption = styled(Box)`
|
|
|
31
31
|
gap: 8px;
|
|
32
32
|
`;
|
|
33
33
|
|
|
34
|
+
const CustomOptionSubTitle = styled(Box)`
|
|
35
|
+
${({ theme, disabled }) => css`
|
|
36
|
+
font-size: ${theme.fontSizes[1]};
|
|
37
|
+
opacity: 0.5;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
text-overflow: ellipsis;
|
|
41
|
+
width: calc(100%);
|
|
42
|
+
`}
|
|
43
|
+
`;
|
|
44
|
+
const CustomOptionItemWrapper = styled(Flex)`
|
|
45
|
+
> ${CustomOptionSubTitle} {
|
|
46
|
+
margin-top: -2px;
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
|
|
34
50
|
const CustomOptionStatus = styled(Box)`
|
|
35
51
|
background: ${({ theme, publicationState }) =>
|
|
36
52
|
publicationState === 'published' ? theme.colors.success600 : theme.colors.secondary600};
|
|
37
53
|
width: 6px;
|
|
38
54
|
height: 6px;
|
|
39
55
|
border-radius: 100px;
|
|
56
|
+
flex-shrink: 0;
|
|
40
57
|
`;
|
|
41
58
|
|
|
42
59
|
const FieldWrapper = styled(Box)`
|
|
@@ -73,5 +90,7 @@ export default {
|
|
|
73
90
|
EntityLink,
|
|
74
91
|
CustomOptionStatus,
|
|
75
92
|
CustomOption,
|
|
93
|
+
CustomOptionSubTitle,
|
|
94
|
+
CustomOptionItemWrapper,
|
|
76
95
|
LinkToPage
|
|
77
96
|
};
|