@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
|
@@ -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
|
+
};
|
|
@@ -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,13 @@ export interface IPlatformFilteredSelectFieldProps {
|
|
|
28
29
|
customFilters?: Record<string, any>[];
|
|
29
30
|
disablePlatformFilter?: boolean;
|
|
30
31
|
hideSameEntity?: boolean;
|
|
32
|
+
searchableFields?: string[];
|
|
33
|
+
subTitlePath?: string;
|
|
34
|
+
conditionalFilters?: {
|
|
35
|
+
targetField?: string;
|
|
36
|
+
targetFieldKey?: string;
|
|
37
|
+
filter?: Record<string, any>;
|
|
38
|
+
}[];
|
|
31
39
|
};
|
|
32
40
|
};
|
|
33
41
|
required?: boolean;
|
|
@@ -41,20 +49,31 @@ export interface IPlatformFilteredSelectFieldProps {
|
|
|
41
49
|
value?: string;
|
|
42
50
|
contentTypeUID?: string;
|
|
43
51
|
placeholder?: MessageDescriptor & Parameters<IntlFormatters['formatMessage']>;
|
|
52
|
+
selectedPlatform?: Platform;
|
|
53
|
+
hiddenId?: number[];
|
|
54
|
+
}
|
|
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;
|
|
44
63
|
}
|
|
45
64
|
|
|
46
65
|
const RelationHelper = {
|
|
47
|
-
getTargetAttributes: (
|
|
48
|
-
fieldName
|
|
49
|
-
attribute
|
|
50
|
-
modifiedData
|
|
51
|
-
layout
|
|
52
|
-
allLayoutData
|
|
53
|
-
|
|
66
|
+
getTargetAttributes: ({
|
|
67
|
+
fieldName = '',
|
|
68
|
+
attribute,
|
|
69
|
+
modifiedData,
|
|
70
|
+
layout,
|
|
71
|
+
allLayoutData,
|
|
72
|
+
customTargetField
|
|
73
|
+
}: IRelationHelperProps) => {
|
|
54
74
|
const lastFieldName = fieldName?.split('.')?.[fieldName?.split('.')?.length - 1];
|
|
55
|
-
const targetField = attribute?.pluginOptions?.filteredSelect?.targetField || fieldName || '';
|
|
75
|
+
const targetField = customTargetField || attribute?.pluginOptions?.filteredSelect?.targetField || fieldName || '';
|
|
56
76
|
const targetFieldName = (fieldName || '')?.replace(lastFieldName || '', targetField);
|
|
57
|
-
|
|
58
77
|
const component = getComponent(targetFieldName, modifiedData, allLayoutData);
|
|
59
78
|
const result: GetTargetAttributesResult = {
|
|
60
79
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
<
|
|
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
|
|
398
|
-
{
|
|
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}
|
|
510
|
+
<Box minWidth={0} paddingRight={4}>
|
|
491
511
|
<Tooltip description={mainField ?? `${id}`}>
|
|
492
512
|
{href ? (
|
|
493
|
-
<
|
|
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
|
-
<
|
|
496
|
-
{
|
|
497
|
-
|
|
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>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { parse, stringify } from 'qs';
|
|
2
|
+
import { useMemo, useCallback } from 'react';
|
|
3
|
+
import { useLocation, useHistory } from 'react-router-dom';
|
|
4
|
+
|
|
5
|
+
interface IUseQueryParamsObj {
|
|
6
|
+
query: Record<string, any>;
|
|
7
|
+
rawQuery: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type ISetQuery = (nextParams: Record<string, any>, method?: string, routerMethod?: string) => void;
|
|
11
|
+
|
|
12
|
+
// We created this as a copy of the useQueryParams hook from the Strapi plugin
|
|
13
|
+
// This one however supports the replace and push methods from the useHistory hook
|
|
14
|
+
const useQueryParams = (initialParams?: Record<string, any>): [IUseQueryParamsObj, ISetQuery] => {
|
|
15
|
+
const { search } = useLocation();
|
|
16
|
+
const { replace, push } = useHistory();
|
|
17
|
+
|
|
18
|
+
const query = useMemo(() => {
|
|
19
|
+
const searchQuery = search.substring(1);
|
|
20
|
+
if (!search) {
|
|
21
|
+
return initialParams || {};
|
|
22
|
+
}
|
|
23
|
+
return parse(searchQuery);
|
|
24
|
+
}, [search, initialParams]);
|
|
25
|
+
|
|
26
|
+
const setQuery = useCallback(
|
|
27
|
+
(nextParams: Record<string, any>, method = 'push', routerMethod = 'push') => {
|
|
28
|
+
let nextQuery = { ...query };
|
|
29
|
+
if (method === 'remove') {
|
|
30
|
+
Object.keys(nextParams).forEach((key) => {
|
|
31
|
+
if (Object.prototype.hasOwnProperty.call(nextQuery, key)) {
|
|
32
|
+
delete nextQuery[key];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
nextQuery = { ...query, ...nextParams };
|
|
37
|
+
}
|
|
38
|
+
const props = { search: stringify(nextQuery, { encode: false }) };
|
|
39
|
+
|
|
40
|
+
if (routerMethod === 'replace') {
|
|
41
|
+
replace(props);
|
|
42
|
+
} else {
|
|
43
|
+
push(props);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
[push, replace, query]
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return [{ query, rawQuery: search }, setQuery];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { useQueryParams };
|
package/dist/package.json
CHANGED
|
@@ -20,7 +20,7 @@ exports.default = async ({ strapi }) => {
|
|
|
20
20
|
displayName,
|
|
21
21
|
category: 'Platform',
|
|
22
22
|
handler: async (x) => {
|
|
23
|
-
var _a, _b, _c
|
|
23
|
+
var _a, _b, _c;
|
|
24
24
|
if (((_a = x === null || x === void 0 ? void 0 : x.permission) === null || _a === void 0 ? void 0 : _a.subject) === 'api::platform.platform') {
|
|
25
25
|
return {
|
|
26
26
|
id: {
|
|
@@ -34,25 +34,28 @@ exports.default = async ({ strapi }) => {
|
|
|
34
34
|
limit: -1,
|
|
35
35
|
populate: '*'
|
|
36
36
|
})));
|
|
37
|
-
// checks which
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
// checks which roles the user has
|
|
38
|
+
const foundRoles = roles.filter((role) => x.roles.find((userRole) => userRole.name === role.name));
|
|
39
|
+
// Get all permissions from the roles the user has
|
|
40
|
+
const allPermissions = [foundRoles === null || foundRoles === void 0 ? void 0 : foundRoles[0]]
|
|
41
|
+
.map((role) => role === null || role === void 0 ? void 0 : role.permissions)
|
|
42
|
+
.flat()
|
|
43
|
+
.filter(Boolean);
|
|
41
44
|
// get the right platform permissions, and filters out the platform
|
|
42
45
|
// this is neccesary because of multiple platforms. if you can see Vacancy from platform 1 and collegue from platform 2
|
|
43
46
|
// it will show both at page level, so this filters out the wrong page
|
|
44
|
-
const platformPermission =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return permission.permission;
|
|
47
|
+
const platformPermission = allPermissions.map((permission) => ({
|
|
48
|
+
subject: permission.subject,
|
|
49
|
+
conditions: permission === null || permission === void 0 ? void 0 : permission.conditions.filter((condition) => condition.includes(platform.title))
|
|
50
|
+
}));
|
|
51
|
+
// Get the right permission for platform
|
|
52
|
+
const permissions = platformPermission
|
|
53
|
+
.map((permission) => {
|
|
54
|
+
if (permission.conditions.length > 0) {
|
|
55
|
+
return permission.subject;
|
|
54
56
|
}
|
|
55
|
-
})
|
|
57
|
+
})
|
|
58
|
+
.filter(Boolean);
|
|
56
59
|
const uniquePermissions = (0, uniq_1.default)(permissions);
|
|
57
60
|
return {
|
|
58
61
|
$and: [
|