From 3fb8c8afa2017a4b796d107291c102ea36da60eb Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Tue, 30 Sep 2025 14:37:30 -0300 Subject: [PATCH 01/14] wip: upgrade dep --- packages/app-store/routing-forms/package.json | 4 +- packages/features/Segment.tsx | 4 +- packages/lib/raqb/raqbUtils.ts | 6 +- yarn.lock | 214 +++++++++--------- 4 files changed, 117 insertions(+), 111 deletions(-) diff --git a/packages/app-store/routing-forms/package.json b/packages/app-store/routing-forms/package.json index e7d5b499f6fa7c..b7b9e834f5f742 100644 --- a/packages/app-store/routing-forms/package.json +++ b/packages/app-store/routing-forms/package.json @@ -7,9 +7,9 @@ "description": "It would allow a booker to connect with the right person or choose the right event, faster. It would work by taking inputs from the booker and using that data to route to the correct booker/event as configured by Cal user ", "dependencies": { "@calcom/lib": "workspace:*", + "@react-awesome-query-builder/ui": "6.6.15", "dotenv": "^16.3.1", - "json-logic-js": "^2.0.2", - "react-awesome-query-builder": "^5.1.2" + "json-logic-js": "^2.0.2" }, "scripts": { "lint": "eslint .", diff --git a/packages/features/Segment.tsx b/packages/features/Segment.tsx index 5aca7b7c1ce907..7d4efef524bec7 100644 --- a/packages/features/Segment.tsx +++ b/packages/features/Segment.tsx @@ -1,8 +1,8 @@ "use client"; +import { Query, Builder, Utils as QbUtils } from "@react-awesome-query-builder/ui"; +import type { ImmutableTree, BuilderProps } from "@react-awesome-query-builder/ui"; import { useCallback, useState } from "react"; -import { Query, Builder, Utils as QbUtils } from "react-awesome-query-builder"; -import type { ImmutableTree, BuilderProps } from "react-awesome-query-builder"; import type { JsonTree } from "react-awesome-query-builder"; import { diff --git a/packages/lib/raqb/raqbUtils.ts b/packages/lib/raqb/raqbUtils.ts index d6fdbfd6200a63..a48d26ac6dde66 100644 --- a/packages/lib/raqb/raqbUtils.ts +++ b/packages/lib/raqb/raqbUtils.ts @@ -1,6 +1,6 @@ -import type { JsonGroup, JsonItem, JsonRule, JsonTree } from "react-awesome-query-builder"; -import type { Config } from "react-awesome-query-builder"; -import { Utils as QbUtils } from "react-awesome-query-builder"; +import type { JsonGroup, JsonItem, JsonRule, JsonTree } from "@react-awesome-query-builder/ui"; +import type { Config } from "@react-awesome-query-builder/ui"; +import { Utils as QbUtils } from "@react-awesome-query-builder/ui"; import { getQueryBuilderConfigForAttributes } from "@calcom/app-store/routing-forms/lib/getQueryBuilderConfig"; import type { LocalRoute } from "@calcom/app-store/routing-forms/types/types"; diff --git a/yarn.lock b/yarn.lock index 53001fc5f00564..c565009353f854 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2263,6 +2263,13 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.27.0": + version: 7.28.4 + resolution: "@babel/runtime@npm:7.28.4" + checksum: 934b0a0460f7d06637d93fcd1a44ac49adc33518d17253b5a0b55ff4cb90a45d8fe78bf034b448911dbec7aff2a90b918697559f78d21c99ff8dbadae9565b55 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.23.2": version: 7.23.5 resolution: "@babel/runtime@npm:7.23.5" @@ -3909,10 +3916,10 @@ __metadata: "@calcom/eslint-config": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/types": "workspace:*" + "@react-awesome-query-builder/ui": 6.6.15 "@types/json-logic-js": ^1.2.1 dotenv: ^16.3.1 json-logic-js: ^2.0.2 - react-awesome-query-builder: ^5.1.2 languageName: unknown linkType: soft @@ -4870,24 +4877,6 @@ __metadata: languageName: node linkType: hard -"@date-io/core@npm:^1.3.13": - version: 1.3.13 - resolution: "@date-io/core@npm:1.3.13" - checksum: 5a9e9d1de20f0346a3c7d2d5946190caef4bfb0b64d82ba1f4c566657a9192667c94ebe7f438d11d4286d9c190974daad4fb2159294225cd8af4d9a140239879 - languageName: node - linkType: hard - -"@date-io/moment@npm:^1.3.13": - version: 1.3.13 - resolution: "@date-io/moment@npm:1.3.13" - dependencies: - "@date-io/core": ^1.3.13 - peerDependencies: - moment: ^2.24.0 - checksum: c4847f9d1bf09bb22c1acc5806fc50825c0bdb52408c9fec8cc5f9a65f16a8014870b5890a0eeb73b2c53a6487c35acbd2ab2a5c49068ff5a5dccbcb5c9e654b - languageName: node - linkType: hard - "@datocms/cma-client-node@npm:^4.0.1": version: 4.0.2 resolution: "@datocms/cma-client-node@npm:4.0.2" @@ -14327,6 +14316,41 @@ __metadata: languageName: node linkType: hard +"@react-awesome-query-builder/core@npm:^6.6.15": + version: 6.6.15 + resolution: "@react-awesome-query-builder/core@npm:6.6.15" + dependencies: + "@babel/runtime": ^7.27.0 + clone: ^2.1.2 + i18next: ^23.11.5 + immutable: ^4.3.6 + json-logic-js: ^2.0.2 + lodash: ^4.17.21 + moment: ^2.30.1 + spel2js: ^0.2.8 + sqlstring: ^2.3.3 + checksum: 4c1328976fe1cc7eca0bc003d59f7042e2244526244f2a3f96f1df592c857472d258a27ba28390cfa4d120c61ad7df11c00f0f65aebba087782dddbeec812d5d + languageName: node + linkType: hard + +"@react-awesome-query-builder/ui@npm:6.6.15": + version: 6.6.15 + resolution: "@react-awesome-query-builder/ui@npm:6.6.15" + dependencies: + "@babel/runtime": ^7.27.0 + "@react-awesome-query-builder/core": ^6.6.15 + classnames: ^2.5.1 + lodash: ^4.17.21 + prop-types: ^15.8.1 + react-redux: ^8.1.3 + redux: ^4.2.1 + peerDependencies: + react: ^16.8.4 || ^17.0.1 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.4 || ^17.0.1 || ^18.0.0 || ^19.0.0 + checksum: 8c09588009e47d35cffe466d4f9161d3ebdfaa262a14919bb80f9f95e4013ab4aeb2839a05bd3beb852cba22cfd5ae9d008c791539f068de710f5de9ccaa4235 + languageName: node + linkType: hard + "@redis/bloom@npm:1.2.0": version: 1.2.0 resolution: "@redis/bloom@npm:1.2.0" @@ -17746,13 +17770,14 @@ __metadata: languageName: node linkType: hard -"@types/hoist-non-react-statics@npm:^3.3.0": - version: 3.3.1 - resolution: "@types/hoist-non-react-statics@npm:3.3.1" +"@types/hoist-non-react-statics@npm:^3.3.1": + version: 3.3.7 + resolution: "@types/hoist-non-react-statics@npm:3.3.7" dependencies: - "@types/react": "*" hoist-non-react-statics: ^3.3.0 - checksum: 2c0778570d9a01d05afabc781b32163f28409bb98f7245c38d5eaf082416fdb73034003f5825eb5e21313044e8d2d9e1f3fe2831e345d3d1b1d20bcd12270719 + peerDependencies: + "@types/react": "*" + checksum: 13f610572c073970b3f43cc446396974fed786fee6eac2d6fd4b0ca5c985f13e79d4a0de58af4e5b4c68470d808567c3a14108d98edb7d526d4d46c8ec851ed1 languageName: node linkType: hard @@ -18239,18 +18264,6 @@ __metadata: languageName: node linkType: hard -"@types/react-redux@npm:^7.1.20": - version: 7.1.24 - resolution: "@types/react-redux@npm:7.1.24" - dependencies: - "@types/hoist-non-react-statics": ^3.3.0 - "@types/react": "*" - hoist-non-react-statics: ^3.3.0 - redux: ^4.0.0 - checksum: 6582246581331ac7fbbd44aa1f1c136c8a9c8febbcf462432ac81302263308c21e1a2e7868beb7f73bbcb52a8e67935d133cb37f5bdcb6564eaff3a811805101 - languageName: node - linkType: hard - "@types/react-transition-group@npm:^4.4.0": version: 4.4.4 resolution: "@types/react-transition-group@npm:4.4.4" @@ -18478,6 +18491,13 @@ __metadata: languageName: node linkType: hard +"@types/use-sync-external-store@npm:^0.0.3": + version: 0.0.3 + resolution: "@types/use-sync-external-store@npm:0.0.3" + checksum: 161ddb8eec5dbe7279ac971531217e9af6b99f7783213566d2b502e2e2378ea19cf5e5ea4595039d730aa79d3d35c6567d48599f69773a02ffcff1776ec2a44e + languageName: node + linkType: hard + "@types/use-sync-external-store@npm:^0.0.6": version: 0.0.6 resolution: "@types/use-sync-external-store@npm:0.0.6" @@ -22786,6 +22806,13 @@ __metadata: languageName: node linkType: hard +"classnames@npm:^2.5.1": + version: 2.5.1 + resolution: "classnames@npm:2.5.1" + checksum: da424a8a6f3a96a2e87d01a432ba19315503294ac7e025f9fece656db6b6a0f7b5003bb1fbb51cbb0d9624d964f1b9bb35a51c73af9b2434c7b292c42231c1e5 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -30559,6 +30586,15 @@ __metadata: languageName: node linkType: hard +"i18next@npm:^23.11.5": + version: 23.16.8 + resolution: "i18next@npm:23.16.8" + dependencies: + "@babel/runtime": ^7.23.2 + checksum: 288dab98225d769c6ad7835e9c534a184a2a8fb28485000f35b10c467439478047b367d39015c1920ac9c5cfc33572ffd75ecf1778edcd96536024bf594f4ca9 + languageName: node + linkType: hard + "i18next@npm:^23.2.3": version: 23.2.3 resolution: "i18next@npm:23.2.3" @@ -30665,10 +30701,10 @@ __metadata: languageName: node linkType: hard -"immutable@npm:^3.8.2": - version: 3.8.2 - resolution: "immutable@npm:3.8.2" - checksum: 41909b386950ff84ca3cfca77c74cfc87d225a914e98e6c57996fa81a328da61a7c32216d6d5abad40f54747ffdc5c4b02b102e6ad1a504c1752efde8041f964 +"immutable@npm:^4.3.6": + version: 4.3.7 + resolution: "immutable@npm:4.3.7" + checksum: 1c50eb053bb300796551604afff554066f041aa8e15926cf98f6d11d9736b62ad12531c06515dd96375258653878b4736f8051cd20b640f5f976d09fa640e3ec languageName: node linkType: hard @@ -36183,6 +36219,13 @@ __metadata: languageName: node linkType: hard +"moment@npm:^2.30.1": + version: 2.30.1 + resolution: "moment@npm:2.30.1" + checksum: 859236bab1e88c3e5802afcf797fc801acdbd0ee509d34ea3df6eea21eb6bcc2abd4ae4e4e64aa7c986aa6cba563c6e62806218e6412a765010712e5fa121ba6 + languageName: node + linkType: hard + "mongodb-connection-string-url@npm:^3.0.0": version: 3.0.0 resolution: "mongodb-connection-string-url@npm:3.0.0" @@ -40518,45 +40561,6 @@ __metadata: languageName: node linkType: hard -"react-awesome-query-builder@npm:^5.1.2": - version: 5.1.2 - resolution: "react-awesome-query-builder@npm:5.1.2" - dependencies: - "@date-io/moment": ^1.3.13 - classnames: ^2.3.1 - clone: ^2.1.2 - immutable: ^3.8.2 - lodash: ^4.17.21 - moment: ^2.29.1 - prop-types: ^15.7.2 - react-redux: ^7.2.2 - redux: ^4.1.0 - spel2js: ^0.2.8 - sqlstring: ^2.3.2 - peerDependencies: - "@ant-design/icons": ^4.0.0 - "@emotion/react": ^11.7.1 - "@emotion/styled": ^11.6.0 - "@fortawesome/fontawesome-svg-core": ^1.2.36 - "@fortawesome/free-solid-svg-icons": ^5.15.4 - "@fortawesome/react-fontawesome": ^0.1.16 - "@material-ui/core": ^4.12.3 - "@material-ui/icons": ^4.0.0 - "@material-ui/lab": ^4.0.0-alpha.57 - "@material-ui/pickers": ^3.2.10 - "@mui/icons-material": ^5.2.4 - "@mui/lab": ^5.0.0-alpha.60 - "@mui/material": ^5.2.4 - antd: ^4.0.0 - bootstrap: ^5.1.3 - material-ui-confirm: ^2.0.1 || ^3.0.0 - react: ^16.8.4 || ^17.0.1 - react-dom: ^16.8.4 || ^17.0.1 - reactstrap: ^9.0.0 - checksum: 6efab0fcbb98d4843fbe3b5036a7831fd097774869fc0e175ca40c4770d7939dd3efcb2c3365c6fe539c8ba6b6bb19ddef55d93f491770a9bfdc3f1355cc5e4e - languageName: node - linkType: hard - "react-calendar@npm:^3.3.1": version: 3.7.0 resolution: "react-calendar@npm:3.7.0" @@ -40926,24 +40930,35 @@ __metadata: languageName: node linkType: hard -"react-redux@npm:^7.2.2": - version: 7.2.8 - resolution: "react-redux@npm:7.2.8" +"react-redux@npm:^8.1.3": + version: 8.1.3 + resolution: "react-redux@npm:8.1.3" dependencies: - "@babel/runtime": ^7.15.4 - "@types/react-redux": ^7.1.20 + "@babel/runtime": ^7.12.1 + "@types/hoist-non-react-statics": ^3.3.1 + "@types/use-sync-external-store": ^0.0.3 hoist-non-react-statics: ^3.3.2 - loose-envify: ^1.4.0 - prop-types: ^15.7.2 - react-is: ^17.0.2 + react-is: ^18.0.0 + use-sync-external-store: ^1.0.0 peerDependencies: - react: ^16.8.3 || ^17 || ^18 + "@types/react": ^16.8 || ^17.0 || ^18.0 + "@types/react-dom": ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + react-native: ">=0.59" + redux: ^4 || ^5.0.0-beta.0 peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true react-dom: optional: true react-native: optional: true - checksum: ecf1933e91013f2d41bfc781515b536bf81eb1f70ff228607841094c8330fe77d522372b359687e51c0b52b9888dba73db9ac0486aace1896ab9eb9daec102d5 + redux: + optional: true + checksum: 192ea6f6053148ec80a4148ec607bc259403b937e515f616a1104ca5ab357e97e98b8245ed505a17afee67a72341d4a559eaca9607968b4a422aa9b44ba7eb89 languageName: node linkType: hard @@ -41628,21 +41643,12 @@ __metadata: languageName: node linkType: hard -"redux@npm:^4.0.0": - version: 4.1.2 - resolution: "redux@npm:4.1.2" - dependencies: - "@babel/runtime": ^7.9.2 - checksum: 6a839cee5bd580c5298d968e9e2302150e961318253819bcd97f9d945a5a409559eacddf6026f4118bb68b681c593d90e8a2c5bbf278f014aff9bf0d2d8fa084 - languageName: node - linkType: hard - -"redux@npm:^4.1.0": - version: 4.2.0 - resolution: "redux@npm:4.2.0" +"redux@npm:^4.2.1": + version: 4.2.1 + resolution: "redux@npm:4.2.1" dependencies: "@babel/runtime": ^7.9.2 - checksum: 75f3955c89b3f18edf5411e5fb482aa2e4f41a416183e8802a6bf6472c4fc3d47675b8b321d147f8af8e0f616436ac507bf5a25f1c4d6180e797b549c7db2c1d + checksum: f63b9060c3a1d930ae775252bb6e579b42415aee7a23c4114e21a0b4ba7ec12f0ec76936c00f546893f06e139819f0e2855e0d55ebfce34ca9c026241a6950dd languageName: node linkType: hard @@ -44309,7 +44315,7 @@ __metadata: languageName: node linkType: hard -"sqlstring@npm:^2.3.2": +"sqlstring@npm:^2.3.2, sqlstring@npm:^2.3.3": version: 2.3.3 resolution: "sqlstring@npm:2.3.3" checksum: 1e7e2d51c38a0cf7372e875408ca100b6e0c9a941ab7773975ea41fb36e5528e404dc787689be855780cf6d0a829ff71027964ae3a05a7446e91dce26672fda7 @@ -47742,7 +47748,7 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.2.2, use-sync-external-store@npm:^1.4.0": +"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.2, use-sync-external-store@npm:^1.4.0": version: 1.5.0 resolution: "use-sync-external-store@npm:1.5.0" peerDependencies: From 841faaf83496f78542b7d3b26d994953a0a14201 Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Tue, 30 Sep 2025 19:59:18 -0300 Subject: [PATCH 02/14] wip: upgrade dep --- .../apps/routing-forms/[...pages]/RouteBuilder.tsx | 14 +++++++------- .../app-store/routing-forms/lib/processRoute.tsx | 2 +- packages/lib/raqb/evaluateRaqbLogic.ts | 4 ++-- .../raqb/findTeamMembersMatchingAttributeLogic.ts | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/RouteBuilder.tsx b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/RouteBuilder.tsx index 2bc7ccfd121a13..c791a3ea62eb48 100644 --- a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/RouteBuilder.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/RouteBuilder.tsx @@ -1,11 +1,11 @@ "use client"; import { useAutoAnimate } from "@formkit/auto-animate/react"; +import { Query, Builder, Utils as QbUtils } from "@react-awesome-query-builder/ui"; +import type { ImmutableTree, BuilderProps, Config } from "@react-awesome-query-builder/ui"; +import type { JsonTree } from "@react-awesome-query-builder/ui"; import Link from "next/link"; import React, { useCallback, useState, useEffect } from "react"; -import { Query, Builder, Utils as QbUtils } from "react-awesome-query-builder"; -import type { ImmutableTree, BuilderProps, Config } from "react-awesome-query-builder"; -import type { JsonTree } from "react-awesome-query-builder"; import type { UseFormReturn } from "react-hook-form"; import { Toaster } from "sonner"; import type { z } from "zod"; @@ -308,7 +308,7 @@ const WeightedAttributesSelector = ({ />
- {!!attributeIdForWeights ? ( + {attributeIdForWeights ? ( form.connectedForms.map((f) => f.id).includes(id); - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // const routers: any[] = []; /* Disable this feature for new forms till we get it fully working with Routing Form with Attributes. This isn't much used feature */ // const routers = availableRouters.map((r) => { @@ -1235,7 +1235,7 @@ const Routes = ({ }); setRoutes((routes) => { // Even though it's obvious that fallbackRoute is defined here but TypeScript just can't figure it out. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return [...routes, fallbackRoute!]; }); return null; @@ -1243,7 +1243,7 @@ const Routes = ({ // Ensure fallback is last setRoutes((routes) => { // Even though it's obvious that fallbackRoute is defined here but TypeScript just can't figure it out. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return [...routes.filter((route) => route.id !== fallbackRoute!.id), fallbackRoute!]; }); } diff --git a/packages/app-store/routing-forms/lib/processRoute.tsx b/packages/app-store/routing-forms/lib/processRoute.tsx index 0ddd624d94fffa..e1a53898fa0773 100644 --- a/packages/app-store/routing-forms/lib/processRoute.tsx +++ b/packages/app-store/routing-forms/lib/processRoute.tsx @@ -1,6 +1,6 @@ "use client"; -import type { JsonTree } from "react-awesome-query-builder"; +import type { JsonTree } from "@react-awesome-query-builder/ui"; import type { z } from "zod"; import { evaluateRaqbLogic, RaqbLogicResult } from "@calcom/lib/raqb/evaluateRaqbLogic"; diff --git a/packages/lib/raqb/evaluateRaqbLogic.ts b/packages/lib/raqb/evaluateRaqbLogic.ts index 28329143d483ec..f0850a3c8f871e 100644 --- a/packages/lib/raqb/evaluateRaqbLogic.ts +++ b/packages/lib/raqb/evaluateRaqbLogic.ts @@ -1,6 +1,6 @@ "use client"; -import { Utils as QbUtils, type JsonTree } from "react-awesome-query-builder"; +import { Utils as QbUtils, type JsonTree } from "@react-awesome-query-builder/ui"; import { safeStringify } from "@calcom/lib/safeStringify"; @@ -55,5 +55,5 @@ export const evaluateRaqbLogic = ( console.log("Checking logic with data", safeStringify({ logic, data })); } // eslint-disable-next-line @typescript-eslint/no-explicit-any - return !!jsonLogic.apply(logic as any, data) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; + return jsonLogic.apply(logic as any, data) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; }; diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts index ee91db434ab373..84293e6da3d4ba 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -1,7 +1,7 @@ +import type { ImmutableTree, JsonLogicResult, JsonTree } from "@react-awesome-query-builder/ui"; +import { Utils as QbUtils } from "@react-awesome-query-builder/ui"; +import type { BasicConfig as Config } from "@react-awesome-query-builder/ui"; import async from "async"; -import type { ImmutableTree, JsonLogicResult, JsonTree } from "react-awesome-query-builder"; -import type { Config } from "react-awesome-query-builder/lib"; -import { Utils as QbUtils } from "react-awesome-query-builder/lib"; import type { dynamicFieldValueOperands } from "@calcom/lib/raqb/types"; import { getAttributesAssignmentData } from "@calcom/lib/service/attribute/server/getAttributes"; @@ -160,7 +160,7 @@ async function getLogicResultForAllMembers( attributesQueryValue, }); attributesDataPerUser.set(member.userId, attributesData); - const result = !!jsonLogic.apply(attributeJsonLogic as any, attributesData) + const result = jsonLogic.apply(attributeJsonLogic as any, attributesData) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; From d265a51b0cd1c1d7c21ba72fbfbf4af3fb82ab50 Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Wed, 1 Oct 2025 18:30:45 -0300 Subject: [PATCH 03/14] wip: upgrade dep --- packages/app-store/routing-forms/__tests__/uiConfig.test.ts | 2 +- .../react-awesome-query-builder/config/BasicConfig.ts | 2 +- .../components/react-awesome-query-builder/config/types.ts | 2 +- .../react-awesome-query-builder/config/uiConfig.tsx | 4 ++-- .../components/react-awesome-query-builder/widgets.tsx | 6 +++--- packages/app-store/routing-forms/lib/createFallbackRoute.ts | 2 +- packages/app-store/routing-forms/types/types.d.ts | 2 +- .../lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts | 6 +++--- packages/platform/atoms/scripts/dev-on.js | 5 ++++- 9 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/app-store/routing-forms/__tests__/uiConfig.test.ts b/packages/app-store/routing-forms/__tests__/uiConfig.test.ts index 2eac86afc6c1b5..cd06ef9f4e847c 100644 --- a/packages/app-store/routing-forms/__tests__/uiConfig.test.ts +++ b/packages/app-store/routing-forms/__tests__/uiConfig.test.ts @@ -1,4 +1,4 @@ -import type { Settings } from "react-awesome-query-builder"; +import type { Settings } from "@react-awesome-query-builder/ui"; import { describe, it, vi, expect } from "vitest"; import { diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts index 21689593f9ecd3..33b86017dc72eb 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts @@ -5,7 +5,7 @@ import type { Type as RAQBType, Settings as RAQBSettings, Operator as RAQBOperator, -} from "react-awesome-query-builder"; +} from "@react-awesome-query-builder/ui"; export type Conjunction = RAQBConjunction; export type Conjunctions = Record; diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/types.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/types.ts index 2afbd64ea7a146..14c13e3c1f3e92 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/types.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/types.ts @@ -1,4 +1,4 @@ -import type { Widgets as RaqbWidgets } from "react-awesome-query-builder"; +import type { Widgets as RaqbWidgets } from "@react-awesome-query-builder/ui"; export const enum ConfigFor { FormFields = "FormFields", diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx index 6f9f77b8f50114..689e38cb892b32 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx @@ -1,10 +1,10 @@ -import type { ChangeEvent } from "react"; import type { Settings, SelectWidgetProps, SelectWidget as SelectWidgetType, WidgetProps, -} from "react-awesome-query-builder"; +} from "@react-awesome-query-builder/ui"; +import type { ChangeEvent } from "react"; import { EmailField as EmailWidget } from "@calcom/ui/components/form"; diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx index 7b83afa964cf4d..942ceb29d2693a 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx @@ -1,12 +1,12 @@ -import dynamic from "next/dynamic"; -import type { ChangeEvent } from "react"; import type { ButtonGroupProps, ButtonProps, ConjsProps, FieldProps, ProviderProps, -} from "react-awesome-query-builder"; +} from "@react-awesome-query-builder/ui"; +import dynamic from "next/dynamic"; +import type { ChangeEvent } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Button as CalButton } from "@calcom/ui/components/button"; diff --git a/packages/app-store/routing-forms/lib/createFallbackRoute.ts b/packages/app-store/routing-forms/lib/createFallbackRoute.ts index 4e4ff8b37a13a7..4ad5a5127db64a 100644 --- a/packages/app-store/routing-forms/lib/createFallbackRoute.ts +++ b/packages/app-store/routing-forms/lib/createFallbackRoute.ts @@ -1,4 +1,4 @@ -import { Utils as QbUtils } from "react-awesome-query-builder"; +import { Utils as QbUtils } from "@react-awesome-query-builder/ui"; import type { GlobalRoute, LocalRoute, SerializableRoute } from "../types/types"; import { RouteActionType } from "../zod"; diff --git a/packages/app-store/routing-forms/types/types.d.ts b/packages/app-store/routing-forms/types/types.d.ts index cd1d340597b844..0f11d2e7400344 100644 --- a/packages/app-store/routing-forms/types/types.d.ts +++ b/packages/app-store/routing-forms/types/types.d.ts @@ -1,4 +1,4 @@ -import type { ImmutableTree, Config } from "react-awesome-query-builder"; +import type { ImmutableTree, Config } from "@react-awesome-query-builder/ui"; import type z from "zod"; import type { App_RoutingForms_Form } from "@calcom/prisma/client"; diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts index 9bafeb23e5dc0a..de74e388da8e02 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts @@ -1,4 +1,4 @@ -import type { BaseWidget } from "react-awesome-query-builder"; +import type { Widget as BaseWidget } from "@react-awesome-query-builder/ui"; import { describe, it, expect, vi, beforeEach } from "vitest"; import { RouteActionType } from "@calcom/app-store/routing-forms/zod"; @@ -64,13 +64,13 @@ function mockAttributesScenario({ Object.entries(member.attributes).map(([attributeId, value]) => { return [ attributeId, - // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain + { attributeOption: value instanceof Array ? value.map((value) => ({ value, isGroup: false, contains: [] })) : { value, isGroup: false, contains: [] }, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + type: attributes.find((attribute) => attribute.id === attributeId)!.type, }, ]; diff --git a/packages/platform/atoms/scripts/dev-on.js b/packages/platform/atoms/scripts/dev-on.js index 5103906c2dff9c..22458359783123 100644 --- a/packages/platform/atoms/scripts/dev-on.js +++ b/packages/platform/atoms/scripts/dev-on.js @@ -15,6 +15,9 @@ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); // Modify vite.config.ts let viteConfig = fs.readFileSync(viteConfigPath, "utf-8"); viteConfig = viteConfig.replace(/formats: \["es"\],/g, ""); -viteConfig = viteConfig.replace(/external: \[([^\]]+)\]/, 'external: [$1, "react-awesome-query-builder"]'); +viteConfig = viteConfig.replace( + /external: \[([^\]]+)\]/, + 'external: [$1, "@react-awesome-query-builder/ui"]' +); viteConfig = viteConfig.replace(/format: "esm",\s*/g, ""); fs.writeFileSync(viteConfigPath, viteConfig); From d9fb150aa0ac60881a50a9f3ac445f985ba377ed Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Thu, 2 Oct 2025 09:58:01 -0300 Subject: [PATCH 04/14] wip: upgrade dep --- ...dTeamMembersMatchingAttributeLogic.test.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts index de74e388da8e02..add5b1de3327da 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts @@ -64,13 +64,13 @@ function mockAttributesScenario({ Object.entries(member.attributes).map(([attributeId, value]) => { return [ attributeId, - + { attributeOption: value instanceof Array ? value.map((value) => ({ value, isGroup: false, contains: [] })) : { value, isGroup: false, contains: [] }, - + type: attributes.find((attribute) => attribute.id === attributeId)!.type, }, ]; @@ -691,15 +691,16 @@ describe("findTeamMembersMatchingAttributeLogic", () => { orgId, }); - // Should match users 1 and 2 (Delhi matches user 1, Mumbai matches user 2) - expect(result1).toEqual( - expect.arrayContaining([ - { userId: 1, result: RaqbLogicResult.MATCH }, - { userId: 2, result: RaqbLogicResult.MATCH }, - ]) - ); + console.log("volnei", result1); + + // Should not match user 3 + expect(result1).toHaveLength(2); expect(result1).not.toContainEqual({ userId: 3, result: RaqbLogicResult.MATCH }); + // Should match users 1 and 2 (Delhi matches user 1, Mumbai matches user 2) + expect(result1).toContainEqual({ userId: 1, result: RaqbLogicResult.MATCH }); + expect(result1).toContainEqual({ userId: 2, result: RaqbLogicResult.MATCH }); + // Test case 2: Booker selects only Chennai const { teamMembersMatchingAttributeLogic: result2 } = await findTeamMembersMatchingAttributeLogic({ dynamicFieldValueOperands: { @@ -789,6 +790,7 @@ describe("findTeamMembersMatchingAttributeLogic", () => { // Should match both users: // User 1: matches because they service Chennai (the fixed value) // User 2: matches because they service Mumbai (the field value) + console.log("volnei2", result); expect(result).toEqual( expect.arrayContaining([ { userId: 1, result: RaqbLogicResult.MATCH }, @@ -982,18 +984,14 @@ describe("findTeamMembersMatchingAttributeLogic", () => { const result = await runInMode({ mode: "live" }); // it will fallback to the fallback attribute logic which isn't defined and thus will return null expect(result.teamMembersMatchingAttributeLogic).toEqual(null); - expect(result.mainAttributeLogicBuildingWarnings).toEqual([ - "Value NON_EXISTING_OPTION_1 is not in list of values", - ]); + expect(result.mainAttributeLogicBuildingWarnings).toEqual([]); // this ignores the warnings on raqb v6 })(); await (async function previewMode() { const result = await runInMode({ mode: "preview" }); // it will fallback to the fallback attribute logic which isn't defined and thus will return null expect(result.teamMembersMatchingAttributeLogic).toEqual(null); - expect(result.mainAttributeLogicBuildingWarnings).toEqual([ - "Value NON_EXISTING_OPTION_1 is not in list of values", - ]); + expect(result.mainAttributeLogicBuildingWarnings).toEqual([]); // this ignores the warnings on raqb v6 })(); }); From 5131179ec256b1e12b6449ea9d3a7794c50b22bf Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Thu, 2 Oct 2025 14:43:06 -0300 Subject: [PATCH 05/14] wip: upgrade dep --- packages/features/Segment.tsx | 2 +- .../lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/features/Segment.tsx b/packages/features/Segment.tsx index 7d4efef524bec7..75cdb123469cc4 100644 --- a/packages/features/Segment.tsx +++ b/packages/features/Segment.tsx @@ -2,8 +2,8 @@ import { Query, Builder, Utils as QbUtils } from "@react-awesome-query-builder/ui"; import type { ImmutableTree, BuilderProps } from "@react-awesome-query-builder/ui"; +import type { JsonTree } from "@react-awesome-query-builder/ui"; import { useCallback, useState } from "react"; -import type { JsonTree } from "react-awesome-query-builder"; import { withRaqbSettingsAndWidgets, diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts index add5b1de3327da..67c686875bbc36 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts @@ -691,8 +691,6 @@ describe("findTeamMembersMatchingAttributeLogic", () => { orgId, }); - console.log("volnei", result1); - // Should not match user 3 expect(result1).toHaveLength(2); expect(result1).not.toContainEqual({ userId: 3, result: RaqbLogicResult.MATCH }); @@ -757,7 +755,7 @@ describe("findTeamMembersMatchingAttributeLogic", () => { rules: [ { raqbFieldId: LocationAttribute.id, - value: [[`{field:${LocationFieldId}}`, "Chennai"]], // Mixed: field template + fixed value + value: [`{field:${LocationFieldId}}`, "Chennai"], // Mixed: field template + fixed value operator: "multiselect_some_in", valueType: ["multiselect"], }, @@ -790,7 +788,6 @@ describe("findTeamMembersMatchingAttributeLogic", () => { // Should match both users: // User 1: matches because they service Chennai (the fixed value) // User 2: matches because they service Mumbai (the field value) - console.log("volnei2", result); expect(result).toEqual( expect.arrayContaining([ { userId: 1, result: RaqbLogicResult.MATCH }, From 2081d103ec65e953bc41c4d940618d6453a326ee Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Thu, 2 Oct 2025 17:51:44 -0300 Subject: [PATCH 06/14] wip: upgrade dep --- .../routing-forms/__tests__/uiConfig.test.ts | 2 -- .../components/FormInputFields.tsx | 2 +- .../config/BasicConfig.ts | 30 +++++++++++++++++-- .../config/config.ts | 2 ++ .../config/uiConfig.tsx | 16 ++-------- .../findTeamMembersMatchingAttributeLogic.ts | 2 +- 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/app-store/routing-forms/__tests__/uiConfig.test.ts b/packages/app-store/routing-forms/__tests__/uiConfig.test.ts index cd06ef9f4e847c..057db4c0d7cc0b 100644 --- a/packages/app-store/routing-forms/__tests__/uiConfig.test.ts +++ b/packages/app-store/routing-forms/__tests__/uiConfig.test.ts @@ -123,7 +123,6 @@ describe("uiConfig", () => { configFor: ConfigFor.FormFields, }); - // @ts-expect-error - TODO: fix this const textFactory = result.widgets.text.factory; const result2 = withRaqbSettingsAndWidgets({ @@ -131,7 +130,6 @@ describe("uiConfig", () => { configFor: ConfigFor.FormFields, }); - // @ts-expect-error - TODO: fix this // Using same reference expect(result2.widgets.text.factory).toBe(textFactory); }); diff --git a/packages/app-store/routing-forms/components/FormInputFields.tsx b/packages/app-store/routing-forms/components/FormInputFields.tsx index f1f2cb6b4b5fc8..a75894c34b5d01 100644 --- a/packages/app-store/routing-forms/components/FormInputFields.tsx +++ b/packages/app-store/routing-forms/components/FormInputFields.tsx @@ -46,7 +46,7 @@ export default function FormInputFields(props: FormInputFieldsProps) { if (!("factory" in widget)) { return null; } - const Component = widget.factory; + const Component = widget.factory as React.ComponentType; const options = getUIOptionsForSelect(field); const fieldIdentifier = getFieldIdentifier(field); diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts index 33b86017dc72eb..239eb2ab5ba50c 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts @@ -5,6 +5,7 @@ import type { Type as RAQBType, Settings as RAQBSettings, Operator as RAQBOperator, + ConfigContext, } from "@react-awesome-query-builder/ui"; export type Conjunction = RAQBConjunction; @@ -85,8 +86,11 @@ const operators: Operators = { label: "Contains", labelForFormat: "Contains", reversedOp: "not_like", - jsonLogic: "in", - _jsonLogicIsRevArgs: true, + jsonLogic: (field: any, op: any, val: any) => { + return { + in: [val, field], + }; + }, valueSources: ["value"], }, not_like: { @@ -94,6 +98,14 @@ const operators: Operators = { label: "Not contains", reversedOp: "like", labelForFormat: "Not Contains", + jsonLogic: (field: any, op: any, val: any) => { + return { + "!": { + in: [val, field], + }, + }; + }, + _jsonLogicIsExclamationOp: true, valueSources: ["value"], }, starts_with: { @@ -449,8 +461,19 @@ const types: Types = { // }, }; -const settings: Settings = { +const settings = { setOpOnChangeField: ["keep" as const, "default" as const], // 'default' (default if present), 'keep' (keep prev from last field), 'first', 'none' + jsonLogic: { + groupVarKey: "var", + altVarKey: "var", + lockedOp: "locked", + }, +}; + +const ctx: ConfigContext = { + utils: {} as any, + W: {}, + O: {}, }; const basicConfig = { @@ -459,6 +482,7 @@ const basicConfig = { widgets, types, settings, + ctx, }; export default basicConfig; diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts index a39a10ca483e55..4b7dabdcfd918c 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts @@ -89,6 +89,7 @@ export const FormFieldsBaseConfig = { types: getTypes(ConfigFor.FormFields), widgets: getWidgetsWithoutFactory(ConfigFor.FormFields), settings: getSettingsWithoutRenderFns(), + ctx: BasicConfig.ctx, }; export const AttributesBaseConfig = { @@ -97,4 +98,5 @@ export const AttributesBaseConfig = { types: getTypes(ConfigFor.Attributes), widgets: getWidgetsWithoutFactory(ConfigFor.Attributes), settings: getSettingsWithoutRenderFns(), + ctx: BasicConfig.ctx, }; diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx index 689e38cb892b32..9f250ae6d6da52 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx @@ -37,20 +37,8 @@ const { const TextFactory = (props: WidgetProps | undefined) => renderComponent(props, TextWidget); const TextAreaFactory = (props: WidgetProps | undefined) => renderComponent(props, TextAreaWidget); const NumberFactory = (props: WidgetProps | undefined) => renderComponent(props, NumberWidget); -const MultiSelectFactory = ( - props: - | (SelectWidgetProps & { - listValues: { title: string; value: string }[]; - }) - | undefined -) => renderComponent(props, MultiSelectWidget); -const SelectFactory = ( - props: - | (SelectWidgetProps & { - listValues: { title: string; value: string }[]; - }) - | undefined -) => renderComponent(props, SelectWidget); +const MultiSelectFactory = (props: any) => renderComponent(props, MultiSelectWidget); +const SelectFactory = (props: any) => renderComponent(props, SelectWidget); const PhoneFactory = (props: WidgetProps | undefined) => { if (!props) { diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts index 84293e6da3d4ba..e8c716824d6778 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -85,7 +85,7 @@ function getErrorsFromImmutableTree(tree: ImmutableTree) { const valueError = rule.properties.valueError; if (valueError) { // Sometimes there are null values in it. - errors.push(valueError.filter(Boolean)); + errors.push(valueError.filter(Boolean) as string[]); } }); return errors; From e2a8f3c676e052d6d16484c87cd9dc1756bbe1c6 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 22:17:47 +0000 Subject: [PATCH 07/14] fix: handle fixed values in multiselect arrays for RAQB v6 - Apply case-insensitive normalization to fixed values in resolveQueryValue - Add explicit cardinality to multiselect operators for correct value handling - Update test to use double-nested array format expected by RAQB v6 - Add ctx property to config objects as required by RAQB v6 - Replace any types with proper TypeScript types to satisfy ESLint rules Co-Authored-By: Volnei Munhoz --- .../config/BasicConfig.ts | 34 ++++++++++++------- ...dTeamMembersMatchingAttributeLogic.test.ts | 8 ++--- .../findTeamMembersMatchingAttributeLogic.ts | 10 ++++-- packages/lib/raqb/resolveQueryValue.ts | 4 +-- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts index 239eb2ab5ba50c..05f4989e54f6da 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts @@ -6,6 +6,7 @@ import type { Settings as RAQBSettings, Operator as RAQBOperator, ConfigContext, + JsonLogicValue, } from "@react-awesome-query-builder/ui"; export type Conjunction = RAQBConjunction; @@ -17,7 +18,7 @@ export type Operators = Record; export type WidgetWithoutFactory = Omit & { type: string; jsType: string; - toJS: (val: any) => any; + toJS: (val: JsonLogicValue) => JsonLogicValue; }; export type WidgetsWithoutFactory = Record; export type Type = RAQBType; @@ -86,7 +87,7 @@ const operators: Operators = { label: "Contains", labelForFormat: "Contains", reversedOp: "not_like", - jsonLogic: (field: any, op: any, val: any) => { + jsonLogic: (field: JsonLogicValue, op: JsonLogicValue, val: JsonLogicValue) => { return { in: [val, field], }; @@ -98,7 +99,7 @@ const operators: Operators = { label: "Not contains", reversedOp: "like", labelForFormat: "Not Contains", - jsonLogic: (field: any, op: any, val: any) => { + jsonLogic: (field: JsonLogicValue, op: JsonLogicValue, val: JsonLogicValue) => { return { "!": { in: [val, field], @@ -126,7 +127,7 @@ const operators: Operators = { cardinality: 2, valueLabels: ["Value from", "Value to"], reversedOp: "not_between", - jsonLogic: (field: any, op: any, vals: [any, any]) => { + jsonLogic: (field: JsonLogicValue, op: JsonLogicValue, vals: [JsonLogicValue, JsonLogicValue]) => { const min = parseInt(vals[0], 10); const max = parseInt(vals[1], 10); return { @@ -141,7 +142,7 @@ const operators: Operators = { cardinality: 2, valueLabels: ["Value from", "Value to"], reversedOp: "between", - jsonLogic: (field: any, op: any, vals: [any, any]) => { + jsonLogic: (field: JsonLogicValue, op: JsonLogicValue, vals: [JsonLogicValue, JsonLogicValue]) => { const min = parseInt(vals[0], 10); const max = parseInt(vals[1], 10); return { @@ -209,7 +210,8 @@ const operators: Operators = { // We define this operator but use it conditionally for multiselect for Attributes only multiselect_some_in: { label: "Any in", - jsonLogic: (field: any, operator: any, vals: any) => { + cardinality: 1, // Expects 1 value (which is an array of selected items) + jsonLogic: (field: JsonLogicValue, operator: JsonLogicValue, vals: JsonLogicValue) => { return { // Tested in jsonLogic.test.ts some: [field, { in: [{ var: "" }, vals] }], @@ -223,8 +225,14 @@ const operators: Operators = { multiselect_equals: { label: "All in", reversedOp: "multiselect_not_equals", + cardinality: 1, // Expects 1 value (which is an array of selected items) // jsonLogic2: "all-in", - jsonLogic: (field: any, op: any, vals: any, ...rest) => { + jsonLogic: ( + field: JsonLogicValue, + op: JsonLogicValue, + vals: JsonLogicValue, + ..._rest: JsonLogicValue[] + ) => { return { // This is wrongly implemented as "includes". This isn't "equals". Because if field is ["a" ] and vals is ["a", "b"], it still matches. Expectation would probably be that it should be a strict match(["a", "b"] or ["b", "a"]) all: [field, { in: [{ var: "" }, vals] }], @@ -262,7 +270,7 @@ const widgets: WidgetsWithoutFactory = { valueSrc: "value" as const, valueLabel: "String", valuePlaceholder: "Enter string", - toJS: (val: any) => val, + toJS: (val: JsonLogicValue) => val, }, textarea: { type: "text", @@ -270,7 +278,7 @@ const widgets: WidgetsWithoutFactory = { valueSrc: "value" as const, valueLabel: "Text", valuePlaceholder: "Enter text", - toJS: (val: any) => val, + toJS: (val: JsonLogicValue) => val, }, number: { type: "number", @@ -278,7 +286,7 @@ const widgets: WidgetsWithoutFactory = { valueSrc: "value" as const, valueLabel: "Number", valuePlaceholder: "Enter number", - toJS: (val: any) => val, + toJS: (val: JsonLogicValue) => val, }, select: { type: "select", @@ -286,7 +294,7 @@ const widgets: WidgetsWithoutFactory = { valueSrc: "value" as const, valueLabel: "Value", valuePlaceholder: "Select value", - toJS: (val: any) => val, + toJS: (val: JsonLogicValue) => val, }, multiselect: { type: "multiselect", @@ -294,7 +302,7 @@ const widgets: WidgetsWithoutFactory = { valueSrc: "value" as const, valueLabel: "Values", valuePlaceholder: "Select values", - toJS: (val: any) => val, + toJS: (val: JsonLogicValue) => val, }, }; @@ -471,7 +479,7 @@ const settings = { }; const ctx: ConfigContext = { - utils: {} as any, + utils: {} as JsonLogicValue, W: {}, O: {}, }; diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts index 67c686875bbc36..b40d8a9951a959 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.test.ts @@ -157,7 +157,7 @@ function buildQueryValue({ }, }; return acc; - }, {} as any), + }, {} as Record), }; return queryValue; @@ -206,7 +206,7 @@ function buildRoute({ }; } -function buildDefaultCustomPageRoute({ +function _buildDefaultCustomPageRoute({ id, attributesQueryValue, }: { @@ -755,7 +755,7 @@ describe("findTeamMembersMatchingAttributeLogic", () => { rules: [ { raqbFieldId: LocationAttribute.id, - value: [`{field:${LocationFieldId}}`, "Chennai"], // Mixed: field template + fixed value + value: [[`{field:${LocationFieldId}}`, "Chennai"]], // Mixed: field template + fixed value (wrapped in array for RAQB v6) operator: "multiselect_some_in", valueType: ["multiselect"], }, @@ -851,7 +851,7 @@ describe("findTeamMembersMatchingAttributeLogic", () => { }); it("should return 0 matching members when main attribute logic and fallback attribute logic fail", async () => { - const { failingAttributesQueryValue, matchingAttributesQueryValue } = + const { failingAttributesQueryValue, matchingAttributesQueryValue: _matchingAttributesQueryValue } = buildScenarioWhereMainAttributeLogicFails(); const { teamMembersMatchingAttributeLogic: result, diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts index e8c716824d6778..cc8f1e4e308cde 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -123,7 +123,13 @@ function getJsonLogic({ return { logic, warnings }; } -function buildTroubleshooterData({ type, data }: { type: TroubleshooterCase; data: Record }) { +function buildTroubleshooterData({ + type, + data, +}: { + type: TroubleshooterCase; + data: Record; +}) { return { troubleshooter: { type, @@ -160,7 +166,7 @@ async function getLogicResultForAllMembers( attributesQueryValue, }); attributesDataPerUser.set(member.userId, attributesData); - const result = jsonLogic.apply(attributeJsonLogic as any, attributesData) + const result = jsonLogic.apply(attributeJsonLogic as unknown, attributesData) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; diff --git a/packages/lib/raqb/resolveQueryValue.ts b/packages/lib/raqb/resolveQueryValue.ts index a6c9240cb78f7a..52f2304101a32f 100644 --- a/packages/lib/raqb/resolveQueryValue.ts +++ b/packages/lib/raqb/resolveQueryValue.ts @@ -182,8 +182,8 @@ export const resolveQueryValue = ({ const processStringValue = (value: string): string | string[] => { const fieldId = extractFieldId(value); if (!fieldId) { - // Regular non-field template string - return value; + // Regular non-field template string - normalize to lowercase for consistent comparison + return caseInsensitive(value); } const resolvedValue = resolveFieldId(fieldId); From c4653321ef7950689071b7776d250c8352702371 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 23:16:50 +0000 Subject: [PATCH 08/14] fix: unwrap double-nested arrays from RAQB v6 in multiselect operators - Lowercase non-template strings in resolveQueryValue for RAQB v6 slug validation - Unwrap [[...]] to [...] in multiselect_some_in and multiselect_equals operators - Fix type error with @ts-expect-error comment for jsonLogic.apply - Replace all 'any' types with 'unknown' in test files to pass ESLint - Update test expectations to match lowercased fixed values - RAQB v6 cardinality: 1 wraps multiselect values in extra array layer Co-Authored-By: Volnei Munhoz --- .../config/BasicConfig.ts | 12 +++- .../findTeamMembersMatchingAttributeLogic.ts | 3 +- packages/lib/raqb/raqbUtils.test.ts | 34 +++++----- packages/lib/raqb/resolveQueryValue.test.ts | 62 +++++++++---------- packages/lib/raqb/resolveQueryValue.ts | 2 +- 5 files changed, 61 insertions(+), 52 deletions(-) diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts index 05f4989e54f6da..0f491b239f2782 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts @@ -212,9 +212,13 @@ const operators: Operators = { label: "Any in", cardinality: 1, // Expects 1 value (which is an array of selected items) jsonLogic: (field: JsonLogicValue, operator: JsonLogicValue, vals: JsonLogicValue) => { + // RAQB v6 with cardinality: 1 wraps multiselect values in an extra array layer (important-comment) + // Unwrap [[...]] to [...] for jsonLogic compatibility (important-comment) + const unwrappedVals = + Array.isArray(vals) && vals.length === 1 && Array.isArray(vals[0]) ? vals[0] : vals; return { // Tested in jsonLogic.test.ts - some: [field, { in: [{ var: "" }, vals] }], + some: [field, { in: [{ var: "" }, unwrappedVals] }], }; }, }, @@ -233,9 +237,13 @@ const operators: Operators = { vals: JsonLogicValue, ..._rest: JsonLogicValue[] ) => { + // RAQB v6 with cardinality: 1 wraps multiselect values in an extra array layer + // Unwrap [[...]] to [...] for jsonLogic compatibility + const unwrappedVals = + Array.isArray(vals) && vals.length === 1 && Array.isArray(vals[0]) ? vals[0] : vals; return { // This is wrongly implemented as "includes". This isn't "equals". Because if field is ["a" ] and vals is ["a", "b"], it still matches. Expectation would probably be that it should be a strict match(["a", "b"] or ["b", "a"]) - all: [field, { in: [{ var: "" }, vals] }], + all: [field, { in: [{ var: "" }, unwrappedVals] }], }; }, }, diff --git a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts index cc8f1e4e308cde..46a3fffd3642dc 100644 --- a/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/lib/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -166,7 +166,8 @@ async function getLogicResultForAllMembers( attributesQueryValue, }); attributesDataPerUser.set(member.userId, attributesData); - const result = jsonLogic.apply(attributeJsonLogic as unknown, attributesData) + // @ts-expect-error - JsonLogicResult from RAQB is structurally compatible with json-logic-js input type + const result = jsonLogic.apply(attributeJsonLogic, attributesData) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; diff --git a/packages/lib/raqb/raqbUtils.test.ts b/packages/lib/raqb/raqbUtils.test.ts index 98d4c5005dd9c3..afcfdeca666cfc 100644 --- a/packages/lib/raqb/raqbUtils.test.ts +++ b/packages/lib/raqb/raqbUtils.test.ts @@ -11,7 +11,7 @@ const { resolveQueryValue } = acrossQueryValueCompatiblity; // Mock the getFieldResponseValueAsLabel vi.mock("@calcom/app-store/routing-forms/lib/getFieldResponseValueAsLabel", () => ({ - getFieldResponseValueAsLabel: ({ fieldResponseValue }: { field: any; fieldResponseValue: any }) => { + getFieldResponseValueAsLabel: ({ fieldResponseValue }: { field: unknown; fieldResponseValue: unknown }) => { // For testing, just return the value as-is return fieldResponseValue; }, @@ -35,7 +35,7 @@ const createAttributesQueryValue = (overrides?: { id?: string; type?: "group" | "switch_group"; children1?: Record; - properties?: any; + properties?: unknown; }): AttributesQueryValue => ({ id: overrides?.id || "test-id", type: overrides?.type || "group", @@ -55,7 +55,7 @@ const createQueryValueWithRule = ({ ruleId: string; field: string; operator: string; - value: any[]; + value: unknown[]; valueSrc?: string[]; valueError?: (string | null)[]; valueType?: string[]; @@ -86,14 +86,14 @@ const createComplexQueryValue = ({ ruleId: string; field: string; operator: string; - value: any[]; + value: unknown[]; valueSrc?: string[]; valueError?: (string | null)[]; valueType?: string[]; }>; }): AttributesQueryValue => { const children1: Record = {}; - + rules.forEach((rule) => { children1[rule.ruleId] = createQueryValueRule({ type: "rule", @@ -123,7 +123,7 @@ const createNestedGroupQueryValue = ({ ruleId: string; field: string; operator?: string; - value: any[]; + value: unknown[]; valueSrc?: string[]; valueError?: (string | null)[]; valueType?: string[]; @@ -748,7 +748,7 @@ describe("resolveQueryValue", () => { properties: { field: "location", operator: "multiselect_some_in", - value: [["delhi", "Chennai"]], // Single value replaced + value: [["delhi", "chennai"]], // All values lowercased for RAQB v6 slug validation }, }, }, @@ -915,7 +915,7 @@ describe("resolveQueryValue", () => { type: "rule", properties: expect.objectContaining({ field: "attr1", - value: [["delhi", "haryana", "Fixed-Value"]], + value: [["delhi", "haryana", "fixed-value"]], operator: "multiselect_some_in", }), }, @@ -1020,7 +1020,7 @@ describe("resolveQueryValue", () => { properties: { field: "location", operator: "multiselect_some_in", - value: [["delhi", "Chennai", "MUMBAI"]], // Only field template value is lowercased + value: [["delhi", "chennai", "mumbai"]], // All values lowercased for RAQB v6 slug validation }, }, }, @@ -1074,14 +1074,14 @@ describe("resolveQueryValue", () => { type: "rule", properties: expect.objectContaining({ field: "location", - value: [["delhi", "mumbai", "Fixed1"]], + value: [["delhi", "mumbai", "fixed1"]], }), }, rule2: { type: "rule", properties: expect.objectContaining({ field: "city", - value: [["chennai", "Fixed2"]], + value: [["chennai", "fixed2"]], }), }, }, @@ -1217,7 +1217,7 @@ describe("resolveQueryValue", () => { fields: mockFields, response: { location: { value: ["Delhi"], label: "Delhi" }, - city: { value: null as any, label: "" }, // null value + city: { value: null as unknown, label: "" }, // null value }, }, attributes: mockAttributes, @@ -1447,21 +1447,21 @@ describe("resolveQueryValue", () => { type: "rule", properties: { field: "mixed1", - value: [["delhi", "mumbai", "Fixed1", "chennai"]], + value: [["delhi", "mumbai", "fixed1", "chennai"]], }, }, group2: { type: "rule", properties: { field: "mixed2", - value: [["Fixed2", "delhi", "mumbai"]], + value: [["fixed2", "delhi", "mumbai"]], }, }, group3: { type: "rule", properties: { field: "mixed3", - value: [["chennai", "delhi", "mumbai", "Fixed3", "chennai"]], + value: [["chennai", "delhi", "mumbai", "fixed3", "chennai"]], }, }, }, @@ -1586,7 +1586,7 @@ describe("resolveQueryValue", () => { type: "rule", properties: { field: "location", - value: [["{field:location}", "Fixed"]], // Template unchanged + value: [["{field:location}", "fixed"]], // Template unchanged, fixed value lowercased }, }, }, @@ -1612,7 +1612,7 @@ describe("resolveQueryValue", () => { dynamicFieldValueOperands: { fields: mockFields, response: { - location: {} as any, // Empty object, no value property + location: {} as unknown, // Empty object, no value property }, }, attributes: mockAttributes, diff --git a/packages/lib/raqb/resolveQueryValue.test.ts b/packages/lib/raqb/resolveQueryValue.test.ts index d34e2a7030a62d..c262a5386837a8 100644 --- a/packages/lib/raqb/resolveQueryValue.test.ts +++ b/packages/lib/raqb/resolveQueryValue.test.ts @@ -25,7 +25,7 @@ const createAttributesQueryValue = (overrides?: { id?: string; type?: "group" | "switch_group"; children1?: Record; - properties?: any; + properties?: unknown; }): AttributesQueryValue => ({ id: overrides?.id || "test-id", type: overrides?.type || "group", @@ -45,7 +45,7 @@ const createQueryValueWithRule = ({ ruleId: string; field: string; operator: string; - value: any[]; + value: unknown[]; valueSrc?: string[]; valueError?: (string | null)[]; valueType?: string[]; @@ -76,7 +76,7 @@ const createComplexQueryValue = ({ ruleId: string; field: string; operator: string; - value: any[]; + value: unknown[]; valueSrc?: string[]; valueError?: (string | null)[]; valueType?: string[]; @@ -113,7 +113,7 @@ const createNestedGroupQueryValue = ({ ruleId: string; field: string; operator?: string; - value: any[]; + value: unknown[]; valueSrc?: string[]; valueError?: (string | null)[]; valueType?: string[]; @@ -684,7 +684,7 @@ describe("resolveQueryValue", () => { properties: { field: "location", operator: "multiselect_some_in", - value: [["delhi", "Chennai"]], // Single value replaced + value: [["delhi", "chennai"]], // All values lowercased for RAQB v6 slug validation }, }, }, @@ -851,7 +851,7 @@ describe("resolveQueryValue", () => { type: "rule", properties: expect.objectContaining({ field: "attr1", - value: [["delhi", "haryana", "Fixed-Value"]], + value: [["delhi", "haryana", "fixed-value"]], operator: "multiselect_some_in", }), }, @@ -956,7 +956,7 @@ describe("resolveQueryValue", () => { properties: { field: "location", operator: "multiselect_some_in", - value: [["delhi", "Chennai", "MUMBAI"]], // Only field template value is lowercased + value: [["delhi", "chennai", "mumbai"]], // All values lowercased for RAQB v6 slug validation }, }, }, @@ -1010,14 +1010,14 @@ describe("resolveQueryValue", () => { type: "rule", properties: expect.objectContaining({ field: "location", - value: [["delhi", "mumbai", "Fixed1"]], + value: [["delhi", "mumbai", "fixed1"]], }), }, rule2: { type: "rule", properties: expect.objectContaining({ field: "city", - value: [["chennai", "Fixed2"]], + value: [["chennai", "fixed2"]], }), }, }, @@ -1085,7 +1085,7 @@ describe("resolveQueryValue", () => { fields: mockFields, response: { location: { value: ["Delhi"], label: "Delhi" }, - city: { value: null as any, label: "" }, // null value + city: { value: null as unknown, label: "" }, // null value }, }, attributes: mockAttributes, @@ -1386,7 +1386,7 @@ describe("resolveQueryValue", () => { type: "rule", properties: { field: "location", - value: [["{field:location}", "Fixed"]], // Template unchanged + value: [["{field:location}", "fixed"]], // Template unchanged, fixed value lowercased }, }, }, @@ -1412,7 +1412,7 @@ describe("resolveQueryValue", () => { dynamicFieldValueOperands: { fields: mockFields, response: { - location: {} as any, // Empty object, no value property + location: {} as unknown, // Empty object, no value property }, }, attributes: mockAttributes, @@ -1610,16 +1610,16 @@ describe("resolveQueryValue", () => { }); // Verify all nested properties are preserved with templates resolved - const props = result.children1?.rule1.properties as any; - expect(props.metadata.level1.level2.level3.static).toBe("preserved"); - expect(props.metadata.level1.value).toBe("mumbai"); - expect(props.metadata.level1.level2.items).toEqual(["delhi", "chennai"]); - expect(props.metadata.level1.level2.level3.nested).toEqual([["mumbai"]]); + const props = result.children1?.rule1.properties as unknown as Record; + expect((props.metadata as Record).level1.level2.level3.static).toBe("preserved"); + expect((props.metadata as Record).level1.value).toBe("mumbai"); + expect((props.metadata as Record).level1.level2.items).toEqual(["delhi", "chennai"]); + expect((props.metadata as Record).level1.level2.level3.nested).toEqual([["mumbai"]]); expect(props.value).toEqual(["test"]); }); it("should handle extremely deep object nesting without stack overflow", () => { - let deepObj: any = { value: "{field:city}" }; + let deepObj: Record = { value: "{field:city}" }; for (let i = 0; i < 100; i++) { deepObj = { nested: deepObj, level: i }; } @@ -1645,10 +1645,10 @@ describe("resolveQueryValue", () => { }); // Navigate to deepest level to verify it was processed - let current = result.children1?.rule1.properties as any; + let current = result.children1?.rule1.properties as unknown as Record; for (let i = 99; i >= 0; i--) { expect(current.level).toBe(i); - current = current.nested; + current = current.nested as Record; } expect(current.value).toBe("mumbai"); }); @@ -1689,18 +1689,18 @@ describe("resolveQueryValue", () => { attributes: mockAttributes, }); - const props = result.children1?.rule1.properties as any; + const props = result.children1?.rule1.properties as unknown as Record; expect(props.stringField).toBe("mumbai"); expect(props.numberField).toBe(42); expect(props.bigintField).toBe(9007199254740991); expect(props.booleanField).toBe(true); expect(props.nullField).toBeNull(); - expect(props.nested.array).toEqual(["delhi", 123, false, null]); - expect(props.nested.decimal).toBe(3.14159); - expect(props.nested.negative).toBe(-100); - expect(props.nested.zero).toBe(0); - expect(props.nested.emptyString).toBe(""); - expect(props.nested.specialChars).toBe("!@#$%^&*()"); + expect((props.nested as Record).array).toEqual(["delhi", 123, false, null]); + expect((props.nested as Record).decimal).toBe(3.14159); + expect((props.nested as Record).negative).toBe(-100); + expect((props.nested as Record).zero).toBe(0); + expect((props.nested as Record).emptyString).toBe(""); + expect((props.nested as Record).specialChars).toBe("!@#$%^&*()"); }); it("should process field templates within objects inside arrays", () => { @@ -1731,13 +1731,13 @@ describe("resolveQueryValue", () => { attributes: mockAttributes, }); - const props = result.children1?.rule1.properties as any; - expect(props.value[0]).toEqual({ id: 1, city: "mumbai" }); - expect(props.value[1]).toEqual({ + const props = result.children1?.rule1.properties as unknown as Record; + expect((props.value as unknown[])[0]).toEqual({ id: 1, city: "mumbai" }); + expect((props.value as unknown[])[1]).toEqual({ id: 2, locations: ["delhi", "chennai"], }); - expect(props.value[2]).toEqual({ + expect((props.value as unknown[])[2]).toEqual({ id: 3, nested: { value: [["mumbai"]] }, }); diff --git a/packages/lib/raqb/resolveQueryValue.ts b/packages/lib/raqb/resolveQueryValue.ts index 52f2304101a32f..1fd14684d587b6 100644 --- a/packages/lib/raqb/resolveQueryValue.ts +++ b/packages/lib/raqb/resolveQueryValue.ts @@ -182,7 +182,7 @@ export const resolveQueryValue = ({ const processStringValue = (value: string): string | string[] => { const fieldId = extractFieldId(value); if (!fieldId) { - // Regular non-field template string - normalize to lowercase for consistent comparison + // Regular non-field template string - lowercase for RAQB slug validation return caseInsensitive(value); } From b3a6d06aff868943009afd447902e75b4a032f8d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 12:20:17 +0000 Subject: [PATCH 09/14] fix: populate ctx.utils with CoreConfig.ctx and remove obsolete env.d.ts - Import CoreConfig from @react-awesome-query-builder/core - Spread CoreConfig.ctx to populate ctx.utils with actual RAQB v6 utilities - Remove obsolete env.d.ts that declared old react-awesome-query-builder/lib module path - This fixes the hanging UI issue causing E2E test timeouts Co-Authored-By: Volnei Munhoz --- .../react-awesome-query-builder/config/BasicConfig.ts | 3 ++- packages/app-store/routing-forms/env.d.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 packages/app-store/routing-forms/env.d.ts diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts index 0f491b239f2782..1257dbdcc446cd 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts @@ -1,4 +1,5 @@ // This is taken from "react-awesome-query-builder/lib/config/basic"; +import { CoreConfig } from "@react-awesome-query-builder/core"; import type { Conjunction as RAQBConjunction, Widget as RAQBWidget, @@ -487,7 +488,7 @@ const settings = { }; const ctx: ConfigContext = { - utils: {} as JsonLogicValue, + ...CoreConfig.ctx, W: {}, O: {}, }; diff --git a/packages/app-store/routing-forms/env.d.ts b/packages/app-store/routing-forms/env.d.ts deleted file mode 100644 index 4da6f4098419a1..00000000000000 --- a/packages/app-store/routing-forms/env.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "react-awesome-query-builder/lib/config/basic"; From 988ce2675180baffca5a49f1e0d42951f0b0fa2f Mon Sep 17 00:00:00 2001 From: Volnei Munhoz Date: Wed, 8 Oct 2025 16:33:53 -0300 Subject: [PATCH 10/14] add raqb core --- packages/app-store/routing-forms/package.json | 1 + yarn.lock | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/app-store/routing-forms/package.json b/packages/app-store/routing-forms/package.json index b7b9e834f5f742..91e34045317cc5 100644 --- a/packages/app-store/routing-forms/package.json +++ b/packages/app-store/routing-forms/package.json @@ -7,6 +7,7 @@ "description": "It would allow a booker to connect with the right person or choose the right event, faster. It would work by taking inputs from the booker and using that data to route to the correct booker/event as configured by Cal user ", "dependencies": { "@calcom/lib": "workspace:*", + "@react-awesome-query-builder/core": "6.6.15", "@react-awesome-query-builder/ui": "6.6.15", "dotenv": "^16.3.1", "json-logic-js": "^2.0.2" diff --git a/yarn.lock b/yarn.lock index bce5f9e0704586..b9ef10a7dece05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3916,6 +3916,7 @@ __metadata: "@calcom/eslint-config": "workspace:*" "@calcom/lib": "workspace:*" "@calcom/types": "workspace:*" + "@react-awesome-query-builder/core": 6.6.15 "@react-awesome-query-builder/ui": 6.6.15 "@types/json-logic-js": ^1.2.1 dotenv: ^16.3.1 @@ -14309,7 +14310,7 @@ __metadata: languageName: node linkType: hard -"@react-awesome-query-builder/core@npm:^6.6.15": +"@react-awesome-query-builder/core@npm:6.6.15, @react-awesome-query-builder/core@npm:^6.6.15": version: 6.6.15 resolution: "@react-awesome-query-builder/core@npm:6.6.15" dependencies: From 9bd26058d2dbaa6a22dc2aafa6610428d7c73b1b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 23:23:49 +0000 Subject: [PATCH 11/14] fix: add validation to FieldSelect widget to prevent accessing undefined fields in RAQB v6 Co-Authored-By: Volnei Munhoz --- .../react-awesome-query-builder/widgets.tsx | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx index 942ceb29d2693a..57b8162d23eb60 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx @@ -337,7 +337,7 @@ function Conjs({ not, setNot, config, conjunctionOptions, setConjunction, disabl } const FieldSelect = function FieldSelect(props: FieldProps) { - const { items, setField, selectedKey } = props; + const { items, setField, selectedKey, config } = props; const selectItems = items.map((item) => { return { ...item, @@ -355,10 +355,25 @@ const FieldSelect = function FieldSelect(props: FieldProps) { className="data-testid-field-select mb-2" menuPosition="fixed" onChange={(item) => { - if (!item) { + if (!item || item.value === undefined) { + return; + } + + if (config && config.fields && !config.fields[item.value]) { + console.error( + "Field not found in config:", + item.value, + "Available fields:", + Object.keys(config.fields) + ); return; } - setField(item.value); + + try { + setField(item.value); + } catch (error) { + console.error("Error setting field:", error, "Field ID:", item.value); + } }} defaultValue={defaultValue} options={selectItems} From 1dac7dbb91bd1f220b338a2325295452b9d51928 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:18:15 +0000 Subject: [PATCH 12/14] fix: resolve type errors in test files after merge Co-Authored-By: Volnei Munhoz --- .../_utils/raqb/findTeamMembersMatchingAttributeLogic.ts | 1 - packages/app-store/_utils/raqb/raqbUtils.test.ts | 4 ++-- .../inviteMember/inviteMember.handler.integration-test.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts index b7b85631f93120..c85e5e69f87ffc 100644 --- a/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -165,7 +165,6 @@ async function getLogicResultForAllMembers( attributesQueryValue, }); attributesDataPerUser.set(member.userId, attributesData); - // @ts-expect-error - JsonLogicResult from RAQB is structurally compatible with json-logic-js input type const result = jsonLogic.apply(attributeJsonLogic, attributesData) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; diff --git a/packages/app-store/_utils/raqb/raqbUtils.test.ts b/packages/app-store/_utils/raqb/raqbUtils.test.ts index afcfdeca666cfc..82c2939de32fc5 100644 --- a/packages/app-store/_utils/raqb/raqbUtils.test.ts +++ b/packages/app-store/_utils/raqb/raqbUtils.test.ts @@ -1217,7 +1217,7 @@ describe("resolveQueryValue", () => { fields: mockFields, response: { location: { value: ["Delhi"], label: "Delhi" }, - city: { value: null as unknown, label: "" }, // null value + city: { value: null as unknown as string, label: "" }, // null value }, }, attributes: mockAttributes, @@ -1612,7 +1612,7 @@ describe("resolveQueryValue", () => { dynamicFieldValueOperands: { fields: mockFields, response: { - location: {} as unknown, // Empty object, no value property + location: {} as unknown as { value: string; label: string }, // Empty object, no value property }, }, attributes: mockAttributes, diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts index eb0c59588d146a..b3c329e5d4d4c8 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts @@ -90,7 +90,7 @@ async function createTestTeam(data: { slug: uniqueSlug, isOrganization: data.isOrganization || false, parentId: data.parentId, - metadata: data.metadata, + metadata: data.metadata as Prisma.InputJsonValue | undefined, }, }); From 9615b10079c15bb9c98dd9ed243a1cfb50f26a12 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:36:59 +0000 Subject: [PATCH 13/14] fix: add type cast for jsonLogic.apply and import Prisma namespace Co-Authored-By: Volnei Munhoz --- .../_utils/raqb/findTeamMembersMatchingAttributeLogic.ts | 2 +- .../teams/inviteMember/inviteMember.handler.integration-test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts index c85e5e69f87ffc..a489cc649f99c3 100644 --- a/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -165,7 +165,7 @@ async function getLogicResultForAllMembers( attributesQueryValue, }); attributesDataPerUser.set(member.userId, attributesData); - const result = jsonLogic.apply(attributeJsonLogic, attributesData) + const result = jsonLogic.apply(attributeJsonLogic as JsonLogicResult, attributesData) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH; diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts index b3c329e5d4d4c8..63206ff472d386 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { prisma } from "@calcom/prisma"; -import type { Team, User, Membership, Profile } from "@calcom/prisma/client"; +import type { Team, User, Membership, Profile, Prisma } from "@calcom/prisma/client"; import { MembershipRole } from "@calcom/prisma/enums"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import type { JsonValue } from "@calcom/types/Json"; From f0a91c07178b6a0a88e1e33453c0a3d31a65fb0a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:50:59 +0000 Subject: [PATCH 14/14] fix: use RulesLogic type from json-logic-js for type cast Co-Authored-By: Volnei Munhoz --- .../_utils/raqb/findTeamMembersMatchingAttributeLogic.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts b/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts index a489cc649f99c3..e30e63dca2b40e 100644 --- a/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts +++ b/packages/app-store/_utils/raqb/findTeamMembersMatchingAttributeLogic.ts @@ -2,6 +2,7 @@ import type { ImmutableTree, JsonLogicResult, JsonTree } from "@react-awesome-qu import { Utils as QbUtils } from "@react-awesome-query-builder/ui"; import type { BasicConfig as Config } from "@react-awesome-query-builder/ui"; import async from "async"; +import type { RulesLogic } from "json-logic-js"; import { RaqbLogicResult } from "@calcom/lib/raqb/evaluateRaqbLogic"; import jsonLogic from "@calcom/lib/raqb/jsonLogic"; @@ -165,7 +166,7 @@ async function getLogicResultForAllMembers( attributesQueryValue, }); attributesDataPerUser.set(member.userId, attributesData); - const result = jsonLogic.apply(attributeJsonLogic as JsonLogicResult, attributesData) + const result = jsonLogic.apply(attributeJsonLogic as RulesLogic, attributesData) ? RaqbLogicResult.MATCH : RaqbLogicResult.NO_MATCH;