Repository: erxes/erxes
Pull request #6007: fix(tms): icon filter
Author: login: batorshih
Created: 2025-04-18T01:54:38Z | Merged: 2025-04-18T02:07:18Z

[ISSUE](https://github.com/erxes/erxes/issues/ISSUE)

### Context

Your context here.  Additionally, any screenshots.  Delete this line.


// Delete the below section once completed
### PR Checklist
- [ ] Description is clearly stated under Context section
- [ ] Screenshots and the additional verifications are attached

## Summary by Sourcery

Add icon filter functionality to the BM (Business Management) elements query

New Features:
- Introduce an optional 'icon' boolean parameter to filter elements based on icon availability

Enhancements:
- Extend the bmElements GraphQL query to support filtering elements by icon presence

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Added a new optional filter to the bmElements query, allowing users to filter elements based on the presence of an icon.

- **Style**
  - Updated string formatting for consistency throughout the interface.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts b/packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
index 61789464a95..d81e9e76852 100644
--- a/packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
+++ b/packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
@@ -1,15 +1,15 @@
-import { skip } from 'node:test';
-import { IContext, IModels } from '../../../connectionResolver';
+import { skip } from "node:test";
+import { IContext, IModels } from "../../../connectionResolver";
 import {
   IElement,
   IElementCategory
-} from '../../../models/definitions/element';
+} from "../../../models/definitions/element";
 
 const checkDefaults = async (models: IModels, name: string, icon: string) => {
   const one = await models.Elements.findOne({ name, itineraryId: null });
 
   if (!one) {
-    let element: IElement = { name: name, content: '', quick: true, icon };
+    let element: IElement = { name: name, content: "", quick: true, icon };
     await models.Elements.createElement(element, null);
   } else {
     const abc = await models.Elements.updateElement(one._id, {
@@ -39,134 +39,134 @@ const insertCategoryDefaults = async (
 };
 const LIST_CATEGORIES = [
   {
-    name: 'Accommodation',
+    name: "Accommodation",
     children: [
-      { name: 'Hotel', children: [] },
-      { name: 'Resort' },
-      { name: 'Guesthouse' },
-      { name: 'Vacation Rental' },
-      { name: 'Hostel' },
-      { name: 'Camping' },
-      { name: 'Lodge' },
-      { name: 'Motel' },
-      { name: 'Villa' }
+      { name: "Hotel", children: [] },
+      { name: "Resort" },
+      { name: "Guesthouse" },
+      { name: "Vacation Rental" },
+      { name: "Hostel" },
+      { name: "Camping" },
+      { name: "Lodge" },
+      { name: "Motel" },
+      { name: "Villa" }
     ]
   },
   {
-    name: 'Places',
+    name: "Places",
     children: [
       {
-        name: 'Natural Attractions',
+        name: "Natural Attractions",
         children: [
-          { name: 'Beaches' },
-          { name: 'Mountains' },
-          { name: 'Deserts' },
-          { name: 'Forests & Jungles' },
-          { name: 'Lakes & Rivers' },
-          { name: 'Waterfalls' },
-          { name: 'Islands' }
+          { name: "Beaches" },
+          { name: "Mountains" },
+          { name: "Deserts" },
+          { name: "Forests & Jungles" },
+          { name: "Lakes & Rivers" },
+          { name: "Waterfalls" },
+          { name: "Islands" }
         ]
       },
       {
-        name: 'Cultural & Historical Sites',
+        name: "Cultural & Historical Sites",
         children: [
-          { name: 'Ancient Ruins' },
-          { name: 'Temples & Monasteries' },
-          { name: 'Museums & Art Galleries' },
-          { name: 'Historical Cities' },
-          { name: 'Castles & Palaces' }
+          { name: "Ancient Ruins" },
+          { name: "Temples & Monasteries" },
+          { name: "Museums & Art Galleries" },
+          { name: "Historical Cities" },
+          { name: "Castles & Palaces" }
         ]
       },
       {
-        name: 'Urban Destinations',
+        name: "Urban Destinations",
         children: [
-          { name: 'Metropolitan Cities' },
-          { name: 'Skyscraper Cities' },
-          { name: 'Old Towns & Quarters' },
-          { name: 'Technology Hubs' }
+          { name: "Metropolitan Cities" },
+          { name: "Skyscraper Cities" },
+          { name: "Old Towns & Quarters" },
+          { name: "Technology Hubs" }
         ]
       },
       {
-        name: 'Adventure & Outdoor Recreation',
+        name: "Adventure & Outdoor Recreation",
         children: [
-          { name: 'National Parks' },
-          { name: 'Hiking Trails' },
-          { name: 'Ski Resorts' },
-          { name: 'Diving & Snorkeling Spots' },
-          { name: 'Rock Climbing Destinations' }
+          { name: "National Parks" },
+          { name: "Hiking Trails" },
+          { name: "Ski Resorts" },
+          { name: "Diving & Snorkeling Spots" },
+          { name: "Rock Climbing Destinations" }
         ]
       },
       {
-        name: 'Relaxation & Wellness',
+        name: "Relaxation & Wellness",
         children: [
-          { name: 'Spa Towns' },
-          { name: 'Yoga Retreats' },
-          { name: 'Hot Springs' },
-          { name: 'Quiet Countryside' }
+          { name: "Spa Towns" },
+          { name: "Yoga Retreats" },
+          { name: "Hot Springs" },
+          { name: "Quiet Countryside" }
         ]
       },
       {
-        name: 'Relaxation & Wellness',
+        name: "Relaxation & Wellness",
         children: [
-          { name: 'Spa Towns' },
-          { name: 'Yoga Retreats' },
-          { name: 'Hot Springs' },
-          { name: 'Quiet Countryside' }
+          { name: "Spa Towns" },
+          { name: "Yoga Retreats" },
+          { name: "Hot Springs" },
+          { name: "Quiet Countryside" }
         ]
       }
     ]
   },
   {
-    name: 'Activity',
+    name: "Activity",
     children: [
-      { name: 'Sightseeing' },
-      { name: 'Hiking' },
-      { name: 'Camping' },
-      { name: 'Shopping' },
-      { name: 'Cultural Tours' },
-      { name: 'Food Tours' },
-      { name: 'Adventure Sports' },
-      { name: 'Water Sports' },
-      { name: 'Wildlife Safaris' },
-      { name: 'Skiing/Snowboarding' },
-      { name: 'Beach Activities' },
-      { name: 'City Tours' },
-      { name: 'Boat Tours/Cruises' },
-      { name: 'Photography' }
+      { name: "Sightseeing" },
+      { name: "Hiking" },
+      { name: "Camping" },
+      { name: "Shopping" },
+      { name: "Cultural Tours" },
+      { name: "Food Tours" },
+      { name: "Adventure Sports" },
+      { name: "Water Sports" },
+      { name: "Wildlife Safaris" },
+      { name: "Skiing/Snowboarding" },
+      { name: "Beach Activities" },
+      { name: "City Tours" },
+      { name: "Boat Tours/Cruises" },
+      { name: "Photography" }
     ]
   },
   {
-    name: 'Food & Drink',
+    name: "Food & Drink",
     children: [
-      { name: 'Street Food' },
-      { name: 'Local Cuisine' },
-      { name: 'Fine Dining' },
-      { name: 'Café' },
-      { name: 'Beverages' },
-      { name: 'Desserts and Sweets' },
-      { name: 'Vegetarian/Vegan Options' },
-      { name: 'Food Markets' },
-      { name: 'Picnics and Outdoor Dining' },
-      { name: 'Fast Food' }
+      { name: "Street Food" },
+      { name: "Local Cuisine" },
+      { name: "Fine Dining" },
+      { name: "Café" },
+      { name: "Beverages" },
+      { name: "Desserts and Sweets" },
+      { name: "Vegetarian/Vegan Options" },
+      { name: "Food Markets" },
+      { name: "Picnics and Outdoor Dining" },
+      { name: "Fast Food" }
     ]
   },
 
   {
-    name: 'Location',
+    name: "Location",
     children: [
       {
-        name: 'Mongolia',
+        name: "Mongolia",
         children: [
-          { name: 'Arkhangai' },
-          { name: 'Bayan-Ölgii' },
-          { name: 'Bayankhongor' },
-          { name: 'Bulgan' },
-          { name: 'Darkhan-Uul' },
-          { name: 'Dornod' },
-          { name: 'Dornogovi' },
-          { name: 'Dundgovi' },
-          { name: 'Govi-Altai' },
-          { name: 'Ulaanbaatar' }
+          { name: "Arkhangai" },
+          { name: "Bayan-Ölgii" },
+          { name: "Bayankhongor" },
+          { name: "Bulgan" },
+          { name: "Darkhan-Uul" },
+          { name: "Dornod" },
+          { name: "Dornogovi" },
+          { name: "Dundgovi" },
+          { name: "Govi-Altai" },
+          { name: "Ulaanbaatar" }
         ]
       }
     ]
@@ -183,7 +183,8 @@ const elementQueries = {
       perPage = 10,
       quick,
       sortField,
-      sortDirection
+      sortDirection,
+      icon
     },
     { models }: IContext
   ) {
@@ -206,13 +207,20 @@ const elementQueries = {
 
     if (name) {
       selector.$or = [
-        { name: { $regex: name, $options: 'i' } },
-        { 'location.name': { $regex: name, $options: 'i' } }
+        { name: { $regex: name, $options: "i" } },
+        { "location.name": { $regex: name, $options: "i" } }
       ];
     }
-    if (typeof quick === 'boolean') {
+    if (typeof quick === "boolean") {
       selector.quick = quick;
     }
+    if (typeof icon === "boolean") {
+      if (icon) {
+        selector.quick = { $exists: true };
+      } else {
+        selector.quick = { $exists: false };
+      }
+    }
     if (branchId) {
       selector.branchId = branchId;
     }
@@ -250,22 +258,22 @@ const elementQueries = {
   },
 
   async bmElementsInit(_root, {}, { models }: IContext) {
-    await checkDefaults(models, 'Breakfast', 'soup');
-    await checkDefaults(models, 'Lunch', 'utensils');
-    await checkDefaults(models, 'Dinner', 'utensils');
-    await checkDefaults(models, 'Snack', 'donut');
-    await checkDefaults(models, 'Check-in', 'door-open');
-    await checkDefaults(models, 'Check-out', 'door-closed');
-    await checkDefaults(models, 'Overnight', 'moon');
+    await checkDefaults(models, "Breakfast", "soup");
+    await checkDefaults(models, "Lunch", "utensils");
+    await checkDefaults(models, "Dinner", "utensils");
+    await checkDefaults(models, "Snack", "donut");
+    await checkDefaults(models, "Check-in", "door-open");
+    await checkDefaults(models, "Check-out", "door-closed");
+    await checkDefaults(models, "Overnight", "moon");
 
-    await checkDefaults(models, 'Hot shower', 'moon');
-    await checkDefaults(models, 'unable to shower', 'moon');
-    await checkDefaults(models, 'pick-up service', 'moon');
-    await checkDefaults(models, 'electricity', 'moon');
-    await checkDefaults(models, 'no electricity', 'moon');
-    await checkDefaults(models, 'horse & camel', 'moon');
+    await checkDefaults(models, "Hot shower", "moon");
+    await checkDefaults(models, "unable to shower", "moon");
+    await checkDefaults(models, "pick-up service", "moon");
+    await checkDefaults(models, "electricity", "moon");
+    await checkDefaults(models, "no electricity", "moon");
+    await checkDefaults(models, "horse & camel", "moon");
 
-    return 'ok';
+    return "ok";
   },
   async bmCategoryInit(_root, {}, { models }: IContext) {
     let one: any = null;
@@ -283,14 +291,14 @@ const elementQueries = {
             const t1 = await insertCategoryDefaults(
               models,
               grandChild.name,
-              childOne?._id || ''
+              childOne?._id || ""
             );
           }
         }
       }
     }
 
-    return 'ok';
+    return "ok";
   }
 };
 
diff --git a/packages/plugin-bm-api/src/graphql/schema/element.ts b/packages/plugin-bm-api/src/graphql/schema/element.ts
index 35b844a5847..a5e7996a38e 100644
--- a/packages/plugin-bm-api/src/graphql/schema/element.ts
+++ b/packages/plugin-bm-api/src/graphql/schema/element.ts
@@ -1,4 +1,4 @@
-import gql from 'graphql-tag';
+import gql from "graphql-tag";
 
 export const types = () => `
 
@@ -48,7 +48,7 @@ export const types = () => `
 `;
 
 export const queries = `
-  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int): ListElement
+  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int,icon:Boolean): ListElement
   bmElementDetail(_id:String!): Element
   bmElementCategoryies(parentId:String): [ElementCategory]
   bmElementsInit: JSON
@@ -67,7 +67,8 @@ const params = `
   itineraryId: String,
   location: BMSLocationInput,
   quick: Boolean,
-  branchId: String
+  branchId: String,
+  icon: String
 `;
 
 export const mutations = `


Reviews:
user: login: sourcery-ai[bot]
body: Hey @batorshih - I've reviewed your changes - here's some feedback:

**Overall Comments**:
- Consider adding a unit test for the new `icon` filter functionality.
- The PR description is incomplete; please provide the necessary context and details.

<details>
<summary>Here's what I looked at during the review</summary>

- 🟡 **General issues**: 2 issues found
- 🟢 **Security**: all looks good
- 🟢 **Testing**: all looks good
- 🟢 **Complexity**: all looks good
- 🟢 **Documentation**: all looks good
</details>

***

<details>
<summary>Sourcery is free for open source - if you like our reviews please consider sharing them ✨</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)
- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)

</details>

<sub>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
</sub>
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-18T01:55:26Z
user: login: ellipsis-dev[bot]
body: :x: Changes requested. Reviewed everything up to 16ac8ad1d237eca58ba56d62a757906d8d61a07f in <ellipsistime>1 minute and 35 seconds</ellipsistime>

<details>
<summary>More details</summary>

 - Looked at `360` lines of code in `2` files
 - Skipped `0` files when reviewing.
 - Skipped posting `4` drafted comments based on config settings.


<details>
<summary>1. <code>packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts:217</code></summary>

- **Draft comment:** 
Bug: The icon filter incorrectly sets the selector on the 'quick' field. Likely should be using 'selector.icon = { $exists: true }' (or similar) to filter by icon existence.
- **Reason this comment was not posted:** 
Marked as duplicate.

</details>

<details>
<summary>2. <code>packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts:15</code></summary>

- **Draft comment:** 
STYLE: Unused variable 'abc' from updateElement operation. Consider removing the assignment if not needed.
- **Reason this comment was not posted:** 
Comment was on unchanged code.

</details>

<details>
<summary>3. <code>packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts:245</code></summary>

- **Draft comment:** 
Typographical error: The function name 'bmElementCategoryies' appears to be misspelled. It likely should be 'bmElementCategories'.
- **Reason this comment was not posted:** 
Comment was not on a location in the diff, so it can't be submitted as a review comment.

</details>

<details>
<summary>4. <code>packages/plugin-bm-api/src/graphql/schema/element.ts:53</code></summary>

- **Draft comment:** 
Typo: The query name 'bmElementCategoryies' appears to be misspelled. Consider correcting it to 'bmElementCategories' for clarity and consistency.
- **Reason this comment was not posted:** 
Comment was on unchanged code.

</details>


Workflow ID: <workflowid>`wflow_dFfAXIrUSwD3DS8p`</workflowid>

</details>


----
**Want Ellipsis to fix these issues?** Tag `@ellipsis-dev` in a comment. You can customize Ellipsis with :+1: / :-1: [feedback](https://docs.ellipsis.dev/review), review rules, user-specific overrides, `quiet` mode, and [more](https://docs.ellipsis.dev/config).

state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T01:56:23Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts (3)</summary><blockquote>

`214-223`: **Improve naming for better clarity on the filtering logic.**

The `icon` parameter is used to filter elements based on the existence of the `quick` field, which is not intuitive from the parameter name. Consider renaming this parameter to something more descriptive of its actual purpose, such as `hasQuickField`.


```diff
- if (typeof icon === "boolean") {
-   if (icon) {
-     selector.quick = { $exists: true };
-   } else {
-     selector.quick = { $exists: false };
-   }
- }
+ if (typeof icon === "boolean") {
+   // Filter elements based on whether they have a quick field
+   selector.quick = { $exists: icon };
+ }
```

Additionally, consider documenting the purpose of this filter in a code comment to make it clearer for future developers.

---

`268-275`: **Consider using appropriate icons for default elements.**

All elements from "Hot shower" to "horse & camel" use "moon" as their icon, which doesn't seem semantically appropriate for these items. Consider using more relevant icons for each element.


For example:
```diff
- await checkDefaults(models, "Hot shower", "moon");
+ await checkDefaults(models, "Hot shower", "shower");

- await checkDefaults(models, "unable to shower", "moon");
+ await checkDefaults(models, "unable to shower", "shower-slash");

- await checkDefaults(models, "pick-up service", "moon");
+ await checkDefaults(models, "pick-up service", "truck-pickup");

- await checkDefaults(models, "electricity", "moon");
+ await checkDefaults(models, "electricity", "bolt");

- await checkDefaults(models, "no electricity", "moon");
+ await checkDefaults(models, "no electricity", "bolt-slash");

- await checkDefaults(models, "horse & camel", "moon");
+ await checkDefaults(models, "horse & camel", "horse");
```

---

`293-295`: **Simplify conditional with nullish coalescing operator.**

The code checks for the existence of `childOne?._id` and provides an empty string fallback. This can be simplified using the nullish coalescing operator.


```diff
- childOne?._id || ""
+ childOne?._id ?? ""
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 94b9641a097e42ba8923c3541467ac02d396057f and 16ac8ad1d237eca58ba56d62a757906d8d61a07f.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts` (6 hunks)
* `packages/plugin-bm-api/src/graphql/schema/element.ts` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts (1)</summary><blockquote>

<details>
<summary>packages/plugin-bm-api/src/models/definitions/element.ts (1)</summary>

* `IElement` (7-21)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: runtest

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-18T01:58:12Z

Review comments:
diff_hunk: @@ -48,7 +48,7 @@ export const types = () => `
 `;
 
 export const queries = `
-  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int): ListElement
+  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int,icon:Boolean): ListElement
path: packages/plugin-bm-api/src/graphql/schema/element.ts
user: login: sourcery-ai[bot]
body: **issue (bug_risk):** Resolve the type inconsistency for the 'icon' parameter.

While the bmElements query now defines 'icon' as a Boolean, the 'params' section below defines it as a String. This discrepancy may lead to runtime issues, so aligning the types in the schema would be advisable.
created_at: 2025-04-18T01:55:26Z
author_association: NONE
diff_hunk: @@ -39,134 +39,134 @@ const insertCategoryDefaults = async (
 };
 const LIST_CATEGORIES = [
   {
-    name: 'Accommodation',
+    name: "Accommodation",
     children: [
-      { name: 'Hotel', children: [] },
-      { name: 'Resort' },
-      { name: 'Guesthouse' },
-      { name: 'Vacation Rental' },
-      { name: 'Hostel' },
-      { name: 'Camping' },
-      { name: 'Lodge' },
-      { name: 'Motel' },
-      { name: 'Villa' }
+      { name: "Hotel", children: [] },
+      { name: "Resort" },
+      { name: "Guesthouse" },
+      { name: "Vacation Rental" },
+      { name: "Hostel" },
+      { name: "Camping" },
+      { name: "Lodge" },
+      { name: "Motel" },
+      { name: "Villa" }
     ]
   },
   {
-    name: 'Places',
+    name: "Places",
     children: [
       {
-        name: 'Natural Attractions',
+        name: "Natural Attractions",
         children: [
-          { name: 'Beaches' },
-          { name: 'Mountains' },
-          { name: 'Deserts' },
-          { name: 'Forests & Jungles' },
-          { name: 'Lakes & Rivers' },
-          { name: 'Waterfalls' },
-          { name: 'Islands' }
+          { name: "Beaches" },
+          { name: "Mountains" },
+          { name: "Deserts" },
+          { name: "Forests & Jungles" },
+          { name: "Lakes & Rivers" },
+          { name: "Waterfalls" },
+          { name: "Islands" }
         ]
       },
       {
-        name: 'Cultural & Historical Sites',
+        name: "Cultural & Historical Sites",
         children: [
-          { name: 'Ancient Ruins' },
-          { name: 'Temples & Monasteries' },
-          { name: 'Museums & Art Galleries' },
-          { name: 'Historical Cities' },
-          { name: 'Castles & Palaces' }
+          { name: "Ancient Ruins" },
+          { name: "Temples & Monasteries" },
+          { name: "Museums & Art Galleries" },
+          { name: "Historical Cities" },
+          { name: "Castles & Palaces" }
         ]
       },
       {
-        name: 'Urban Destinations',
+        name: "Urban Destinations",
         children: [
-          { name: 'Metropolitan Cities' },
-          { name: 'Skyscraper Cities' },
-          { name: 'Old Towns & Quarters' },
-          { name: 'Technology Hubs' }
+          { name: "Metropolitan Cities" },
+          { name: "Skyscraper Cities" },
+          { name: "Old Towns & Quarters" },
+          { name: "Technology Hubs" }
         ]
       },
       {
-        name: 'Adventure & Outdoor Recreation',
+        name: "Adventure & Outdoor Recreation",
         children: [
-          { name: 'National Parks' },
-          { name: 'Hiking Trails' },
-          { name: 'Ski Resorts' },
-          { name: 'Diving & Snorkeling Spots' },
-          { name: 'Rock Climbing Destinations' }
+          { name: "National Parks" },
+          { name: "Hiking Trails" },
+          { name: "Ski Resorts" },
+          { name: "Diving & Snorkeling Spots" },
+          { name: "Rock Climbing Destinations" }
         ]
       },
       {
-        name: 'Relaxation & Wellness',
+        name: "Relaxation & Wellness",
path: packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
user: login: sourcery-ai[bot]
body: **nitpick (bug_risk):** Duplicate category entry detected.

There are two consecutive entries for "Relaxation & Wellness" in the list categories. If this duplication is not intentional, consider removing one to avoid unintended behavior.
created_at: 2025-04-18T01:55:26Z
author_association: NONE
diff_hunk: @@ -206,13 +207,20 @@ const elementQueries = {
 
     if (name) {
       selector.$or = [
-        { name: { $regex: name, $options: 'i' } },
-        { 'location.name': { $regex: name, $options: 'i' } }
+        { name: { $regex: name, $options: "i" } },
+        { "location.name": { $regex: name, $options: "i" } }
       ];
     }
-    if (typeof quick === 'boolean') {
+    if (typeof quick === "boolean") {
       selector.quick = quick;
     }
+    if (typeof icon === "boolean") {
+      if (icon) {
+        selector.quick = { $exists: true };
path: packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
user: login: ellipsis-dev[bot]
body: BUG: The icon filter is incorrectly applied to the `quick` field. If filtering by icon, use `selector.icon` (e.g. `selector.icon = { $exists: true/false }`) instead of `selector.quick`.
created_at: 2025-04-18T01:56:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -48,7 +48,7 @@ export const types = () => `
 `;
 
 export const queries = `
-  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int): ListElement
+  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int,icon:Boolean): ListElement
path: packages/plugin-bm-api/src/graphql/schema/element.ts
user: login: ellipsis-dev[bot]
body: SUGGESTION: The query parameter `icon` is defined as a Boolean for filtering, while the `icon` field in mutations is a String. Consider renaming the filter (e.g. `iconFilter`) to avoid confusion.
created_at: 2025-04-18T01:56:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -48,7 +48,7 @@ export const types = () => `
 `;
 
 export const queries = `
-  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int): ListElement
+  bmElements(branchId:String, categories: [String],name: String, page:Int, perPage:Int,quick: Boolean,sortField:String, sortDirection:Int,icon:Boolean): ListElement
path: packages/plugin-bm-api/src/graphql/schema/element.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Ensure type consistency across schema and usage.**

The `icon` parameter is defined as `Boolean` here, which correctly matches its usage in the resolver function. However, in the `params` definition at line 71, it's defined as `String`. These should have consistent types.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-18T01:58:11Z
author_association: NONE
diff_hunk: @@ -67,7 +67,8 @@
   itineraryId: String,
   location: BMSLocationInput,
   quick: Boolean,
-  branchId: String
+  branchId: String,
+  icon: String
path: packages/plugin-bm-api/src/graphql/schema/element.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Type mismatch for `icon` parameter.**

The `icon` parameter is defined as `String` here, but it's defined as `Boolean` in the `bmElements` query on line 51. This inconsistency could lead to type errors at runtime.


Apply this diff to fix the type inconsistency:
```diff
  branchId: String,
- icon: String
+ icon: Boolean
```

Or if the parameter serves different purposes in queries vs mutations, consider using distinct names to avoid confusion.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  branchId: String,
  icon: Boolean
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-18T01:58:11Z
author_association: NONE
diff_hunk: @@ -1,15 +1,15 @@
-import { skip } from 'node:test';
-import { IContext, IModels } from '../../../connectionResolver';
+import { skip } from "node:test";
path: packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Unnecessary import from node:test.**

The `skip` import from "node:test" appears to be unused in this file. It might be a leftover from testing or debugging.


```diff
- import { skip } from "node:test";
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion

`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-18T01:58:11Z
author_association: NONE
diff_hunk: @@ -39,134 +39,134 @@
 };
 const LIST_CATEGORIES = [
   {
-    name: 'Accommodation',
+    name: "Accommodation",
     children: [
-      { name: 'Hotel', children: [] },
-      { name: 'Resort' },
-      { name: 'Guesthouse' },
-      { name: 'Vacation Rental' },
-      { name: 'Hostel' },
-      { name: 'Camping' },
-      { name: 'Lodge' },
-      { name: 'Motel' },
-      { name: 'Villa' }
+      { name: "Hotel", children: [] },
+      { name: "Resort" },
+      { name: "Guesthouse" },
+      { name: "Vacation Rental" },
+      { name: "Hostel" },
+      { name: "Camping" },
+      { name: "Lodge" },
+      { name: "Motel" },
+      { name: "Villa" }
     ]
   },
   {
-    name: 'Places',
+    name: "Places",
     children: [
       {
-        name: 'Natural Attractions',
+        name: "Natural Attractions",
         children: [
-          { name: 'Beaches' },
-          { name: 'Mountains' },
-          { name: 'Deserts' },
-          { name: 'Forests & Jungles' },
-          { name: 'Lakes & Rivers' },
-          { name: 'Waterfalls' },
-          { name: 'Islands' }
+          { name: "Beaches" },
+          { name: "Mountains" },
+          { name: "Deserts" },
+          { name: "Forests & Jungles" },
+          { name: "Lakes & Rivers" },
+          { name: "Waterfalls" },
+          { name: "Islands" }
         ]
       },
       {
-        name: 'Cultural & Historical Sites',
+        name: "Cultural & Historical Sites",
         children: [
-          { name: 'Ancient Ruins' },
-          { name: 'Temples & Monasteries' },
-          { name: 'Museums & Art Galleries' },
-          { name: 'Historical Cities' },
-          { name: 'Castles & Palaces' }
+          { name: "Ancient Ruins" },
+          { name: "Temples & Monasteries" },
+          { name: "Museums & Art Galleries" },
+          { name: "Historical Cities" },
+          { name: "Castles & Palaces" }
         ]
       },
       {
-        name: 'Urban Destinations',
+        name: "Urban Destinations",
         children: [
-          { name: 'Metropolitan Cities' },
-          { name: 'Skyscraper Cities' },
-          { name: 'Old Towns & Quarters' },
-          { name: 'Technology Hubs' }
+          { name: "Metropolitan Cities" },
+          { name: "Skyscraper Cities" },
+          { name: "Old Towns & Quarters" },
+          { name: "Technology Hubs" }
         ]
       },
       {
-        name: 'Adventure & Outdoor Recreation',
+        name: "Adventure & Outdoor Recreation",
         children: [
-          { name: 'National Parks' },
-          { name: 'Hiking Trails' },
-          { name: 'Ski Resorts' },
-          { name: 'Diving & Snorkeling Spots' },
-          { name: 'Rock Climbing Destinations' }
+          { name: "National Parks" },
+          { name: "Hiking Trails" },
+          { name: "Ski Resorts" },
+          { name: "Diving & Snorkeling Spots" },
+          { name: "Rock Climbing Destinations" }
         ]
       },
       {
-        name: 'Relaxation & Wellness',
+        name: "Relaxation & Wellness",
         children: [
-          { name: 'Spa Towns' },
-          { name: 'Yoga Retreats' },
-          { name: 'Hot Springs' },
-          { name: 'Quiet Countryside' }
+          { name: "Spa Towns" },
+          { name: "Yoga Retreats" },
+          { name: "Hot Springs" },
+          { name: "Quiet Countryside" }
         ]
       },
       {
-        name: 'Relaxation & Wellness',
+        name: "Relaxation & Wellness",
         children: [
-          { name: 'Spa Towns' },
-          { name: 'Yoga Retreats' },
-          { name: 'Hot Springs' },
-          { name: 'Quiet Countryside' }
+          { name: "Spa Towns" },
+          { name: "Yoga Retreats" },
+          { name: "Hot Springs" },
+          { name: "Quiet Countryside" }
         ]
       }
path: packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Remove duplicate category definition.**

There are two identical "Relaxation & Wellness" categories with the same children defined in lines 100-107 and 109-116. This duplication will likely cause issues when users interact with these categories.


```diff
- {
-   name: "Relaxation & Wellness",
-   children: [
-     { name: "Spa Towns" },
-     { name: "Yoga Retreats" },
-     { name: "Hot Springs" },
-     { name: "Quiet Countryside" }
-   ]
- }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion

`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-18T01:58:11Z
author_association: NONE

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-04-18T01:54:43Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

## Reviewer's Guide by Sourcery

This pull request introduces a new filter to the `bmElements` query, allowing users to filter elements based on the presence of an icon. This was achieved by adding an optional `icon` argument to the query and implementing the corresponding filtering logic in the resolver.

#### Sequence diagram for bmElements query with icon filter

```mermaid
sequenceDiagram
  participant Client
  participant GraphQL Server
  participant Resolver
  participant Models

  Client->>GraphQL Server: Query bmElements(icon: Boolean)
  GraphQL Server->>Resolver: bmElements(args, context)
  Resolver->>Models: Elements.find(selector)
  alt icon is true
    Models-->>Resolver: Elements with icon
  else icon is false
    Models-->>Resolver: Elements without icon
  else icon is not provided
    Models-->>Resolver: All elements
  end
  Resolver-->>GraphQL Server: ListElement
  GraphQL Server-->>Client: Response
```

#### Updated class diagram for the bmElements query

```mermaid
classDiagram
  class bmElementsQuery {
    branchId: String
    categories: String[]
    name: String
    page: Int
    perPage: Int
    quick: Boolean
    sortField: String
    sortDirection: Int
    +icon: Boolean
  }
  note for bmElementsQuery "Added 'icon' field to filter elements based on icon presence"
```

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Added a filter to the `bmElements` query to filter elements based on whether they have an icon or not. | <ul><li>Added an `icon` argument to the `bmElements` query in the GraphQL schema.</li><li>Implemented the `icon` filter in the resolver for the `bmElements` query.</li></ul> | `packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts`<br/>`packages/plugin-bm-api/src/graphql/schema/element.ts` |

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!
- **Generate a plan of action for an issue:** Comment `@sourcery-ai plan` on
  an issue to generate a plan of action for it.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-18T01:54:47Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The changes introduce a new optional `icon` argument to the `bmElements` GraphQL query, allowing clients to filter elements based on the existence of the `quick` field in the database. This is implemented by updating both the query resolver and the GraphQL schema. Additionally, the codebase is standardized to use double quotes for string literals throughout the affected files. Minor formatting adjustments are also made.

## Changes

| File(s)                                                                                  | Summary of Changes                                                                                           |
|-----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| packages/plugin-bm-api/src/graphql/resolvers/queries/element.ts                         | Replaced single quotes with double quotes; added optional `icon` argument to `bmElements` resolver; updated MongoDB selector logic to filter by existence of `quick` field when `icon` is provided. |
| packages/plugin-bm-api/src/graphql/schema/element.ts                                    | Changed import to use double quotes; added optional `icon` Boolean argument to `bmElements` query; extended input parameter list `params` with `icon: String`. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant GraphQL API
    participant MongoDB

    Client->>GraphQL API: Query bmElements(icon: Boolean)
    GraphQL API->>MongoDB: Find elements (filter by quick field existence if icon is set)
    MongoDB-->>GraphQL API: Return filtered elements
    GraphQL API-->>Client: Return bmElements result
```

## Poem

> 🐇  
> Double quotes now hop in line,  
> And icons filter, oh so fine!  
> Queries leap with nimble grace,  
> Searching for "quick" in every place.  
> Schema and code in harmony sing—  
> What clever changes spring!  
>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡💬 Agentic Chat (Pro Plan, General Availability)</summary>
> 
> - We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=erxes/erxes&utm_content=6007):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-18T01:56:59Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=erxes_erxes&pullRequest=6007) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [68.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=erxes_erxes&pullRequest=6007&metric=new_duplicated_lines_density&view=list) (required ≤ 3%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=erxes_erxes&pullRequest=6007)


author_association: NONE