Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
223 lines
7.9 KiB
Plaintext
223 lines
7.9 KiB
Plaintext
'use client';
|
|
|
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
import { getTranslation } from '@payloadcms/translations';
|
|
import { dequal } from 'dequal/lite';
|
|
import { transformWhereQuery, validateWhereQuery } from 'payload/shared';
|
|
import React, { useMemo } from 'react';
|
|
import { useAuth } from '../../providers/Auth/index.js';
|
|
import { useListQuery } from '../../providers/ListQuery/index.js';
|
|
import { useTranslation } from '../../providers/Translation/index.js';
|
|
import { reduceFieldsToOptions } from '../../utilities/reduceFieldsToOptions.js';
|
|
import { Button } from '../Button/index.js';
|
|
import { Condition } from './Condition/index.js';
|
|
import './index.scss';
|
|
import { fieldTypeConditions, getValidFieldOperators } from './field-types.js';
|
|
const baseClass = 'where-builder';
|
|
/**
|
|
* The WhereBuilder component is used to render the filter controls for a collection's list view.
|
|
* It is part of the {@link ListControls} component which is used to render the controls (search, filter, where).
|
|
*/
|
|
export const WhereBuilder = props => {
|
|
const {
|
|
collectionPluralLabel,
|
|
collectionSlug,
|
|
fields,
|
|
renderedFilters,
|
|
resolvedFilterOptions
|
|
} = props;
|
|
const {
|
|
i18n,
|
|
t
|
|
} = useTranslation();
|
|
const {
|
|
permissions
|
|
} = useAuth();
|
|
const fieldPermissions = permissions?.collections?.[collectionSlug]?.fields;
|
|
const reducedFields = useMemo(() => reduceFieldsToOptions({
|
|
fieldPermissions,
|
|
fields,
|
|
i18n
|
|
}), [fieldPermissions, fields, i18n]);
|
|
const {
|
|
handleWhereChange,
|
|
query
|
|
} = useListQuery();
|
|
const conditions = useMemo(() => {
|
|
const whereFromSearch = query.where;
|
|
if (whereFromSearch) {
|
|
if (validateWhereQuery(whereFromSearch)) {
|
|
return whereFromSearch.or;
|
|
}
|
|
// Transform the where query to be in the right format. This will transform something simple like [text][equals]=example%20post to the right format
|
|
const transformedWhere = transformWhereQuery(whereFromSearch);
|
|
if (validateWhereQuery(transformedWhere)) {
|
|
return transformedWhere.or;
|
|
}
|
|
console.warn(`Invalid where query in URL: ${JSON.stringify(whereFromSearch)}`); // eslint-disable-line no-console
|
|
}
|
|
return [];
|
|
}, [query.where]);
|
|
const addCondition = React.useCallback(async ({
|
|
andIndex,
|
|
field,
|
|
orIndex,
|
|
relation
|
|
}) => {
|
|
const newConditions = [...conditions];
|
|
const defaultOperator = fieldTypeConditions[field.field.type].operators[0].value;
|
|
if (relation === 'and') {
|
|
newConditions[orIndex].and.splice(andIndex, 0, {
|
|
[String(field.value)]: {
|
|
[defaultOperator]: undefined
|
|
}
|
|
});
|
|
} else {
|
|
newConditions.push({
|
|
and: [{
|
|
[String(field.value)]: {
|
|
[defaultOperator]: undefined
|
|
}
|
|
}]
|
|
});
|
|
}
|
|
await handleWhereChange({
|
|
or: newConditions
|
|
});
|
|
}, [conditions, handleWhereChange]);
|
|
const updateCondition = React.useCallback(async ({
|
|
andIndex: andIndex_0,
|
|
field: field_0,
|
|
operator: incomingOperator,
|
|
orIndex: orIndex_0,
|
|
value
|
|
}) => {
|
|
const existingCondition = conditions[orIndex_0].and[andIndex_0];
|
|
if (typeof existingCondition === 'object' && field_0.value) {
|
|
const {
|
|
validOperator
|
|
} = getValidFieldOperators({
|
|
field: field_0.field,
|
|
operator: incomingOperator
|
|
});
|
|
// Skip if nothing changed
|
|
const existingValue = existingCondition[String(field_0.value)]?.[validOperator];
|
|
if (typeof existingValue !== 'undefined' && existingValue === value) {
|
|
return;
|
|
}
|
|
const newRowCondition = {
|
|
[String(field_0.value)]: {
|
|
[validOperator]: value
|
|
}
|
|
};
|
|
if (dequal(existingCondition, newRowCondition)) {
|
|
return;
|
|
}
|
|
const newConditions_0 = [...conditions];
|
|
newConditions_0[orIndex_0].and[andIndex_0] = newRowCondition;
|
|
await handleWhereChange({
|
|
or: newConditions_0
|
|
});
|
|
}
|
|
}, [conditions, handleWhereChange]);
|
|
const removeCondition = React.useCallback(async ({
|
|
andIndex: andIndex_1,
|
|
orIndex: orIndex_1
|
|
}) => {
|
|
const newConditions_1 = [...conditions];
|
|
newConditions_1[orIndex_1].and.splice(andIndex_1, 1);
|
|
if (newConditions_1[orIndex_1].and.length === 0) {
|
|
newConditions_1.splice(orIndex_1, 1);
|
|
}
|
|
await handleWhereChange({
|
|
or: newConditions_1
|
|
});
|
|
}, [conditions, handleWhereChange]);
|
|
return /*#__PURE__*/_jsxs("div", {
|
|
className: baseClass,
|
|
children: [conditions.length > 0 && /*#__PURE__*/_jsxs(React.Fragment, {
|
|
children: [/*#__PURE__*/_jsx("p", {
|
|
className: `${baseClass}__label`,
|
|
children: t('general:filterWhere', {
|
|
label: getTranslation(collectionPluralLabel, i18n)
|
|
})
|
|
}), /*#__PURE__*/_jsx("ul", {
|
|
className: `${baseClass}__or-filters`,
|
|
children: conditions.map((or, orIndex_2) => {
|
|
const compoundOrKey = `${orIndex_2}_${Array.isArray(or?.and) ? or.and.length : ''}`;
|
|
return /*#__PURE__*/_jsxs("li", {
|
|
children: [orIndex_2 !== 0 && /*#__PURE__*/_jsx("div", {
|
|
className: `${baseClass}__label`,
|
|
children: t('general:or')
|
|
}), /*#__PURE__*/_jsx("ul", {
|
|
className: `${baseClass}__and-filters`,
|
|
children: Array.isArray(or?.and) && or.and.map((_, andIndex_2) => {
|
|
const condition = conditions[orIndex_2].and[andIndex_2];
|
|
const fieldPath = Object.keys(condition)[0];
|
|
const operator = Object.keys(condition?.[fieldPath] || {})?.[0] || undefined;
|
|
const value_0 = condition?.[fieldPath]?.[operator] || undefined;
|
|
return /*#__PURE__*/_jsxs("li", {
|
|
children: [andIndex_2 !== 0 && /*#__PURE__*/_jsx("div", {
|
|
className: `${baseClass}__label`,
|
|
children: t('general:and')
|
|
}), /*#__PURE__*/_jsx(Condition, {
|
|
addCondition: addCondition,
|
|
andIndex: andIndex_2,
|
|
fieldPath: fieldPath,
|
|
filterOptions: resolvedFilterOptions?.get(fieldPath),
|
|
operator: operator,
|
|
orIndex: orIndex_2,
|
|
reducedFields: reducedFields,
|
|
removeCondition: removeCondition,
|
|
RenderedFilter: renderedFilters?.get(fieldPath),
|
|
updateCondition: updateCondition,
|
|
value: value_0
|
|
})]
|
|
}, andIndex_2);
|
|
})
|
|
})]
|
|
}, compoundOrKey);
|
|
})
|
|
}), /*#__PURE__*/_jsx(Button, {
|
|
buttonStyle: "icon-label",
|
|
className: `${baseClass}__add-or`,
|
|
icon: "plus",
|
|
iconPosition: "left",
|
|
iconStyle: "with-border",
|
|
onClick: async () => {
|
|
await addCondition({
|
|
andIndex: 0,
|
|
field: reducedFields.find(field_1 => !field_1.field.admin?.disableListFilter),
|
|
orIndex: conditions.length,
|
|
relation: 'or'
|
|
});
|
|
},
|
|
children: t('general:or')
|
|
})]
|
|
}), conditions.length === 0 && /*#__PURE__*/_jsxs("div", {
|
|
className: `${baseClass}__no-filters`,
|
|
children: [/*#__PURE__*/_jsx("div", {
|
|
className: `${baseClass}__label`,
|
|
children: t('general:noFiltersSet')
|
|
}), /*#__PURE__*/_jsx(Button, {
|
|
buttonStyle: "icon-label",
|
|
className: `${baseClass}__add-first-filter`,
|
|
icon: "plus",
|
|
iconPosition: "left",
|
|
iconStyle: "with-border",
|
|
onClick: async () => {
|
|
if (reducedFields.length > 0) {
|
|
await addCondition({
|
|
andIndex: 0,
|
|
field: reducedFields.find(field_2 => !field_2.field.admin?.disableListFilter),
|
|
orIndex: conditions.length,
|
|
relation: 'or'
|
|
});
|
|
}
|
|
},
|
|
children: t('general:addFilter')
|
|
})]
|
|
})]
|
|
});
|
|
};
|
|
//# sourceMappingURL=index.js.map |