fix: select_any_in operator - Broken only for attributes (#17148)
* Fix select any_in operator for attributes - Broken only for attributres * Fix ts error
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
- [x] Connect Form Response to Booking
|
||||
- [x] Test with non option based attributes and form field input
|
||||
- [ ] Switching from Select to MultiSelect in attribute
|
||||
- [x] It immediately makes the Routing logic to not work. Fix it.
|
||||
- [ ] It immediately makes the Routing logic to not work. Fix it.
|
||||
- [ ] It removes the selected option from Routing. Fix it.
|
||||
- [ ] Warnings are needed with recommendation to create new attribute instead in unsupported scenarios. We need to test for more such changes to Attribute types.
|
||||
- [ ] When choosing 'Value of Field' option in RAQB, show a warning somewhere if all options of the Form field aren't present in the attribute option.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { BaseWidget } from "react-awesome-query-builder";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { AttributeType } from "@calcom/prisma/enums";
|
||||
|
||||
import { RoutingFormFieldType } from "../../lib/FieldTypes";
|
||||
@@ -86,7 +85,7 @@ function buildQueryValue({
|
||||
}: {
|
||||
rules: {
|
||||
raqbFieldId: string;
|
||||
value: string | number | string[];
|
||||
value: string | number | string[] | [string[]];
|
||||
operator: string;
|
||||
valueSrc: NonNullable<BaseWidget["valueSrc"]>[];
|
||||
valueType: string[];
|
||||
@@ -118,8 +117,9 @@ function buildSelectTypeFieldQueryValue({
|
||||
}: {
|
||||
rules: {
|
||||
raqbFieldId: string;
|
||||
value: string | number | string[];
|
||||
value: string | number | string[] | [string[]];
|
||||
operator: string;
|
||||
valueType?: string[];
|
||||
}[];
|
||||
}) {
|
||||
return buildQueryValue({
|
||||
@@ -128,7 +128,7 @@ function buildSelectTypeFieldQueryValue({
|
||||
value: rule.value,
|
||||
operator: rule.operator,
|
||||
valueSrc: ["value"],
|
||||
valueType: ["select"],
|
||||
valueType: rule.valueType ?? ["select"],
|
||||
})),
|
||||
}) as AttributesQueryValue;
|
||||
}
|
||||
@@ -336,6 +336,125 @@ describe("findTeamMembersMatchingAttributeLogicOfRoute", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("should return matching team members with a SINGLE_SELECT attribute when 'Any in' option is selected", async () => {
|
||||
const Option1OfAttribute1HumanReadableValue = "Option 1";
|
||||
const Option1OfField1HumanReadableValue = Option1OfAttribute1HumanReadableValue;
|
||||
const Field1Id = "field-1";
|
||||
|
||||
const Option1OfAttribute1 = {
|
||||
id: "attr-1-opt-1",
|
||||
value: Option1OfAttribute1HumanReadableValue,
|
||||
slug: "option-1",
|
||||
};
|
||||
|
||||
const Option2OfAttribute1 = {
|
||||
id: "attr-1-opt-2",
|
||||
value: "Option 2",
|
||||
slug: "option-2",
|
||||
};
|
||||
|
||||
const Option3OfAttribute1 = {
|
||||
id: "attr-1-opt-3",
|
||||
value: "Option 3",
|
||||
slug: "option-3",
|
||||
};
|
||||
|
||||
const Attribute1 = {
|
||||
id: "attr1",
|
||||
name: "Attribute 1",
|
||||
type: "SINGLE_SELECT" as const,
|
||||
slug: "attribute-1",
|
||||
options: [Option1OfAttribute1, Option2OfAttribute1, Option3OfAttribute1],
|
||||
};
|
||||
|
||||
mockAttributesScenario({
|
||||
attributes: [Attribute1],
|
||||
teamMembersWithAttributeOptionValuePerAttribute: [
|
||||
{ userId: 1, attributes: { [Attribute1.id]: Option1OfAttribute1.value } },
|
||||
],
|
||||
});
|
||||
|
||||
const attributesQueryValue = buildSelectTypeFieldQueryValue({
|
||||
rules: [
|
||||
{
|
||||
raqbFieldId: Attribute1.id,
|
||||
value: [[Option1OfAttribute1.id, Option2OfAttribute1.id]],
|
||||
operator: "select_any_in",
|
||||
valueType: ["multiselect"],
|
||||
},
|
||||
],
|
||||
}) as AttributesQueryValue;
|
||||
|
||||
const { teamMembersMatchingAttributeLogic: result } = await findTeamMembersMatchingAttributeLogicOfRoute({
|
||||
form: {
|
||||
routes: [
|
||||
buildDefaultCustomPageRoute({
|
||||
id: "test-route",
|
||||
attributesQueryValue: attributesQueryValue,
|
||||
}),
|
||||
],
|
||||
fields: [],
|
||||
},
|
||||
response: {},
|
||||
routeId: "test-route",
|
||||
teamId: 1,
|
||||
});
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
userId: 1,
|
||||
result: RaqbLogicResult.MATCH,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
describe("Error handling", () => {
|
||||
it("should throw an error if the attribute type is not supported", async () => {
|
||||
const Option1OfAttribute1 = { id: "opt1", value: "Option 1", slug: "option-1" };
|
||||
const Attribute1 = {
|
||||
id: "attr1",
|
||||
name: "Attribute 1",
|
||||
type: "UNSUPPORTED_ATTRIBUTE_TYPE" as unknown as AttributeType,
|
||||
slug: "attribute-1",
|
||||
options: [Option1OfAttribute1],
|
||||
};
|
||||
mockAttributesScenario({
|
||||
attributes: [Attribute1],
|
||||
teamMembersWithAttributeOptionValuePerAttribute: [
|
||||
{
|
||||
userId: 1,
|
||||
attributes: { [Attribute1.id]: Option1OfAttribute1.value },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await expect(
|
||||
findTeamMembersMatchingAttributeLogicOfRoute({
|
||||
form: {
|
||||
routes: [
|
||||
buildDefaultCustomPageRoute({
|
||||
id: "test-route",
|
||||
attributesQueryValue: buildSelectTypeFieldQueryValue({
|
||||
rules: [
|
||||
{
|
||||
raqbFieldId: Attribute1.id,
|
||||
value: [Option1OfAttribute1.id],
|
||||
operator: "select_equals",
|
||||
},
|
||||
],
|
||||
}) as AttributesQueryValue,
|
||||
}),
|
||||
],
|
||||
fields: [],
|
||||
},
|
||||
response: {},
|
||||
routeId: "test-route",
|
||||
teamId: 1,
|
||||
})
|
||||
).rejects.toThrow("Unsupported attribute type");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Performance testing", () => {
|
||||
describe("20 attributes, 4000 team members", async () => {
|
||||
// In tests, the performance is actually really bad than real world. So, skipping this test for now
|
||||
@@ -346,7 +465,6 @@ describe("findTeamMembersMatchingAttributeLogicOfRoute", () => {
|
||||
numTeamMembers: 4000,
|
||||
numAttributesUsedPerTeamMember: 10,
|
||||
});
|
||||
|
||||
const attributesQueryValue = buildSelectTypeFieldQueryValue({
|
||||
rules: [
|
||||
{
|
||||
|
||||
@@ -138,6 +138,10 @@ const replaceFieldTemplateVariableWithOptionLabel = ({
|
||||
* Utilities to handle compatiblity when attribute's type changes
|
||||
*/
|
||||
const attributeChangeCompatibility = {
|
||||
/**
|
||||
* FIXME: It isn't able to handle a case where for SINGLE_SELECT attribute, the queryValue->valueType is ["multiselect"]. It happens for select_any_in operator
|
||||
* So, don't use it till that is fixed.
|
||||
*/
|
||||
getRaqbFieldTypeCompatibleWithQueryValue: function getRaqbFieldTypeCompatibleWithQueryValue({
|
||||
attributesQueryValue,
|
||||
raqbField,
|
||||
@@ -163,6 +167,8 @@ const attributeChangeCompatibility = {
|
||||
},
|
||||
/**
|
||||
* Ensure the attribute value if of type same as the valueType in queryValue
|
||||
* FIXME: It isn't able to handle a case where for SINGLE_SELECT attribute, the queryValue->valueType is ["multiselect"]. It happens for select_any_in operator
|
||||
* So, don't use it till that is fixed.
|
||||
*/
|
||||
ensureAttributeValueToBeOfRaqbFieldValueType: function ensureAttributeValueToBeOfRaqbFieldValueType({
|
||||
attributeValue,
|
||||
@@ -197,11 +203,14 @@ function getAttributesData({
|
||||
const compatibleValueForAttributeAndFormFieldMatching = compatibleForAttributeAndFormFieldMatch(value);
|
||||
|
||||
// We do this to ensure that correct jsonLogic is generated for an existing route even if the attribute's type changes
|
||||
acc[attributeId] = attributeChangeCompatibility.ensureAttributeValueToBeOfRaqbFieldValueType({
|
||||
attributeValue: compatibleValueForAttributeAndFormFieldMatching,
|
||||
attributesQueryValue,
|
||||
attributeId,
|
||||
});
|
||||
// acc[attributeId] = attributeChangeCompatibility.ensureAttributeValueToBeOfRaqbFieldValueType({
|
||||
// attributeValue: compatibleValueForAttributeAndFormFieldMatching,
|
||||
// attributesQueryValue,
|
||||
// attributeId,
|
||||
// });
|
||||
|
||||
// Right now we can't trust ensureAttributeValueToBeOfRaqbFieldValueType to give us the correct value
|
||||
acc[attributeId] = compatibleValueForAttributeAndFormFieldMatching;
|
||||
|
||||
return acc;
|
||||
}, {} as Record<string, string | string[]>);
|
||||
@@ -262,11 +271,14 @@ function getAttributesQueryBuilderConfig({
|
||||
|
||||
const attributesQueryBuilderConfigFieldsWithCompatibleListValues = Object.fromEntries(
|
||||
Object.entries(attributesQueryBuilderConfig.fields).map(([raqbFieldId, raqbField]) => {
|
||||
const raqbFieldType = attributeChangeCompatibility.getRaqbFieldTypeCompatibleWithQueryValue({
|
||||
attributesQueryValue,
|
||||
raqbField,
|
||||
raqbFieldId,
|
||||
});
|
||||
// const raqbFieldType = attributeChangeCompatibility.getRaqbFieldTypeCompatibleWithQueryValue({
|
||||
// attributesQueryValue,
|
||||
// raqbField,
|
||||
// raqbFieldId,
|
||||
// });
|
||||
|
||||
// Right now we can't trust getRaqbFieldTypeCompatibleWithQueryValue to give us the correct type
|
||||
const raqbFieldType = raqbField.type;
|
||||
|
||||
return [
|
||||
raqbFieldId,
|
||||
|
||||
Reference in New Issue
Block a user