@webbio/strapi-plugin-page-builder 0.13.0-platform → 0.14.1-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
@@ -134,14 +134,23 @@ Ik wil een lijst van vacature relaties selecteren. Deze vacatures moeten van het
134
134
  "targetField": "vacatures",
135
135
  // (Default: undefined) Adds filters to the $and query for result filtering
136
136
  "customFilters": [{ "title": { "$contains": "Hoi" } }],
137
- // (Default: true). Disables result filtering by globally selected platform
137
+ // (Default: false). 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
140
  "hideSameEntity": boolean,
141
141
  // (Default: ['title']) Defines searchable fields
142
142
  "searchableFields": string[],
143
- // If set the field will show a subtitle with the value that results in following this path.
144
- "subTitlePath": string
143
+ // (Default: undefined) If set the field will show a subtitle with the value that results in following this path.
144
+ "subTitlePath": string,
145
+ // (Default: undefined)
146
+ // Conditional filters add the posibility to who results based on values from other fields.
147
+ // For now this only works for fields on the same level as the targetfield.
148
+ // The value found will be replacing the '${value}' string.
149
+ "conditionalFilters": {
150
+ "targetField": string,
151
+ "targetFieldKey": string,
152
+ "filter": [{ "title": { "$contains": "${value}" } }]
153
+ }[];
145
154
  }
146
155
  },
147
156
  "type": "customField",
@@ -4,6 +4,7 @@ import objGet from 'lodash/get';
4
4
 
5
5
  import { useFetchClient } from '@strapi/helper-plugin';
6
6
  import qs from 'qs';
7
+ import { getConditionalFilters } from '../components/PlatformFilteredSelectField/utils/get-condition-filters';
7
8
 
8
9
  export type SearchFilteredEntitiesResult = {
9
10
  pagination: {
@@ -34,6 +35,7 @@ type SearchFilteredEntitiesQueryParams = {
34
35
  searchableFields?: string[];
35
36
  subTitlePath?: string;
36
37
  mainFieldName?: string;
38
+ conditionalFilters?: Record<string, any>[];
37
39
  };
38
40
 
39
41
  const QUERY_KEY = 'filteredEntities';
@@ -49,7 +51,8 @@ export const getSearchFilteredEntities = async ({
49
51
  customFilters,
50
52
  searchableFields = ['title'],
51
53
  subTitlePath,
52
- mainFieldName = 'title'
54
+ mainFieldName = 'title',
55
+ conditionalFilters = []
53
56
  }: SearchFilteredEntitiesQueryParams): Promise<SearchFilteredEntitiesResult> => {
54
57
  try {
55
58
  const { get } = fetchClient;
@@ -71,7 +74,8 @@ export const getSearchFilteredEntities = async ({
71
74
  $or: fieldFilters
72
75
  },
73
76
  ...notIdFilters,
74
- ...customFilterObject
77
+ ...customFilterObject,
78
+ ...conditionalFilters
75
79
  ]
76
80
  }
77
81
  });
@@ -14,6 +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 { getConditionalFilters } from '../utils/get-condition-filters';
17
18
 
18
19
  const PAGE = 1;
19
20
 
@@ -72,11 +73,7 @@ const MultiPlatformFilteredSelectField = ({
72
73
  const { formatMessage } = useIntl();
73
74
 
74
75
  const { targetAttributes, targetFieldValue, targetField, relationMainFieldName } = RelationHelper.getTargetAttributes(
75
- name,
76
- attribute,
77
- modifiedData,
78
- layout,
79
- allLayoutData
76
+ { fieldName: name, attribute, modifiedData, layout, allLayoutData }
80
77
  );
81
78
 
82
79
  const label = intlLabel?.id
@@ -92,6 +89,14 @@ const MultiPlatformFilteredSelectField = ({
92
89
  }, [targetFieldValue]);
93
90
 
94
91
  const getItems = async (inputValue?: string) => {
92
+ const conditionalFilters = getConditionalFilters({
93
+ fieldName: name,
94
+ allLayoutData,
95
+ attribute,
96
+ layout,
97
+ modifiedData
98
+ });
99
+
95
100
  const entities = await getSearchFilteredEntities({
96
101
  fetchClient,
97
102
  page: PAGE,
@@ -103,7 +108,8 @@ const MultiPlatformFilteredSelectField = ({
103
108
  customFilters: attribute?.pluginOptions?.filteredSelect?.customFilters,
104
109
  searchableFields: attribute?.pluginOptions?.filteredSelect?.searchableFields,
105
110
  subTitlePath: attribute?.pluginOptions?.filteredSelect?.subTitlePath,
106
- mainFieldName: relationMainFieldName
111
+ mainFieldName: relationMainFieldName,
112
+ conditionalFilters
107
113
  });
108
114
 
109
115
  const mapped = entities?.results.map((x) => ({
@@ -15,6 +15,7 @@ import { getSearchFilteredEntities } from '../../../api/search-filtered-entity';
15
15
  import S from './../styles';
16
16
  import getTrad from '../../../utils/getTrad';
17
17
  import RelationHelper, { IPlatformFilteredSelectFieldProps } from '../utils/relation-helper';
18
+ import { getConditionalFilters } from '../utils/get-condition-filters';
18
19
 
19
20
  export interface ISinglePlatformFilteredSelectFieldProps extends IPlatformFilteredSelectFieldProps {}
20
21
 
@@ -53,11 +54,7 @@ const SinglePlatformFilteredSelectField = ({
53
54
  const { formatMessage } = useIntl();
54
55
 
55
56
  const { targetAttributes, targetFieldValue, targetField, relationMainFieldName } = RelationHelper.getTargetAttributes(
56
- name,
57
- attribute,
58
- modifiedData,
59
- layout,
60
- allLayoutData
57
+ { fieldName: name, attribute, modifiedData, layout, allLayoutData }
61
58
  );
62
59
 
63
60
  const label = intlLabel?.id
@@ -110,6 +107,14 @@ const SinglePlatformFilteredSelectField = ({
110
107
  };
111
108
 
112
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
+
113
118
  const pages = await getSearchFilteredEntities({
114
119
  fetchClient,
115
120
  page: PAGE,
@@ -121,7 +126,8 @@ const SinglePlatformFilteredSelectField = ({
121
126
  notIds: hiddenId,
122
127
  searchableFields: attribute?.pluginOptions?.filteredSelect?.searchableFields,
123
128
  subTitlePath: attribute?.pluginOptions?.filteredSelect?.subTitlePath,
124
- mainFieldName: relationMainFieldName
129
+ mainFieldName: relationMainFieldName,
130
+ conditionalFilters
125
131
  });
126
132
 
127
133
  return pages?.results.map((x) => ({
@@ -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(name, attribute, modifiedData, layout, allLayoutData);
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
  );
@@ -34,7 +34,7 @@ const CustomOption = styled(Box)`
34
34
  const CustomOptionSubTitle = styled(Box)`
35
35
  ${({ theme, disabled }) => css`
36
36
  font-size: ${theme.fontSizes[1]};
37
- opacity: 0.5;
37
+ color: ${theme.colors.neutral400};
38
38
  white-space: nowrap;
39
39
  overflow: hidden;
40
40
  text-overflow: ellipsis;
@@ -0,0 +1,82 @@
1
+ import { isJSON } from '../../../utils/isJson';
2
+ import RelationHelper, { IRelationHelperProps } from './relation-helper';
3
+
4
+ interface IGetConditionalFiltersProps extends IRelationHelperProps {}
5
+
6
+ export const getConditionalFilters = ({
7
+ attribute,
8
+ modifiedData,
9
+ layout,
10
+ allLayoutData,
11
+ fieldName
12
+ }: IGetConditionalFiltersProps): Record<string, any>[] => {
13
+ const conditionalFilters = (attribute?.pluginOptions?.filteredSelect?.conditionalFilters || []).filter(
14
+ (x) => x.filter && x.targetField
15
+ );
16
+
17
+ const filters: Record<string, any>[] = [];
18
+
19
+ for (const { targetField, filter, targetFieldKey } of conditionalFilters) {
20
+ const completeFieldNamePath = (fieldName || '').split('.');
21
+ completeFieldNamePath.pop();
22
+ completeFieldNamePath.push(targetField || '');
23
+ const { targetFieldValue } = RelationHelper.getTargetAttributes({
24
+ fieldName,
25
+ attribute,
26
+ modifiedData,
27
+ layout,
28
+ allLayoutData,
29
+ customTargetField: targetField
30
+ });
31
+
32
+ const value = getTargetFieldValue(targetFieldValue, targetFieldKey);
33
+
34
+ // If the value is an array, we need to create an OR filter
35
+ if (Array.isArray(value)) {
36
+ const orFilters: { $or: Record<string, any>[] } = {
37
+ $or: []
38
+ };
39
+
40
+ for (const val of value) {
41
+ const filterReplacement = replaceObj(filter, val);
42
+ if (val && filterReplacement) {
43
+ orFilters.$or.push(filterReplacement);
44
+ }
45
+ }
46
+ filters.push(orFilters);
47
+ } else {
48
+ const filterReplacement = replaceObj(filter, value);
49
+
50
+ if (value) {
51
+ filters.push(filterReplacement);
52
+ }
53
+ }
54
+ }
55
+
56
+ return filters.filter(Boolean);
57
+ };
58
+
59
+ const getTargetFieldValue = (targetFieldValue?: any, targetFieldKey?: string): any => {
60
+ const key = targetFieldKey || 'id';
61
+
62
+ if (typeof targetFieldValue !== 'object' || !targetFieldValue) {
63
+ return targetFieldValue;
64
+ }
65
+
66
+ if (Array.isArray(targetFieldValue)) {
67
+ return targetFieldValue.map((x) => x?.[key]);
68
+ }
69
+
70
+ return targetFieldValue?.[key];
71
+ };
72
+
73
+ const replaceObj = (filter?: Record<string, any>, value?: string) => {
74
+ const stringFilter = JSON.stringify(filter || {}).replaceAll('${value}', value || '');
75
+ const json = isJSON(stringFilter);
76
+
77
+ if (!json) {
78
+ return undefined;
79
+ }
80
+
81
+ return JSON.parse(stringFilter);
82
+ };
@@ -31,6 +31,11 @@ export interface IPlatformFilteredSelectFieldProps {
31
31
  hideSameEntity?: boolean;
32
32
  searchableFields?: string[];
33
33
  subTitlePath?: string;
34
+ conditionalFilters?: {
35
+ targetField?: string;
36
+ targetFieldKey?: string;
37
+ filter?: Record<string, any>;
38
+ }[];
34
39
  };
35
40
  };
36
41
  required?: boolean;
@@ -48,16 +53,26 @@ export interface IPlatformFilteredSelectFieldProps {
48
53
  hiddenId?: number[];
49
54
  }
50
55
 
56
+ export interface IRelationHelperProps {
57
+ fieldName?: string;
58
+ attribute?: IPlatformFilteredSelectFieldProps['attribute'];
59
+ modifiedData?: Record<string, any>;
60
+ layout?: Record<string, any>;
61
+ allLayoutData?: Record<string, any>;
62
+ customTargetField?: string;
63
+ }
64
+
51
65
  const RelationHelper = {
52
- getTargetAttributes: (
53
- fieldName?: string,
54
- attribute?: IPlatformFilteredSelectFieldProps['attribute'],
55
- modifiedData?: Record<string, any>,
56
- layout?: Record<string, any>,
57
- allLayoutData?: Record<string, any>
58
- ) => {
66
+ getTargetAttributes: ({
67
+ fieldName = '',
68
+ attribute,
69
+ modifiedData,
70
+ layout,
71
+ allLayoutData,
72
+ customTargetField
73
+ }: IRelationHelperProps) => {
59
74
  const lastFieldName = fieldName?.split('.')?.[fieldName?.split('.')?.length - 1];
60
- const targetField = attribute?.pluginOptions?.filteredSelect?.targetField || fieldName || '';
75
+ const targetField = customTargetField || attribute?.pluginOptions?.filteredSelect?.targetField || fieldName || '';
61
76
  const targetFieldName = (fieldName || '')?.replace(lastFieldName || '', targetField);
62
77
  const component = getComponent(targetFieldName, modifiedData, allLayoutData);
63
78
  const result: GetTargetAttributesResult = {
@@ -312,8 +312,7 @@ const RelationInput = ({
312
312
  onRelationDisconnect,
313
313
  publicationStateTranslations,
314
314
  relations,
315
- updatePositionOfRelation: handleUpdatePositionOfRelation,
316
- subTitle: 'ho'
315
+ updatePositionOfRelation: handleUpdatePositionOfRelation
317
316
  }}
318
317
  itemKey={(index) => `${relations[index].mainField}_${relations[index].id}`}
319
318
  innerElementType="ol"
@@ -452,7 +451,6 @@ interface ListItemProps extends Pick<RelationItemProps, 'index' | 'style'> {
452
451
  published: string;
453
452
  };
454
453
  relations: NormalizedRelation[];
455
- subTitle?: string;
456
454
  };
457
455
  }
458
456
 
@@ -472,7 +470,7 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
472
470
  relations,
473
471
  updatePositionOfRelation
474
472
  } = data;
475
- const { publicationState, href, mainField, id } = relations[index];
473
+ const { publicationState, href, mainField, id, subTitle } = relations[index];
476
474
  const statusColor = publicationState === 'draft' ? 'secondary' : 'success';
477
475
 
478
476
  return (
@@ -512,14 +510,14 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
512
510
  {href ? (
513
511
  <Flex direction="column" alignItems="start" gap={0}>
514
512
  <LinkEllipsis to={href}>{mainField ?? id}</LinkEllipsis>
515
- {data?.subTitle && <S.CustomOptionSubTitle>{data.subTitle}</S.CustomOptionSubTitle>}
513
+ {subTitle && <S.CustomOptionSubTitle>{subTitle}</S.CustomOptionSubTitle>}
516
514
  </Flex>
517
515
  ) : (
518
516
  <Flex direction="column" alignItems="start" gap={0}>
519
517
  <Typography textColor={disabled ? 'neutral600' : 'primary600'} ellipsis>
520
518
  {mainField ?? id}
521
519
  </Typography>
522
- {data?.subTitle && <S.CustomOptionSubTitle>{data.subTitle}</S.CustomOptionSubTitle>}
520
+ {subTitle && <S.CustomOptionSubTitle>{subTitle}</S.CustomOptionSubTitle>}
523
521
  </Flex>
524
522
  )}
525
523
  </Tooltip>
@@ -15,6 +15,7 @@ export type NormalizedRelation = Contracts.Relations.RelationResult & {
15
15
  href?: string;
16
16
  mainField: string;
17
17
  publicationState?: false | 'published' | 'draft';
18
+ subTitle?: string;
18
19
  };
19
20
 
20
21
  export const normalizeRelation = (
@@ -0,0 +1,9 @@
1
+ export const isJSON = (value?: string) => {
2
+ if (!value) return false;
3
+
4
+ try {
5
+ return !!(JSON.parse(value) && value);
6
+ } catch (e) {
7
+ return false;
8
+ }
9
+ };
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webbio/strapi-plugin-page-builder",
3
- "version": "0.13.0-platform",
3
+ "version": "0.14.1-platform",
4
4
  "description": "This is the description of the plugin.",
5
5
  "scripts": {
6
6
  "develop": "tsc -p tsconfig.server.json -w",