@webbio/strapi-plugin-page-builder 0.12.8-platform → 0.13.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 CHANGED
@@ -137,7 +137,11 @@ 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
141
145
  }
142
146
  },
143
147
  "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,5 +1,6 @@
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';
@@ -17,6 +18,7 @@ export type SearchFilteredEntitiesResult = {
17
18
  href: string;
18
19
  publicationState?: string | false;
19
20
  publishedAt?: string;
21
+ subTitle?: string;
20
22
  }[];
21
23
  };
22
24
 
@@ -29,6 +31,9 @@ type SearchFilteredEntitiesQueryParams = {
29
31
  platformTitle?: string;
30
32
  notIds?: number[];
31
33
  customFilters?: Record<string, any>[];
34
+ searchableFields?: string[];
35
+ subTitlePath?: string;
36
+ mainFieldName?: string;
32
37
  };
33
38
 
34
39
  const QUERY_KEY = 'filteredEntities';
@@ -41,22 +46,30 @@ export const getSearchFilteredEntities = async ({
41
46
  searchQuery,
42
47
  platformTitle,
43
48
  notIds,
44
- customFilters
49
+ customFilters,
50
+ searchableFields = ['title'],
51
+ subTitlePath,
52
+ mainFieldName = 'title'
45
53
  }: SearchFilteredEntitiesQueryParams): Promise<SearchFilteredEntitiesResult> => {
46
54
  try {
47
55
  const { get } = fetchClient;
48
56
  const notIdFilters = notIds && notIds.length > 0 ? notIds.map((id) => ({ id: { $ne: id } })) : [];
49
57
  const customFilterObject = Array.isArray(customFilters) ? customFilters : [];
50
58
 
59
+ const fieldFilters = searchableFields.map((field) => ({ [field]: { $containsi: searchQuery } }));
60
+
51
61
  const filters = qs.stringify({
52
62
  page,
53
63
  pageSize: 20,
54
64
  locale,
55
- sort: searchQuery ? 'title:ASC' : undefined,
56
- _q: searchQuery || undefined,
65
+ // _q is a fuzzy search with sometimes unexpected results
66
+ // _q: searchQuery || undefined,
57
67
  filters: {
58
68
  $and: [
59
- { platform: { title: { $contains: platformTitle || undefined } } },
69
+ { platform: { title: { $eq: platformTitle || undefined } } },
70
+ {
71
+ $or: fieldFilters
72
+ },
60
73
  ...notIdFilters,
61
74
  ...customFilterObject
62
75
  ]
@@ -74,12 +87,15 @@ export const getSearchFilteredEntities = async ({
74
87
  return false;
75
88
  };
76
89
 
90
+ const subTitle = subTitlePath ? objGet(result, subTitlePath) : undefined;
91
+
77
92
  return {
78
93
  id: result.id,
79
- title: result.title,
94
+ title: result?.[mainFieldName],
80
95
  publicationState: getPublicationState(),
81
96
  publishedAt: result?.publishedAt,
82
- href: `/content-manager/collectionType/${uid}/${result.id}`
97
+ href: `/content-manager/collectionType/${uid}/${result.id}`,
98
+ subTitle: typeof subTitle === 'string' || typeof subTitle === 'number' ? String(subTitle) : ''
83
99
  };
84
100
  }
85
101
  );
@@ -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
- const showCreatePageButton = isUserCreatedContentType && !isCreatingEntry && !linkedPage && !isLoadingPlatform;
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
- {showCreatePageButton && selectedPlatform && (
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
- <Link />
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() as any;
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
- page: 1,
55
- filters: removedFilters
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
- page: 1,
64
- filters
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,6 @@ 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 { Platform } from '../../../api/platform';
18
17
 
19
18
  const PAGE = 1;
20
19
 
@@ -25,8 +24,6 @@ export interface IMultiPlatformFilteredSelectFieldProps extends IPlatformFiltere
25
24
  isCloningEntry?: boolean;
26
25
  totalRelations: number;
27
26
  relationsFromModifiedData?: Record<string, any>[];
28
- selectedPlatform?: Platform;
29
- hiddenId?: number[];
30
27
  }
31
28
 
32
29
  const MultiPlatformFilteredSelectField = ({
@@ -43,7 +40,8 @@ const MultiPlatformFilteredSelectField = ({
43
40
  totalRelations,
44
41
  relationsFromModifiedData,
45
42
  selectedPlatform,
46
- hiddenId
43
+ hiddenId,
44
+ disabled
47
45
  }: IMultiPlatformFilteredSelectFieldProps) => {
48
46
  const fetchClient = useFetchClient();
49
47
  const {
@@ -73,7 +71,7 @@ const MultiPlatformFilteredSelectField = ({
73
71
 
74
72
  const { formatMessage } = useIntl();
75
73
 
76
- const { targetAttributes, targetFieldValue, targetField } = RelationHelper.getTargetAttributes(
74
+ const { targetAttributes, targetFieldValue, targetField, relationMainFieldName } = RelationHelper.getTargetAttributes(
77
75
  name,
78
76
  attribute,
79
77
  modifiedData,
@@ -102,7 +100,10 @@ const MultiPlatformFilteredSelectField = ({
102
100
  searchQuery: inputValue,
103
101
  platformTitle: attribute?.pluginOptions?.filteredSelect?.disablePlatformFilter ? '' : selectedPlatform?.title,
104
102
  notIds: [...(selectedResults?.data || []).map((x: Record<string, any>) => x.id), ...(hiddenId || [])],
105
- customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters
103
+ customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters,
104
+ searchableFields: attribute?.pluginOptions?.filteredSelect?.searchableFields,
105
+ subTitlePath: attribute?.pluginOptions?.filteredSelect?.subTitlePath,
106
+ mainFieldName: relationMainFieldName
106
107
  });
107
108
 
108
109
  const mapped = entities?.results.map((x) => ({
@@ -110,7 +111,8 @@ const MultiPlatformFilteredSelectField = ({
110
111
  mainField: x.title,
111
112
  href: x?.href,
112
113
  publicationState: x.publicationState,
113
- publishedAt: x.publishedAt
114
+ publishedAt: x.publishedAt,
115
+ subTitle: x.subTitle
114
116
  }));
115
117
 
116
118
  // @ts-expect-error data is fine
@@ -202,7 +204,7 @@ const MultiPlatformFilteredSelectField = ({
202
204
  hint={hint || ''}
203
205
  labelAction={labelAction}
204
206
  required={required}
205
- disabled={!selectedPlatform}
207
+ disabled={!selectedPlatform || disabled}
206
208
  />
207
209
  );
208
210
  };
@@ -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,14 @@ 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 { Platform } from '../../../api/platform';
18
18
 
19
- export interface ISinglePlatformFilteredSelectFieldProps extends IPlatformFilteredSelectFieldProps {
20
- selectedPlatform?: Platform;
21
- hiddenId?: number[];
22
- }
19
+ export interface ISinglePlatformFilteredSelectFieldProps extends IPlatformFilteredSelectFieldProps {}
23
20
 
24
21
  interface CustomReactSelectValue extends Omit<IReactSelectValue, 'initialSelected'> {
25
22
  href?: string;
26
23
  publicationState?: string | false;
27
24
  publishedAt?: string;
25
+ subTitle?: string;
28
26
  }
29
27
 
30
28
  const SEARCH_DEBOUNCE_MS = 150;
@@ -38,7 +36,8 @@ const SinglePlatformFilteredSelectField = ({
38
36
  intlLabel,
39
37
  name,
40
38
  selectedPlatform,
41
- hiddenId
39
+ hiddenId,
40
+ disabled
42
41
  }: ISinglePlatformFilteredSelectFieldProps) => {
43
42
  const fetchClient = useFetchClient();
44
43
  const { onChange, initialData, modifiedData, isCreatingEntry, layout, allLayoutData } =
@@ -53,7 +52,7 @@ const SinglePlatformFilteredSelectField = ({
53
52
 
54
53
  const { formatMessage } = useIntl();
55
54
 
56
- const { targetAttributes, targetFieldValue, targetField } = RelationHelper.getTargetAttributes(
55
+ const { targetAttributes, targetFieldValue, targetField, relationMainFieldName } = RelationHelper.getTargetAttributes(
57
56
  name,
58
57
  attribute,
59
58
  modifiedData,
@@ -70,7 +69,10 @@ const SinglePlatformFilteredSelectField = ({
70
69
  : '';
71
70
 
72
71
  useEffect(() => {
73
- const initialSelect = getInitialSelectItem(targetFieldValue?.[0]);
72
+ const initialSelect = getInitialSelectItem(
73
+ targetFieldValue?.[0],
74
+ attribute?.pluginOptions?.filteredSelect?.subTitlePath
75
+ );
74
76
 
75
77
  setSelected(initialSelect);
76
78
  }, [targetFieldValue]);
@@ -116,7 +118,10 @@ const SinglePlatformFilteredSelectField = ({
116
118
  searchQuery: inputValue,
117
119
  platformTitle: attribute?.pluginOptions?.filteredSelect?.disablePlatformFilter ? '' : platformTitle,
118
120
  customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters,
119
- notIds: hiddenId
121
+ notIds: hiddenId,
122
+ searchableFields: attribute?.pluginOptions?.filteredSelect?.searchableFields,
123
+ subTitlePath: attribute?.pluginOptions?.filteredSelect?.subTitlePath,
124
+ mainFieldName: relationMainFieldName
120
125
  });
121
126
 
122
127
  return pages?.results.map((x) => ({
@@ -124,7 +129,8 @@ const SinglePlatformFilteredSelectField = ({
124
129
  label: x.title,
125
130
  href: x?.href,
126
131
  publicationState: x.publicationState,
127
- publishedAt: x.publishedAt
132
+ publishedAt: x.publishedAt,
133
+ subTitle: x.subTitle
128
134
  }));
129
135
  };
130
136
 
@@ -153,9 +159,9 @@ const SinglePlatformFilteredSelectField = ({
153
159
  onChange={handleChange}
154
160
  value={selected}
155
161
  defaultOptions
156
- hideSelectedOptions
162
+ // hideSelectedOptions
157
163
  labelAction={labelAction}
158
- isDisabled={!selectedPlatform}
164
+ isDisabled={!selectedPlatform || disabled}
159
165
  afterInput={
160
166
  <S.LinkToPage
161
167
  title={formatMessage({ id: getTrad('platformFilteredSelect.linkToEntity.label') })}
@@ -172,25 +178,33 @@ const SinglePlatformFilteredSelectField = ({
172
178
  );
173
179
  };
174
180
 
175
- const CustomOption = (props: OptionProps<CustomReactSelectValue, false>) => {
181
+ export const CustomOption = (props: OptionProps<CustomReactSelectValue, false>) => {
176
182
  return (
177
183
  <components.Option {...props}>
178
184
  <S.CustomOption>
179
185
  {props.data?.publicationState && <S.CustomOptionStatus publicationState={props.data?.publicationState} />}
180
- {props.children}
186
+
187
+ <Flex direction="column" alignItems="start" gap={1}>
188
+ {props.children}
189
+ {props.data?.subTitle && <S.CustomOptionSubTitle>{props.data?.subTitle}</S.CustomOptionSubTitle>}
190
+ </Flex>
181
191
  </S.CustomOption>
182
192
  </components.Option>
183
193
  );
184
194
  };
185
195
 
186
- const getInitialSelectItem = (initialValue?: Record<string, any>): SingleValue<CustomReactSelectValue | null> =>
196
+ const getInitialSelectItem = (
197
+ initialValue?: Record<string, any>,
198
+ subTitlePath?: string
199
+ ): SingleValue<CustomReactSelectValue | null> =>
187
200
  initialValue?.id
188
201
  ? {
189
202
  value: String(initialValue?.id),
190
203
  label: initialValue?.title ?? '',
191
204
  href: initialValue?.href,
192
205
  publicationState: initialValue.publicationState,
193
- publishedAt: initialValue.publishedAt
206
+ publishedAt: initialValue.publishedAt,
207
+ subTitle: subTitlePath ? objGet(initialValue, subTitlePath) : ''
194
208
  }
195
209
  : null;
196
210
 
@@ -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
  };
@@ -1,6 +1,7 @@
1
1
  import { IntlFormatters, MessageDescriptor } from '@formatjs/intl';
2
2
  import get from 'lodash/get';
3
3
  import { pointPathToGetPath } from '../../../utils/getObjectFromFormName';
4
+ import { Platform } from '../../../api/platform';
4
5
 
5
6
  export interface GetTargetAttributesResult {
6
7
  targetAttributes?: {
@@ -28,6 +29,8 @@ export interface IPlatformFilteredSelectFieldProps {
28
29
  customFilters?: Record<string, any>[];
29
30
  disablePlatformFilter?: boolean;
30
31
  hideSameEntity?: boolean;
32
+ searchableFields?: string[];
33
+ subTitlePath?: string;
31
34
  };
32
35
  };
33
36
  required?: boolean;
@@ -41,6 +44,8 @@ export interface IPlatformFilteredSelectFieldProps {
41
44
  value?: string;
42
45
  contentTypeUID?: string;
43
46
  placeholder?: MessageDescriptor & Parameters<IntlFormatters['formatMessage']>;
47
+ selectedPlatform?: Platform;
48
+ hiddenId?: number[];
44
49
  }
45
50
 
46
51
  const RelationHelper = {
@@ -54,7 +59,6 @@ const RelationHelper = {
54
59
  const lastFieldName = fieldName?.split('.')?.[fieldName?.split('.')?.length - 1];
55
60
  const targetField = attribute?.pluginOptions?.filteredSelect?.targetField || fieldName || '';
56
61
  const targetFieldName = (fieldName || '')?.replace(lastFieldName || '', targetField);
57
-
58
62
  const component = getComponent(targetFieldName, modifiedData, allLayoutData);
59
63
  const result: GetTargetAttributesResult = {
60
64
  targetAttributes: undefined,
@@ -32,6 +32,7 @@ import { getTranslation } from '../../utils/translations';
32
32
  import type { NormalizedRelation } from './utils/normalizeRelations';
33
33
  import type { Contracts } from '../../../../../../content-manager/shared';
34
34
  import type { Entity } from '@strapi/types';
35
+ import S from '../../../../../../../PlatformFilteredSelectField/styles';
35
36
 
36
37
  const RELATION_ITEM_HEIGHT = 50;
37
38
  const RELATION_GUTTER = 4;
@@ -81,6 +82,7 @@ interface RelationInputProps
81
82
  hasNextPage?: boolean;
82
83
  };
83
84
  size: number;
85
+ mainField?: string;
84
86
  }
85
87
 
86
88
  const RelationInput = ({
@@ -114,6 +116,7 @@ const RelationInput = ({
114
116
  required,
115
117
  relations: paginatedRelations,
116
118
  searchResults,
119
+ mainField,
117
120
  size
118
121
  }: RelationInputProps) => {
119
122
  const [textValue, setTextValue] = React.useState<string | undefined>('');
@@ -265,9 +268,9 @@ const RelationInput = ({
265
268
  onSearch(event.currentTarget.value);
266
269
  }}
267
270
  >
268
- {options.map((opt) => {
269
- return <Option key={opt.id} {...opt} />;
270
- })}
271
+ {options.map((opt) => (
272
+ <Option key={opt.id} {...opt} />
273
+ ))}
271
274
  </Combobox>
272
275
  </ComboboxWrapper>
273
276
 
@@ -309,7 +312,8 @@ const RelationInput = ({
309
312
  onRelationDisconnect,
310
313
  publicationStateTranslations,
311
314
  relations,
312
- updatePositionOfRelation: handleUpdatePositionOfRelation
315
+ updatePositionOfRelation: handleUpdatePositionOfRelation,
316
+ subTitle: 'ho'
313
317
  }}
314
318
  itemKey={(index) => `${relations[index].mainField}_${relations[index].id}`}
315
319
  innerElementType="ol"
@@ -366,8 +370,9 @@ const ShadowBox = styled(Box)<{ overflowDirection?: 'top-bottom' | 'top' | 'bott
366
370
  const Option = ({
367
371
  publicationState,
368
372
  mainField,
369
- id
370
- }: Pick<NormalizedRelation, 'id' | 'mainField' | 'publicationState'>) => {
373
+ id,
374
+ subTitle
375
+ }: Pick<NormalizedRelation, 'id' | 'mainField' | 'publicationState'> & { subTitle?: string }) => {
371
376
  const { formatMessage } = useIntl();
372
377
  const stringifiedDisplayValue = (mainField ?? id).toString();
373
378
 
@@ -384,18 +389,32 @@ const Option = ({
384
389
  const title = isDraft ? formatMessage(draftMessage) : formatMessage(publishedMessage);
385
390
 
386
391
  return (
387
- <ComboboxOption value={id.toString()} textValue={stringifiedDisplayValue}>
392
+ <ComboboxOption
393
+ value={id.toString()}
394
+ textValue={stringifiedDisplayValue}
395
+ style={{ paddingTop: 5, paddingBottom: 5 }}
396
+ >
388
397
  <Flex>
389
398
  <StyledBullet title={title} isDraft={isDraft} />
390
- <Typography ellipsis>{stringifiedDisplayValue}</Typography>
399
+ <S.CustomOptionItemWrapper direction="column" alignItems="start">
400
+ <Typography ellipsis>{stringifiedDisplayValue}</Typography>
401
+ {subTitle && <S.CustomOptionSubTitle>{subTitle}</S.CustomOptionSubTitle>}
402
+ </S.CustomOptionItemWrapper>
391
403
  </Flex>
392
404
  </ComboboxOption>
393
405
  );
394
406
  }
395
407
 
396
408
  return (
397
- <ComboboxOption value={id.toString()} textValue={stringifiedDisplayValue}>
398
- {stringifiedDisplayValue}
409
+ <ComboboxOption
410
+ value={id.toString()}
411
+ textValue={stringifiedDisplayValue}
412
+ style={{ paddingTop: 5, paddingBottom: 5 }}
413
+ >
414
+ <S.CustomOptionItemWrapper direction="column" alignItems="start" gap={0}>
415
+ {stringifiedDisplayValue}
416
+ {subTitle && <S.CustomOptionSubTitle>{subTitle}</S.CustomOptionSubTitle>}
417
+ </S.CustomOptionItemWrapper>
399
418
  </ComboboxOption>
400
419
  );
401
420
  };
@@ -433,6 +452,7 @@ interface ListItemProps extends Pick<RelationItemProps, 'index' | 'style'> {
433
452
  published: string;
434
453
  };
435
454
  relations: NormalizedRelation[];
455
+ subTitle?: string;
436
456
  };
437
457
  }
438
458
 
@@ -487,14 +507,20 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
487
507
  }}
488
508
  updatePositionOfRelation={updatePositionOfRelation}
489
509
  >
490
- <Box minWidth={0} paddingTop={1} paddingBottom={1} paddingRight={4}>
510
+ <Box minWidth={0} paddingRight={4}>
491
511
  <Tooltip description={mainField ?? `${id}`}>
492
512
  {href ? (
493
- <LinkEllipsis to={href}>{mainField ?? id}</LinkEllipsis>
513
+ <Flex direction="column" alignItems="start" gap={0}>
514
+ <LinkEllipsis to={href}>{mainField ?? id}</LinkEllipsis>
515
+ {data?.subTitle && <S.CustomOptionSubTitle>{data.subTitle}</S.CustomOptionSubTitle>}
516
+ </Flex>
494
517
  ) : (
495
- <Typography textColor={disabled ? 'neutral600' : 'primary600'} ellipsis>
496
- {mainField ?? id}
497
- </Typography>
518
+ <Flex direction="column" alignItems="start" gap={0}>
519
+ <Typography textColor={disabled ? 'neutral600' : 'primary600'} ellipsis>
520
+ {mainField ?? id}
521
+ </Typography>
522
+ {data?.subTitle && <S.CustomOptionSubTitle>{data.subTitle}</S.CustomOptionSubTitle>}
523
+ </Flex>
498
524
  )}
499
525
  </Tooltip>
500
526
  </Box>