feat: confine conditions inside list to the same local list item (#863)
This commit is contained in:
parent
82a8e11ab3
commit
5602812774
@ -569,6 +569,64 @@ collections:
|
||||
- label: File
|
||||
name: file
|
||||
widget: file
|
||||
- name: typed_list_with_condition
|
||||
label: Typed List With Condition
|
||||
widget: list
|
||||
types:
|
||||
- label: Type 1 Object
|
||||
name: type_1_object
|
||||
widget: object
|
||||
fields:
|
||||
- name: template
|
||||
label: template
|
||||
widget: select
|
||||
options:
|
||||
- column
|
||||
- row
|
||||
- banner
|
||||
default: column
|
||||
- label: String
|
||||
name: string
|
||||
widget: string
|
||||
- label: Boolean
|
||||
name: boolean
|
||||
widget: boolean
|
||||
condition:
|
||||
field: template
|
||||
value: banner
|
||||
- label: Text
|
||||
name: text
|
||||
widget: text
|
||||
- label: Type 2 Object
|
||||
name: type_2_object
|
||||
widget: object
|
||||
fields:
|
||||
- label: Number
|
||||
name: number
|
||||
widget: number
|
||||
- label: Select
|
||||
name: select
|
||||
widget: select
|
||||
options:
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
- label: Datetime
|
||||
name: datetime
|
||||
widget: datetime
|
||||
- label: Markdown
|
||||
name: markdown
|
||||
widget: markdown
|
||||
- label: Type 3 Object
|
||||
name: type_3_object
|
||||
widget: object
|
||||
fields:
|
||||
- label: Image
|
||||
name: image
|
||||
widget: image
|
||||
- label: File
|
||||
name: file
|
||||
widget: file
|
||||
- name: map
|
||||
label: Map
|
||||
file: _widgets/map.json
|
||||
|
@ -1045,7 +1045,7 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
|
||||
}
|
||||
|
||||
filterEntries(collection: { entries: Entry[] }, filterRule: FilterRule | FilterRule[]) {
|
||||
return filterEntries(collection.entries, filterRule);
|
||||
return filterEntries(collection.entries, filterRule, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ const EditorControl = ({
|
||||
t,
|
||||
value,
|
||||
forList = false,
|
||||
listItemPath,
|
||||
forSingleList = false,
|
||||
changeDraftField,
|
||||
i18n,
|
||||
@ -94,7 +95,7 @@ const EditorControl = ({
|
||||
() => isFieldHidden(field, locale, i18n?.defaultLocale),
|
||||
[field, i18n?.defaultLocale, locale],
|
||||
);
|
||||
const hidden = useHidden(field, entry);
|
||||
const hidden = useHidden(field, entry, listItemPath);
|
||||
|
||||
useEffect(() => {
|
||||
if (hidden) {
|
||||
@ -202,6 +203,7 @@ const EditorControl = ({
|
||||
t,
|
||||
value: finalValue,
|
||||
forList,
|
||||
listItemPath,
|
||||
forSingleList,
|
||||
i18n,
|
||||
hasErrors,
|
||||
@ -231,6 +233,7 @@ const EditorControl = ({
|
||||
query,
|
||||
finalValue,
|
||||
forList,
|
||||
listItemPath,
|
||||
forSingleList,
|
||||
i18n,
|
||||
hasErrors,
|
||||
@ -248,6 +251,7 @@ interface EditorControlOwnProps {
|
||||
parentPath: string;
|
||||
value: ValueOrNestedValue;
|
||||
forList?: boolean;
|
||||
listItemPath?: string;
|
||||
forSingleList?: boolean;
|
||||
i18n: I18nSettings | undefined;
|
||||
fieldName?: string;
|
||||
|
@ -32,6 +32,7 @@ export interface EditorControlPaneProps {
|
||||
onLocaleChange?: (locale: string) => void;
|
||||
allowDefaultLocale?: boolean;
|
||||
context?: 'default' | 'i18nSplit';
|
||||
listItemPath?: string;
|
||||
}
|
||||
|
||||
const EditorControlPane = ({
|
||||
@ -47,6 +48,7 @@ const EditorControlPane = ({
|
||||
onLocaleChange,
|
||||
allowDefaultLocale = false,
|
||||
context = 'default',
|
||||
listItemPath,
|
||||
t,
|
||||
}: TranslatedProps<EditorControlPaneProps>) => {
|
||||
const pathField = useMemo(
|
||||
@ -138,6 +140,7 @@ const EditorControlPane = ({
|
||||
locale={locale}
|
||||
parentPath=""
|
||||
i18n={i18n}
|
||||
listItemPath={listItemPath}
|
||||
controlled
|
||||
isMeta
|
||||
/>
|
||||
@ -156,6 +159,7 @@ const EditorControlPane = ({
|
||||
locale={locale}
|
||||
parentPath=""
|
||||
i18n={i18n}
|
||||
listItemPath={listItemPath}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -311,6 +311,7 @@ export interface WidgetControlProps<T, F extends BaseField = UnknownField, EV =
|
||||
fieldsErrors: FieldsErrors;
|
||||
submitted: boolean;
|
||||
forList: boolean;
|
||||
listItemPath: string | undefined;
|
||||
forSingleList: boolean;
|
||||
disabled: boolean;
|
||||
duplicate: boolean;
|
||||
|
@ -71,30 +71,86 @@ describe('filterEntries', () => {
|
||||
|
||||
describe('isHidden', () => {
|
||||
it('should show field by default', () => {
|
||||
expect(isHidden(mockTitleField, mockExternalEntry)).toBeFalsy();
|
||||
expect(isHidden(mockTitleField, mockExternalEntry, undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide field if single condition is not met', () => {
|
||||
expect(isHidden(mockUrlField, mockInternalEntry)).toBeTruthy();
|
||||
expect(isHidden(mockUrlField, mockInternalEntry, undefined)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show field if single condition is met', () => {
|
||||
expect(isHidden(mockUrlField, mockExternalEntry)).toBeFalsy();
|
||||
expect(isHidden(mockUrlField, mockExternalEntry, undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide field if all multiple conditions are not met', () => {
|
||||
expect(isHidden(mockBodyField, mockExternalEntry)).toBeTruthy();
|
||||
expect(isHidden(mockBodyField, mockExternalEntry, undefined)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show field if single condition is met', () => {
|
||||
expect(isHidden(mockBodyField, mockHasSummaryEntry)).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, mockInternalEntry)).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, mockHasSummaryEntry, undefined)).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, mockInternalEntry, undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show field if entry is undefined', () => {
|
||||
expect(isHidden(mockTitleField, undefined)).toBeFalsy();
|
||||
expect(isHidden(mockUrlField, undefined)).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, undefined)).toBeFalsy();
|
||||
expect(isHidden(mockTitleField, undefined, undefined)).toBeFalsy();
|
||||
expect(isHidden(mockUrlField, undefined, undefined)).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, undefined, undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('inside list', () => {
|
||||
const mockInsideListEntry = createMockEntry({
|
||||
path: 'path/to/file-1.md',
|
||||
data: {
|
||||
list: [
|
||||
{
|
||||
title: 'I am a title',
|
||||
type: 'external',
|
||||
url: 'http://example.com',
|
||||
hasSummary: false,
|
||||
},
|
||||
{
|
||||
title: 'I am a title',
|
||||
type: 'internal',
|
||||
body: 'I am the body of your post',
|
||||
hasSummary: false,
|
||||
},
|
||||
{
|
||||
title: 'I am a title',
|
||||
type: 'external',
|
||||
url: 'http://example.com',
|
||||
body: 'I am the body of your post',
|
||||
hasSummary: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
it('should show field by default', () => {
|
||||
expect(isHidden(mockTitleField, mockInsideListEntry, 'list.0')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide field if single condition is not met', () => {
|
||||
expect(isHidden(mockUrlField, mockInsideListEntry, 'list.1')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show field if single condition is met', () => {
|
||||
expect(isHidden(mockUrlField, mockInsideListEntry, 'list.0')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide field if all multiple conditions are not met', () => {
|
||||
expect(isHidden(mockBodyField, mockInsideListEntry, 'list.0')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show field if single condition is met', () => {
|
||||
expect(isHidden(mockBodyField, mockInsideListEntry, 'list.2')).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, mockInsideListEntry, 'list.1')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show field if entry is undefined', () => {
|
||||
expect(isHidden(mockTitleField, undefined, 'list.0')).toBeFalsy();
|
||||
expect(isHidden(mockUrlField, undefined, 'list.0')).toBeFalsy();
|
||||
expect(isHidden(mockBodyField, undefined, 'list.0')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -87,35 +87,36 @@ describe('filterEntries', () => {
|
||||
|
||||
describe('field rules', () => {
|
||||
it('should filter fields', () => {
|
||||
expect(filterEntries(entries, { field: 'language', value: 'en' })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'language', value: 'en' }, undefined)).toEqual([
|
||||
mockEnglishEntry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'language', value: 'fr' })).toEqual([mockFrenchEntry]);
|
||||
expect(filterEntries(entries, { field: 'language', value: 'fr' }, undefined)).toEqual([
|
||||
mockFrenchEntry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'language', value: 'gr' })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'language', value: 'gr' }, undefined)).toEqual([
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'draft', value: true })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'draft', value: true }, undefined)).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields if multiple filter values are provided (must match only one)', () => {
|
||||
expect(filterEntries(entries, { field: 'language', value: ['en', 'fr'] })).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockFrenchEntry,
|
||||
]);
|
||||
expect(filterEntries(entries, { field: 'language', value: ['en', 'fr'] }, undefined)).toEqual(
|
||||
[mockEnglishEntry, mockFrenchEntry],
|
||||
);
|
||||
});
|
||||
|
||||
it('should filter fields based on pattern', () => {
|
||||
// Languages with an r in their name
|
||||
expect(filterEntries(entries, { field: 'language', pattern: 'r' })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'language', pattern: 'r' }, undefined)).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
@ -125,20 +126,22 @@ describe('filterEntries', () => {
|
||||
});
|
||||
|
||||
it('should filter fields if field value is an array (must include value)', () => {
|
||||
expect(filterEntries(entries, { field: 'tags', value: 'tag-4' })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'tags', value: 'tag-4' }, undefined)).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'numbers', value: 8 })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'numbers', value: 8 }, undefined)).toEqual([
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields if field value is an array and multiple filter values are provided (must include only one)', () => {
|
||||
expect(filterEntries(entries, { field: 'tags', value: ['tag-3', 'tag-4'] })).toEqual([
|
||||
expect(
|
||||
filterEntries(entries, { field: 'tags', value: ['tag-3', 'tag-4'] }, undefined),
|
||||
).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
@ -146,7 +149,7 @@ describe('filterEntries', () => {
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'numbers', value: ['5', '6'] })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'numbers', value: ['5', '6'] }, undefined)).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
@ -155,17 +158,21 @@ describe('filterEntries', () => {
|
||||
|
||||
it('should match all values if matchAll is one (value is an array, multiple filter values are provided)', () => {
|
||||
expect(
|
||||
filterEntries(entries, { field: 'tags', value: ['tag-1', 'tag-4'], matchAll: true }),
|
||||
filterEntries(
|
||||
entries,
|
||||
{ field: 'tags', value: ['tag-1', 'tag-4'], matchAll: true },
|
||||
undefined,
|
||||
),
|
||||
).toEqual([mockFrenchEntry, mockIndexEntry, mockTags1and4Entry]);
|
||||
|
||||
expect(
|
||||
filterEntries(entries, { field: 'numbers', value: ['5', '6'], matchAll: true }),
|
||||
filterEntries(entries, { field: 'numbers', value: ['5', '6'], matchAll: true }, undefined),
|
||||
).toEqual([mockFrenchEntry, mockIndexEntry]);
|
||||
});
|
||||
|
||||
it('should filter fields based on pattern when value is an array', () => {
|
||||
// Tags containing the word "fish"
|
||||
expect(filterEntries(entries, { field: 'tags', pattern: 'fish' })).toEqual([
|
||||
expect(filterEntries(entries, { field: 'tags', pattern: 'fish' }, undefined)).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
@ -173,10 +180,14 @@ describe('filterEntries', () => {
|
||||
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
expect(
|
||||
filterEntries(entries, [
|
||||
{ field: 'tags', value: ['tag-3', 'tag-4'] },
|
||||
{ field: 'language', value: 'gr' },
|
||||
]),
|
||||
filterEntries(
|
||||
entries,
|
||||
[
|
||||
{ field: 'tags', value: ['tag-3', 'tag-4'] },
|
||||
{ field: 'language', value: 'gr' },
|
||||
],
|
||||
undefined,
|
||||
),
|
||||
).toEqual([
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
@ -187,29 +198,35 @@ describe('filterEntries', () => {
|
||||
|
||||
it('should filter based on multiple rules (must match all rules) (matchAll on)', () => {
|
||||
expect(
|
||||
filterEntries(entries, [
|
||||
{ field: 'tags', value: ['tag-1', 'tag-4'], matchAll: true },
|
||||
{ field: 'language', value: 'gr' },
|
||||
]),
|
||||
filterEntries(
|
||||
entries,
|
||||
[
|
||||
{ field: 'tags', value: ['tag-1', 'tag-4'], matchAll: true },
|
||||
{ field: 'language', value: 'gr' },
|
||||
],
|
||||
undefined,
|
||||
),
|
||||
).toEqual([mockIndexEntry, mockTags1and4Entry]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('file rule', () => {
|
||||
it('should filter based on file name', () => {
|
||||
expect(filterEntries(entries, { pattern: '^index.md$' })).toEqual([mockIndexEntry]);
|
||||
expect(filterEntries(entries, { pattern: '^index.md$' }, undefined)).toEqual([
|
||||
mockIndexEntry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { pattern: '^_index.md$' })).toEqual([
|
||||
expect(filterEntries(entries, { pattern: '^_index.md$' }, undefined)).toEqual([
|
||||
mockUnderscoreIndexEntry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { pattern: 'index.md$' })).toEqual([
|
||||
expect(filterEntries(entries, { pattern: 'index.md$' }, undefined)).toEqual([
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
]);
|
||||
|
||||
// File names containing the word file (case insensitive)
|
||||
expect(filterEntries(entries, { pattern: '[fF][iI][lL][eE]' })).toEqual([
|
||||
expect(filterEntries(entries, { pattern: '[fF][iI][lL][eE]' }, undefined)).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockFrenchEntry,
|
||||
mockRandomFileNameEntry,
|
||||
@ -219,7 +236,7 @@ describe('filterEntries', () => {
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
// File names containing the word file (case insensitive)
|
||||
expect(
|
||||
filterEntries(entries, [{ pattern: '[fF][iI][lL][eE]' }, { pattern: 'some' }]),
|
||||
filterEntries(entries, [{ pattern: '[fF][iI][lL][eE]' }, { pattern: 'some' }], undefined),
|
||||
).toEqual([mockRandomFileNameEntry]);
|
||||
});
|
||||
});
|
||||
@ -227,16 +244,20 @@ describe('filterEntries', () => {
|
||||
describe('combined field and file rule', () => {
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
expect(
|
||||
filterEntries(entries, [{ pattern: 'index.md$' }, { field: 'tags', value: 'tag-3' }]),
|
||||
filterEntries(
|
||||
entries,
|
||||
[{ pattern: 'index.md$' }, { field: 'tags', value: 'tag-3' }],
|
||||
undefined,
|
||||
),
|
||||
).toEqual([mockUnderscoreIndexEntry]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nested fields', () => {
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
expect(filterEntries(entries, [{ field: 'nested.object.field', value: 'yes' }])).toEqual([
|
||||
mockNestedEntry,
|
||||
]);
|
||||
expect(
|
||||
filterEntries(entries, [{ field: 'nested.object.field', value: 'yes' }], undefined),
|
||||
).toEqual([mockNestedEntry]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -91,22 +91,30 @@ export function getFieldValue(
|
||||
return entry.data?.[field.name];
|
||||
}
|
||||
|
||||
export function isHidden(field: Field, entry: Entry | undefined): boolean {
|
||||
export function isHidden(
|
||||
field: Field,
|
||||
entry: Entry | undefined,
|
||||
listItemPath: string | undefined,
|
||||
): boolean {
|
||||
if (field.condition) {
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(field.condition)) {
|
||||
return !field.condition.find(r => entryMatchesFieldRule(entry, r));
|
||||
return !field.condition.find(r => entryMatchesFieldRule(entry, r, listItemPath));
|
||||
}
|
||||
|
||||
return !entryMatchesFieldRule(entry, field.condition);
|
||||
return !entryMatchesFieldRule(entry, field.condition, listItemPath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function useHidden(field: Field, entry: Entry | undefined): boolean {
|
||||
return useMemo(() => isHidden(field, entry), [entry, field]);
|
||||
export function useHidden(
|
||||
field: Field,
|
||||
entry: Entry | undefined,
|
||||
listItemPath: string | undefined,
|
||||
): boolean {
|
||||
return useMemo(() => isHidden(field, entry, listItemPath), [entry, field, listItemPath]);
|
||||
}
|
||||
|
@ -3,8 +3,15 @@ import get from 'lodash/get';
|
||||
|
||||
import type { Entry, FieldFilterRule, FilterRule } from '@staticcms/core/interface';
|
||||
|
||||
export function entryMatchesFieldRule(entry: Entry, filterRule: FieldFilterRule): boolean {
|
||||
const fieldValue = get(entry.data, filterRule.field);
|
||||
export function entryMatchesFieldRule(
|
||||
entry: Entry,
|
||||
filterRule: FieldFilterRule,
|
||||
listItemPath: string | undefined,
|
||||
): boolean {
|
||||
const fieldValue = get(
|
||||
entry.data,
|
||||
listItemPath ? `${listItemPath}.${filterRule.field}` : filterRule.field,
|
||||
);
|
||||
if ('pattern' in filterRule) {
|
||||
if (Array.isArray(fieldValue)) {
|
||||
return Boolean(fieldValue.find(v => new RegExp(filterRule.pattern).test(String(v))));
|
||||
@ -48,20 +55,24 @@ export function entryMatchesFieldRule(entry: Entry, filterRule: FieldFilterRule)
|
||||
return String(fieldValue) === String(filterRule.value);
|
||||
}
|
||||
|
||||
function entryMatchesRule(entry: Entry, filterRule: FilterRule) {
|
||||
function entryMatchesRule(entry: Entry, filterRule: FilterRule, listItemPath: string | undefined) {
|
||||
if ('field' in filterRule) {
|
||||
return entryMatchesFieldRule(entry, filterRule);
|
||||
return entryMatchesFieldRule(entry, filterRule, listItemPath);
|
||||
}
|
||||
|
||||
return new RegExp(filterRule.pattern).test(parse(entry.path).base);
|
||||
}
|
||||
|
||||
export default function filterEntries(entries: Entry[], filterRule: FilterRule | FilterRule[]) {
|
||||
export default function filterEntries(
|
||||
entries: Entry[],
|
||||
filterRule: FilterRule | FilterRule[],
|
||||
listItemPath: string | undefined,
|
||||
) {
|
||||
return entries.filter(entry => {
|
||||
if (Array.isArray(filterRule)) {
|
||||
return filterRule.every(r => entryMatchesRule(entry, r));
|
||||
return filterRule.every(r => entryMatchesRule(entry, r, listItemPath));
|
||||
}
|
||||
|
||||
return entryMatchesRule(entry, filterRule);
|
||||
return entryMatchesRule(entry, filterRule, listItemPath);
|
||||
});
|
||||
}
|
||||
|
@ -207,6 +207,7 @@ const ListItem: FC<ListItemProps> = ({
|
||||
locale={locale}
|
||||
i18n={i18n}
|
||||
forList={true}
|
||||
listItemPath={`${path}.${objectField.name}`}
|
||||
forSingleList={isSingleList}
|
||||
/>
|
||||
</ListItemWrapper>
|
||||
|
@ -69,8 +69,6 @@ const InsertLinkToolbarButton: FC<InsertLinkToolbarButtonProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('editor.selection', editor.selection);
|
||||
|
||||
deleteText(editor, {
|
||||
at: editor.selection as unknown as Location,
|
||||
});
|
||||
|
@ -22,6 +22,7 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
errors,
|
||||
disabled,
|
||||
value = {},
|
||||
listItemPath,
|
||||
}) => {
|
||||
const objectLabel = useMemo(() => {
|
||||
const summary = field.summary;
|
||||
@ -59,6 +60,7 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
locale={locale}
|
||||
i18n={i18n}
|
||||
forSingleList={forSingleList}
|
||||
listItemPath={listItemPath}
|
||||
/>
|
||||
);
|
||||
}) ?? null
|
||||
@ -75,6 +77,7 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
locale,
|
||||
i18n,
|
||||
forSingleList,
|
||||
listItemPath,
|
||||
]);
|
||||
|
||||
if (fields.length) {
|
||||
|
@ -65,6 +65,7 @@ export const createMockWidgetControlProps = <
|
||||
hasErrors,
|
||||
submitted: false,
|
||||
forList: false,
|
||||
listItemPath: undefined,
|
||||
forSingleList: false,
|
||||
disabled: false,
|
||||
locale: undefined,
|
||||
|
@ -81,7 +81,7 @@ The `condition` option can take a single filter rule or a list of filter rules.
|
||||
|
||||
### Example
|
||||
|
||||
The example below creates a collection based on a nested field's value.
|
||||
The example below conditionally shows fields based on the values of other fields.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
@ -163,7 +163,7 @@ collections: [
|
||||
|
||||
### Nested Field Example
|
||||
|
||||
The example below creates a collection based on a nested field's value.
|
||||
The example below conditionally shows fields based on the values of other nested fields.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
@ -241,3 +241,96 @@ collections: [
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
### List Field Example
|
||||
|
||||
The example below conditionally shows fields inside a list based on the values of other fields in the same list item. This works with both `fields` or `types`.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
collections:
|
||||
- name: list-field-filtered-collection
|
||||
label: List Field Filtered Collection
|
||||
folder: _list_field_condition
|
||||
create: true
|
||||
fields:
|
||||
- name: list
|
||||
label: List Field
|
||||
widget: list
|
||||
fields:
|
||||
- name: value
|
||||
label: Value 1
|
||||
widget: string
|
||||
condition:
|
||||
field: nested.object.field
|
||||
value: yes
|
||||
- name: nested
|
||||
label: Nested
|
||||
widget: object
|
||||
fields:
|
||||
- name: object
|
||||
label: Object
|
||||
widget: object
|
||||
fields:
|
||||
- name: field
|
||||
label: Field
|
||||
widget: select
|
||||
options:
|
||||
- yes
|
||||
- no
|
||||
|
||||
```
|
||||
|
||||
```js
|
||||
collections: [
|
||||
{
|
||||
name: "list-field-filtered-collection",
|
||||
label: "List Field Filtered Collection",
|
||||
folder: "_list_field_condition",
|
||||
create: true,
|
||||
fields: [
|
||||
{
|
||||
name: "list",
|
||||
label: "List Field",
|
||||
widget: "list",
|
||||
fields: [
|
||||
{
|
||||
name: "value",
|
||||
label: "Value 1",
|
||||
widget: "string",
|
||||
condition: {
|
||||
field: "nested.object.field",
|
||||
value: "yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "nested",
|
||||
label: "Nested",
|
||||
widget: "object",
|
||||
fields: [
|
||||
{
|
||||
name: "object",
|
||||
label: "Object",
|
||||
widget: "object",
|
||||
fields: [
|
||||
{
|
||||
name: "field",
|
||||
label: "Field",
|
||||
widget: "select",
|
||||
options: [
|
||||
"yes",
|
||||
"no"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
Loading…
x
Reference in New Issue
Block a user