@limetech/lime-crm-building-blocks 1.101.0 → 1.102.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/lime-crm-building-blocks.cjs.js +1 -1
  3. package/dist/cjs/lime-query-validation-6be10fa7.js +558 -0
  4. package/dist/cjs/limebb-lime-query-builder.cjs.entry.js +4 -514
  5. package/dist/cjs/{limebb-lime-query-filter-builder_4.cjs.entry.js → limebb-lime-query-filter-builder_3.cjs.entry.js} +1 -243
  6. package/dist/cjs/limebb-lime-query-filter-comparison_2.cjs.entry.js +1 -1
  7. package/dist/cjs/limebb-lime-query-filter-group_3.cjs.entry.js +165 -71
  8. package/dist/cjs/limebb-lime-query-order-by-item.cjs.entry.js +2 -2
  9. package/dist/cjs/limebb-lime-query-response-format-builder.cjs.entry.js +242 -0
  10. package/dist/cjs/limebb-lime-query-response-format-editor_2.cjs.entry.js +322 -0
  11. package/dist/cjs/limebb-live-docs-info.cjs.entry.js +2 -2
  12. package/dist/cjs/limebb-locale-picker.cjs.entry.js +1 -1
  13. package/dist/cjs/limebb-mention-group-counter.cjs.entry.js +2 -2
  14. package/dist/cjs/limebb-navigation-button_2.cjs.entry.js +3 -3
  15. package/dist/cjs/limebb-notification-item.cjs.entry.js +1 -1
  16. package/dist/cjs/limebb-percentage-visualizer.cjs.entry.js +2 -2
  17. package/dist/cjs/limebb-text-editor.cjs.entry.js +1 -1
  18. package/dist/cjs/limebb-trend-indicator.cjs.entry.js +1 -1
  19. package/dist/cjs/loader.cjs.js +1 -1
  20. package/dist/collection/collection-manifest.json +3 -2
  21. package/dist/collection/components/lime-query-builder/expressions/filter-group-logic.js +150 -0
  22. package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-comparison.js +1 -1
  23. package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-group.js +15 -71
  24. package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-not.js +1 -1
  25. package/dist/collection/components/lime-query-builder/lime-query-builder.js +1 -1
  26. package/dist/collection/components/lime-query-builder/lime-query-response-format-builder.css +91 -0
  27. package/dist/collection/components/lime-query-builder/lime-query-response-format-builder.js +355 -0
  28. package/dist/collection/components/lime-query-builder/lime-query-validation.js +40 -0
  29. package/dist/collection/components/lime-query-builder/limetype-field/limetype-field.js +1 -1
  30. package/dist/collection/components/lime-query-builder/order-by/order-by-item.js +2 -2
  31. package/dist/collection/components/lime-query-builder/{response-format-editor.css → response-format/response-format-editor.css} +1 -1
  32. package/dist/collection/components/lime-query-builder/{response-format-editor.js → response-format/response-format-editor.js} +5 -5
  33. package/dist/collection/components/lime-query-builder/response-format/response-format-helpers.js +92 -0
  34. package/dist/collection/components/lime-query-builder/{response-format-item.css → response-format/response-format-item.css} +1 -1
  35. package/dist/collection/components/lime-query-builder/{response-format-item.js → response-format/response-format-item.js} +6 -6
  36. package/dist/collection/components/limeobject/file-viewer/live-docs-info.js +2 -2
  37. package/dist/collection/components/locale-picker/locale-picker.js +1 -1
  38. package/dist/collection/components/notification-list/notification-item/notification-item.js +1 -1
  39. package/dist/collection/components/percentage-visualizer/percentage-visualizer.js +2 -2
  40. package/dist/collection/components/summary-popover/summary-popover.js +3 -3
  41. package/dist/collection/components/text-editor/mention-group-counter.js +2 -2
  42. package/dist/collection/components/text-editor/text-editor.js +1 -1
  43. package/dist/collection/components/trend-indicator/trend-indicator.js +1 -1
  44. package/dist/components/lime-query-filter-comparison.js +1 -1
  45. package/dist/components/lime-query-filter-expression.js +165 -71
  46. package/dist/components/lime-query-validation.js +555 -0
  47. package/dist/components/limebb-lime-query-builder.js +14 -524
  48. package/dist/components/limebb-lime-query-response-format-builder.d.ts +11 -0
  49. package/dist/components/limebb-lime-query-response-format-builder.js +283 -0
  50. package/dist/components/limebb-lime-query-response-format-editor.d.ts +11 -0
  51. package/dist/components/{limebb-response-format-editor.js → limebb-lime-query-response-format-editor.js} +2 -2
  52. package/dist/components/limebb-lime-query-response-format-item.d.ts +11 -0
  53. package/dist/components/{limebb-response-format-item.js → limebb-lime-query-response-format-item.js} +2 -2
  54. package/dist/components/limebb-locale-picker.js +1 -1
  55. package/dist/components/limebb-mention-group-counter.js +2 -2
  56. package/dist/components/limebb-percentage-visualizer.js +2 -2
  57. package/dist/components/limebb-text-editor.js +1 -1
  58. package/dist/components/limebb-trend-indicator.js +1 -1
  59. package/dist/components/limetype-field.js +1 -1
  60. package/dist/components/live-docs-info.js +2 -2
  61. package/dist/components/notification-item.js +1 -1
  62. package/dist/components/order-by-item.js +2 -2
  63. package/dist/components/response-format-editor.js +11 -11
  64. package/dist/components/response-format-item.js +9 -9
  65. package/dist/components/summary-popover.js +3 -3
  66. package/dist/esm/lime-crm-building-blocks.js +1 -1
  67. package/dist/esm/lime-query-validation-573223a5.js +555 -0
  68. package/dist/esm/limebb-lime-query-builder.entry.js +4 -514
  69. package/dist/esm/{limebb-lime-query-filter-builder_4.entry.js → limebb-lime-query-filter-builder_3.entry.js} +2 -243
  70. package/dist/esm/limebb-lime-query-filter-comparison_2.entry.js +1 -1
  71. package/dist/esm/limebb-lime-query-filter-group_3.entry.js +165 -71
  72. package/dist/esm/limebb-lime-query-order-by-item.entry.js +2 -2
  73. package/dist/esm/limebb-lime-query-response-format-builder.entry.js +238 -0
  74. package/dist/esm/limebb-lime-query-response-format-editor_2.entry.js +317 -0
  75. package/dist/esm/limebb-live-docs-info.entry.js +2 -2
  76. package/dist/esm/limebb-locale-picker.entry.js +1 -1
  77. package/dist/esm/limebb-mention-group-counter.entry.js +2 -2
  78. package/dist/esm/limebb-navigation-button_2.entry.js +3 -3
  79. package/dist/esm/limebb-notification-item.entry.js +1 -1
  80. package/dist/esm/limebb-percentage-visualizer.entry.js +2 -2
  81. package/dist/esm/limebb-text-editor.entry.js +1 -1
  82. package/dist/esm/limebb-trend-indicator.entry.js +1 -1
  83. package/dist/esm/loader.js +1 -1
  84. package/dist/lime-crm-building-blocks/lime-crm-building-blocks.esm.js +1 -1
  85. package/dist/lime-crm-building-blocks/{p-5cf4898d.entry.js → p-0de79b7f.entry.js} +1 -1
  86. package/dist/lime-crm-building-blocks/{p-8c2fb1c9.entry.js → p-0f7135ff.entry.js} +1 -1
  87. package/dist/lime-crm-building-blocks/{p-6aa216ec.entry.js → p-186e9f1a.entry.js} +1 -1
  88. package/dist/lime-crm-building-blocks/p-289ce8b9.entry.js +1 -0
  89. package/dist/lime-crm-building-blocks/p-3351395b.entry.js +1 -0
  90. package/dist/lime-crm-building-blocks/p-33e6d0ec.entry.js +1 -0
  91. package/dist/lime-crm-building-blocks/{p-a1ee8990.entry.js → p-3d1be1c9.entry.js} +1 -1
  92. package/dist/lime-crm-building-blocks/{p-92dfc5f8.entry.js → p-577d8909.entry.js} +1 -1
  93. package/dist/lime-crm-building-blocks/{p-d84874dc.entry.js → p-6f6fed59.entry.js} +1 -1
  94. package/dist/lime-crm-building-blocks/p-7731e1b0.entry.js +1 -0
  95. package/dist/lime-crm-building-blocks/{p-0cd036ed.entry.js → p-7e5528f6.entry.js} +1 -1
  96. package/dist/lime-crm-building-blocks/{p-8601eab5.entry.js → p-a9ac501f.entry.js} +1 -1
  97. package/dist/lime-crm-building-blocks/p-be845252.entry.js +1 -0
  98. package/dist/lime-crm-building-blocks/{p-2725671e.entry.js → p-cb338753.entry.js} +1 -1
  99. package/dist/lime-crm-building-blocks/{p-425eaba2.entry.js → p-d0721b22.entry.js} +1 -1
  100. package/dist/lime-crm-building-blocks/p-fa2da6bc.js +1 -0
  101. package/dist/types/components/lime-query-builder/expressions/filter-group-logic.d.ts +89 -0
  102. package/dist/types/components/lime-query-builder/lime-query-response-format-builder.d.ts +102 -0
  103. package/dist/types/components/lime-query-builder/lime-query-validation.d.ts +13 -0
  104. package/dist/types/components/lime-query-builder/{response-format-editor.d.ts → response-format/response-format-editor.d.ts} +2 -2
  105. package/dist/types/components/lime-query-builder/response-format/response-format-helpers.d.ts +42 -0
  106. package/dist/types/components/lime-query-builder/{response-format-item.d.ts → response-format/response-format-item.d.ts} +2 -2
  107. package/dist/types/components.d.ts +394 -222
  108. package/package.json +1 -1
  109. package/dist/cjs/limebb-response-format-item.cjs.entry.js +0 -80
  110. package/dist/components/limebb-response-format-editor.d.ts +0 -11
  111. package/dist/components/limebb-response-format-item.d.ts +0 -11
  112. package/dist/esm/limebb-response-format-item.entry.js +0 -76
  113. package/dist/lime-crm-building-blocks/p-244ee55b.entry.js +0 -1
  114. package/dist/lime-crm-building-blocks/p-67c174d0.entry.js +0 -1
  115. package/dist/lime-crm-building-blocks/p-ccf34631.entry.js +0 -1
  116. package/dist/lime-crm-building-blocks/p-f9efca1d.entry.js +0 -1
@@ -304,7 +304,7 @@ const LimetypeField = class {
304
304
  value: '',
305
305
  };
306
306
  options.unshift(emptyOption);
307
- return (h("limel-select", { key: 'fd9522c5df730f65a5ac57140bca6c05c5acd63d', label: this.label, options: options, value: selectedOption, required: this.required, helperText: this.helperText, invalid: invalid, disabled: this.disabled || this.readonly, onChange: this.handleChange }));
307
+ return (h("limel-select", { key: 'ee9fdc46424c9e6dc5897260cb16bcbedd43413a', label: this.label, options: options, value: selectedOption, required: this.required, helperText: this.helperText, invalid: invalid, disabled: this.disabled || this.readonly, onChange: this.handleChange }));
308
308
  }
309
309
  componentWillRender() {
310
310
  this.updatePropertyFields(this.value || '');
@@ -342,245 +342,4 @@ const limeTypeToOption = (limetype) => ({
342
342
  icon: getIcon(limetype),
343
343
  });
344
344
 
345
- /**
346
- * Process a single property value and add to items array
347
- * @param items Array to add items to
348
- * @param fullPath Full property path
349
- * @param value Property value to process
350
- */
351
- function processPropertyValue(items, fullPath, value) {
352
- if (value === null) {
353
- items.push({ path: fullPath });
354
- return;
355
- }
356
- // Cast to record for checking
357
- const valueObj = value;
358
- const keys = Object.keys(valueObj);
359
- const hasAlias = '_alias' in valueObj;
360
- const hasDescription = '#description' in valueObj;
361
- const otherKeys = keys.filter((k) => k !== '_alias' && k !== '#description');
362
- // If it's {} or only has metadata (_alias, #description), treat as simple property
363
- if (otherKeys.length === 0) {
364
- const aliasValue = valueObj._alias;
365
- const descriptionValue = valueObj['#description'];
366
- if (aliasValue || descriptionValue) {
367
- items.push({
368
- path: fullPath,
369
- alias: aliasValue,
370
- description: descriptionValue,
371
- });
372
- }
373
- else {
374
- items.push({ path: fullPath });
375
- }
376
- return;
377
- }
378
- // If has metadata + other properties, we need to handle both
379
- // Add the nested properties (metadata is preserved in conversion back)
380
- if (hasAlias || hasDescription) {
381
- // Build a PropertySelection without the metadata for recursion
382
- const nestedSelection = {};
383
- for (const key of otherKeys) {
384
- nestedSelection[key] = valueObj[key];
385
- }
386
- items.push(...propertySelectionToItems(nestedSelection, fullPath));
387
- return;
388
- }
389
- // Nested property selection without metadata
390
- items.push(...propertySelectionToItems(value, fullPath));
391
- }
392
- /**
393
- * Convert a nested PropertySelection to a flat list of property items
394
- * @param selection The nested PropertySelection object
395
- * @param prefix Current path prefix (used for recursion)
396
- * @returns Flat array of PropertySelectionItem objects
397
- */
398
- function propertySelectionToItems(selection, prefix = '') {
399
- if (!selection) {
400
- return [];
401
- }
402
- const items = [];
403
- for (const [key, value] of Object.entries(selection)) {
404
- const fullPath = prefix ? `${prefix}.${key}` : key;
405
- if (typeof value === 'object') {
406
- // NOTE: We want to send null values to the processPropertyValue
407
- // function but we don't need a special check for null, since
408
- // `typeof null === 'object'`
409
- processPropertyValue(items, fullPath, value);
410
- }
411
- }
412
- return items;
413
- }
414
- /**
415
- * Set the final property value (with or without alias/description)
416
- * @param current Current PropertySelection object
417
- * @param part Property name/key
418
- * @param item Property selection item with path and optional alias/description
419
- */
420
- function setPropertyValue(current, part, item) {
421
- // Check if there's already a nested PropertySelection with properties
422
- const existing = current[part];
423
- if (existing &&
424
- typeof existing === 'object' &&
425
- !('_alias' in existing) &&
426
- !('#description' in existing)) {
427
- // There's already a nested PropertySelection object with properties
428
- // Don't overwrite it - preserve the nested selections
429
- return;
430
- }
431
- // Build metadata object, stripping empty values
432
- const metadata = {};
433
- if (item.alias && item.alias.trim() !== '') {
434
- metadata._alias = item.alias;
435
- }
436
- if (item.description && item.description.trim() !== '') {
437
- metadata['#description'] = item.description;
438
- }
439
- // If we have metadata, use it; otherwise use null
440
- if (Object.keys(metadata).length > 0) {
441
- current[part] = metadata;
442
- }
443
- else {
444
- current[part] = null;
445
- }
446
- }
447
- /**
448
- * Ensure a nested object exists and return it
449
- * Preserves any existing _alias and #description when converting to nested object
450
- * @param current Current PropertySelection object
451
- * @param part Property name/key
452
- * @returns The nested PropertySelection object
453
- */
454
- function ensureNestedObject(current, part) {
455
- const existing = current[part];
456
- // If doesn't exist or is null, create empty object
457
- if (!existing) {
458
- current[part] = {};
459
- return current[part];
460
- }
461
- // If it's already a PropertySelection object, check for metadata
462
- if (typeof existing === 'object') {
463
- const existingObj = existing;
464
- // If it has metadata but no other properties, preserve the metadata
465
- const keys = Object.keys(existingObj);
466
- const hasMetadata = '_alias' in existingObj || '#description' in existingObj;
467
- const otherKeys = keys.filter((k) => k !== '_alias' && k !== '#description');
468
- if (hasMetadata && otherKeys.length === 0) {
469
- // Convert { _alias: "...", "#description": "..." } to { _alias: "...", "#description": "...", ...nested }
470
- // Keep the existing object and return it (caller will add nested props)
471
- return existingObj;
472
- }
473
- // Already has nested properties, return as is
474
- return existingObj;
475
- }
476
- // Shouldn't reach here, but fallback to creating new object
477
- current[part] = {};
478
- return current[part];
479
- }
480
- /**
481
- * Convert a flat list of property items to a nested PropertySelection structure
482
- * @param items Array of PropertySelectionItem objects
483
- * @returns Nested PropertySelection object
484
- */
485
- function itemsToPropertySelection(items) {
486
- const result = {};
487
- for (const item of items) {
488
- const parts = item.path.split('.');
489
- let current = result;
490
- for (let i = 0; i < parts.length; i++) {
491
- const part = parts[i];
492
- const isLast = i === parts.length - 1;
493
- if (isLast) {
494
- setPropertyValue(current, part, item);
495
- }
496
- else {
497
- current = ensureNestedObject(current, part);
498
- }
499
- }
500
- }
501
- return result;
502
- }
503
-
504
- const responseFormatEditorCss = ":host(limebb-response-format-editor){display:block;width:100%}.response-format-editor{display:flex;flex-direction:column;gap:1rem;padding:1rem}.header{display:flex;justify-content:space-between;align-items:center;gap:1rem}.header h4{margin:0;font-size:1rem;font-weight:600;color:rgb(var(--contrast-1000))}.property-list{display:flex;flex-direction:column;gap:1rem;padding:0.5rem;border:1px solid rgb(var(--contrast-300));border-radius:0.25rem;background-color:rgb(var(--contrast-50));min-height:4rem}.property-item{padding:0.5rem;border-radius:0.25rem;transition:background-color 0.2s}.property-item:hover{background-color:rgb(var(--contrast-100))}.actions{display:flex;justify-content:flex-start}.summary{display:flex;justify-content:space-between;align-items:center;padding-top:0.5rem;border-top:1px solid rgb(var(--contrast-300))}.summary .count{font-size:0.875rem;font-weight:500;color:rgb(var(--contrast-900))}.empty-state{padding:2rem;text-align:center;color:rgb(var(--contrast-700));font-style:italic}.empty-state p{margin:0}";
505
- const LimebbResponseFormatEditorStyle0 = responseFormatEditorCss;
506
-
507
- const ResponseFormatEditor = class {
508
- constructor(hostRef) {
509
- registerInstance(this, hostRef);
510
- this.change = createEvent(this, "change", 7);
511
- /**
512
- * Optional label
513
- */
514
- this.label = 'Select Properties to Return';
515
- this.items = [{ path: '_id' }];
516
- this.handleItemChange = (index) => (event) => {
517
- event.stopPropagation();
518
- const newItems = [...this.items];
519
- if (event.detail === null) {
520
- // Remove item
521
- newItems.splice(index, 1);
522
- }
523
- else {
524
- // Update item
525
- newItems[index] = event.detail;
526
- }
527
- // Ensure we always have at least _id
528
- if (newItems.length === 0) {
529
- newItems.push({ path: '_id' });
530
- }
531
- this.items = newItems;
532
- this.emitChange();
533
- };
534
- this.handleAddProperty = () => {
535
- this.items = [...this.items, { path: '' }];
536
- this.emitChange();
537
- };
538
- }
539
- componentWillLoad() {
540
- var _a;
541
- if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.object) {
542
- const converted = propertySelectionToItems(this.value.object);
543
- if (converted.length > 0) {
544
- this.items = converted;
545
- }
546
- }
547
- }
548
- componentWillUpdate() {
549
- var _a;
550
- if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.object) {
551
- const currentItems = propertySelectionToItems(this.value.object);
552
- // Check if items have changed
553
- const itemsChanged = currentItems.length !== this.items.length ||
554
- !currentItems.every((item, index) => {
555
- const current = this.items[index];
556
- return (current &&
557
- item.path === current.path &&
558
- item.alias === current.alias &&
559
- item.description === current.description);
560
- });
561
- if (itemsChanged) {
562
- this.items =
563
- currentItems.length > 0 ? currentItems : [{ path: '_id' }];
564
- }
565
- }
566
- }
567
- render() {
568
- if (!this.limetype) {
569
- return (h("div", { class: "empty-state" }, h("p", null, "Select a limetype to choose properties")));
570
- }
571
- return (h("div", { class: "response-format-editor" }, h("div", { class: "header" }, h("h4", null, this.label)), h("div", { class: "property-list" }, this.items.map((item, index) => this.renderItem(item, index))), h("div", { class: "actions" }, h("limel-button", { label: "Add Property", icon: "plus_math", onClick: this.handleAddProperty })), h("div", { class: "summary" }, h("span", { class: "count" }, this.items.length, ' ', this.items.length === 1 ? 'property' : 'properties', ' ', "selected"))));
572
- }
573
- renderItem(item, index) {
574
- return (h("limebb-response-format-item", { key: `${item.path}-${index}`, class: "property-item", platform: this.platform, context: this.context, limetype: this.limetype, item: item, onItemChange: this.handleItemChange(index) }));
575
- }
576
- emitChange() {
577
- const propertySelection = itemsToPropertySelection(this.items);
578
- const responseFormat = {
579
- object: propertySelection,
580
- };
581
- this.change.emit(responseFormat);
582
- }
583
- };
584
- ResponseFormatEditor.style = LimebbResponseFormatEditorStyle0;
585
-
586
- export { LimeQueryFilterBuilderComponent as limebb_lime_query_filter_builder, OrderByEditor as limebb_lime_query_order_by_editor, LimetypeField as limebb_limetype_field, ResponseFormatEditor as limebb_response_format_editor };
345
+ export { LimeQueryFilterBuilderComponent as limebb_lime_query_filter_builder, OrderByEditor as limebb_lime_query_order_by_editor, LimetypeField as limebb_limetype_field };
@@ -78,7 +78,7 @@ const LimeQueryFilterComparisonComponent = class {
78
78
  };
79
79
  }
80
80
  render() {
81
- return (h("div", { key: 'a077c982ced9840beec3e574cd3e2e336cff6071', class: "expression" }, this.label && h("limel-header", { key: 'fbcb5cf515aac2c8e68d29947c7560684f30822c', heading: this.label }), h("div", { key: 'ffea426ea1295ae11aaa3c910f835acbeed24cd9', class: "expression-container" }, this.renderPropertySelector(), this.renderOperator(), this.renderValueInput(), h("limel-icon-button", { key: '20064f9fe42a4dfa71b2e1e2d393d50bbe20e2cb', class: "remove", icon: "trash", label: "Remove condition", onClick: this.removeExpression }))));
81
+ return (h("div", { key: '41fc60ed4ce76de8bbed05ee8cc658a188347cbd', class: "expression" }, this.label && h("limel-header", { key: '95cb9b556e2e0f2c8f3fd8ebe3909c402a844fe3', heading: this.label }), h("div", { key: 'feac7dcf059a0a20ad499d1549fa45d775d6bec8', class: "expression-container" }, this.renderPropertySelector(), this.renderOperator(), this.renderValueInput(), h("limel-icon-button", { key: '0fee01518c1c4a29c347a47ce1ce7856b32dfa8f', class: "remove", icon: "trash", label: "Remove condition", onClick: this.removeExpression }))));
82
82
  }
83
83
  renderPropertySelector() {
84
84
  return (h("limebb-property-selector", { platform: this.platform, context: this.context, label: "Property", limetype: this.limetype, value: this.expression.key, required: true, onChange: this.handlePropertyChange }));
@@ -2,6 +2,156 @@ import { r as registerInstance, c as createEvent, h } from './index-96dd111f.js'
2
2
  import { Z as Zt, T as Te } from './index.esm-bb569663.js';
3
3
  import { g as getPropertyFromPath } from './property-resolution-c21a1369.js';
4
4
 
5
+ /**
6
+ * Get the subheading text for a filter group based on its operator and expression count
7
+ *
8
+ * @param operator - The group's operator (AND or OR)
9
+ * @param expressionCount - Number of child expressions
10
+ * @returns Subheading text, or empty string if 0 or 1 expressions
11
+ */
12
+ function getFilterGroupSubheading(operator, expressionCount) {
13
+ if (expressionCount <= 1) {
14
+ return '';
15
+ }
16
+ return operator === Zt.AND
17
+ ? 'All of these conditions are true'
18
+ : 'Any of these conditions are true';
19
+ }
20
+ /**
21
+ * Get the label for the "Add condition" button
22
+ *
23
+ * @param operator - The group's operator (AND or OR)
24
+ * @param expressionCount - Number of child expressions
25
+ * @returns Appropriate button label based on context
26
+ */
27
+ function getAddConditionButtonLabel(operator, expressionCount) {
28
+ if (expressionCount === 0) {
29
+ return 'Add a condition';
30
+ }
31
+ return operator === Zt.AND
32
+ ? 'Add another condition'
33
+ : 'Add alternative';
34
+ }
35
+ /**
36
+ * Get the label for the "Add group" button
37
+ *
38
+ * @param operator - The group's operator (AND or OR)
39
+ * @param expressionCount - Number of child expressions
40
+ * @returns Appropriate button label based on context
41
+ */
42
+ function getAddGroupButtonLabel(operator, expressionCount) {
43
+ if (expressionCount === 0) {
44
+ return 'Add a group';
45
+ }
46
+ return operator === Zt.AND
47
+ ? 'Add another group'
48
+ : 'Add alternative group';
49
+ }
50
+ /**
51
+ * Create a new empty comparison expression
52
+ *
53
+ * @returns A new comparison expression with empty key and value
54
+ */
55
+ function createEmptyComparison() {
56
+ return {
57
+ key: '',
58
+ op: Zt.EQUALS,
59
+ exp: '',
60
+ };
61
+ }
62
+ /**
63
+ * Create a new nested group with the opposite operator from the parent
64
+ *
65
+ * @param parentOperator - The parent group's operator
66
+ * @returns A new group with the opposite operator and one empty comparison
67
+ */
68
+ function createNestedGroup(parentOperator) {
69
+ const oppositeOp = parentOperator === Zt.AND ? Zt.OR : Zt.AND;
70
+ return {
71
+ op: oppositeOp,
72
+ exp: [createEmptyComparison()],
73
+ };
74
+ }
75
+ /**
76
+ * Add a new expression to a group immutably
77
+ *
78
+ * @param group - The existing group
79
+ * @param newExpression - The expression to add
80
+ * @returns A new group with the expression added to the end
81
+ */
82
+ function addExpressionToGroup(group, newExpression) {
83
+ return {
84
+ op: group.op,
85
+ exp: [...group.exp, newExpression],
86
+ };
87
+ }
88
+ /**
89
+ * Toggle a group's operator between AND and OR
90
+ *
91
+ * @param group - The group to toggle
92
+ * @returns A new group with the toggled operator
93
+ */
94
+ function toggleGroupOperator(group) {
95
+ const newOperator = group.op === Zt.AND ? Zt.OR : Zt.AND;
96
+ return {
97
+ op: newOperator,
98
+ exp: [...group.exp],
99
+ };
100
+ }
101
+ /**
102
+ * Update a child expression in a group, handling deletion and unwrapping
103
+ *
104
+ * This function handles three scenarios:
105
+ * 1. Update: Replace a child expression with a new one
106
+ * 2. Delete: Remove a child (when updatedChild is undefined)
107
+ * - If last child is deleted, return 'removed' (group should be deleted)
108
+ * - If deletion leaves one child, return 'unwrapped' (unwrap to that child)
109
+ * - Otherwise, return 'updated' with the remaining children
110
+ *
111
+ * @param group - The group containing the child
112
+ * @param childIndex - Index of the child to update
113
+ * @param updatedChild - The new child expression, or undefined to delete
114
+ * @returns Result object with type and resulting expression
115
+ */
116
+ function updateChildExpression(group, childIndex, updatedChild) {
117
+ const expressions = [...group.exp];
118
+ if (!updatedChild) {
119
+ // Deletion - remove the child
120
+ expressions.splice(childIndex, 1);
121
+ if (expressions.length === 0) {
122
+ // No children left - remove the entire group
123
+ return {
124
+ type: 'removed',
125
+ expression: undefined,
126
+ };
127
+ }
128
+ if (expressions.length === 1) {
129
+ // One child left - unwrap to that child
130
+ return {
131
+ type: 'unwrapped',
132
+ expression: expressions[0],
133
+ };
134
+ }
135
+ // Multiple children remain - return updated group
136
+ return {
137
+ type: 'updated',
138
+ expression: {
139
+ op: group.op,
140
+ exp: expressions,
141
+ },
142
+ };
143
+ }
144
+ // Update - replace the child
145
+ expressions[childIndex] = updatedChild;
146
+ return {
147
+ type: 'updated',
148
+ expression: {
149
+ op: group.op,
150
+ exp: expressions,
151
+ },
152
+ };
153
+ }
154
+
5
155
  const limeQueryFilterGroupCss = "@charset \"UTF-8\";.expression{display:flex;flex-direction:column;margin-bottom:1rem;gap:0;background-color:rgb(var(--contrast-100));border:1px solid rgb(var(--contrast-500));border-radius:0.75rem}.expression .clickable-header{cursor:pointer;user-select:none}.expression .clickable-header:hover{background-color:rgb(var(--contrast-200))}.expression>ul{margin-top:0;margin-right:1rem;margin-bottom:1rem;margin-left:1rem;padding-left:1rem;list-style:disc}.expression>ul li{margin-top:1rem}.expression>ul li.add-button{list-style:none;display:flex;gap:0.5rem}";
6
156
  const LimebbLimeQueryFilterGroupStyle0 = limeQueryFilterGroupCss;
7
157
 
@@ -11,80 +161,32 @@ const LimeQueryFilterGroupComponent = class {
11
161
  this.expressionChange = createEvent(this, "expressionChange", 7);
12
162
  this.renderChildExpression = (expression, childIndex) => (h("li", null, h("limebb-lime-query-filter-expression", { platform: this.platform, context: this.context, limetype: this.limetype, activeLimetype: this.activeLimetype, expression: expression, onExpressionChange: this.handleExpressionChange(childIndex) })));
13
163
  this.handleToggleOperator = () => {
14
- const newOperator = this.expression.op === Zt.AND ? Zt.OR : Zt.AND;
15
- this.expressionChange.emit({
16
- op: newOperator,
17
- exp: this.expression.exp,
18
- });
164
+ const newGroup = toggleGroupOperator(this.expression);
165
+ this.expressionChange.emit(newGroup);
19
166
  };
20
167
  this.handleAddChildExpression = () => {
21
- // Always add a new comparison directly to the list
22
- const newChild = {
23
- key: '',
24
- op: Zt.EQUALS,
25
- exp: '',
26
- };
27
- this.expressionChange.emit({
28
- op: this.expression.op,
29
- exp: [...this.expression.exp, newChild],
30
- });
168
+ const newChild = createEmptyComparison();
169
+ const newGroup = addExpressionToGroup(this.expression, newChild);
170
+ this.expressionChange.emit(newGroup);
31
171
  };
32
172
  this.handleAddChildGroup = () => {
33
- // Add a nested group of the opposite type
34
- const oppositeOp = this.expression.op === Zt.AND ? Zt.OR : Zt.AND;
35
- const newChild = {
36
- op: oppositeOp,
37
- exp: [
38
- {
39
- key: '',
40
- op: Zt.EQUALS,
41
- exp: '',
42
- },
43
- ],
44
- };
45
- this.expressionChange.emit({
46
- op: this.expression.op,
47
- exp: [...this.expression.exp, newChild],
48
- });
173
+ const newChild = createNestedGroup(this.expression.op);
174
+ const newGroup = addExpressionToGroup(this.expression, newChild);
175
+ this.expressionChange.emit(newGroup);
49
176
  };
50
177
  this.handleExpressionChange = (updatedChildIndex) => (event) => {
51
178
  event.stopPropagation();
52
179
  const updatedExpression = event.detail;
53
- const expressions = [...this.expression.exp];
54
- if (updatedExpression === undefined) {
55
- // Deletion - remove the child and potentially unwrap
56
- expressions.splice(updatedChildIndex, 1);
57
- if (expressions.length === 0) {
58
- this.expressionChange.emit(undefined);
59
- return;
60
- }
61
- if (expressions.length === 1) {
62
- // Unwrap when only one child remains after deletion
63
- this.expressionChange.emit(expressions[0]);
64
- return;
65
- }
66
- }
67
- else {
68
- // Update - replace the child, don't unwrap
69
- expressions[updatedChildIndex] = updatedExpression;
70
- }
71
- this.expressionChange.emit({
72
- op: this.expression.op,
73
- exp: expressions,
74
- });
180
+ const result = updateChildExpression(this.expression, updatedChildIndex, updatedExpression);
181
+ this.expressionChange.emit(result.expression);
75
182
  };
76
183
  }
77
184
  render() {
78
185
  const subheading = this.getSubheading();
79
- return (h("div", { key: '0ed5a1403d9641926cd6d474910cedf9c7bba89e', class: "expression" }, subheading && (h("limel-header", { key: 'ea88a97df09f0fb5a21bf9afb4745256a611c7f8', subheading: subheading, onClick: this.handleToggleOperator, class: "clickable-header" })), h("ul", { key: 'cfbcdd539e84f79bf1d778e075cd3317d7409647' }, this.expression.exp.map(this.renderChildExpression), h("li", { key: 'ec443459245bf5852920bb4d3e341f2490a7b75b', class: "add-button" }, this.renderAddButton(), this.renderAddGroupButton()))));
186
+ return (h("div", { key: 'bf26300a939b4a2a1b401fa7a81593ec745a2a52', class: "expression" }, subheading && (h("limel-header", { key: 'f5152a2ca09811540b626965f52f5793e6c99728', subheading: subheading, onClick: this.handleToggleOperator, class: "clickable-header" })), h("ul", { key: 'c4cad750e47e0b6c94d6a76b2a4d8b72e36b3402' }, this.expression.exp.map(this.renderChildExpression), h("li", { key: 'ddd614f237a0c0314c2977b74a31b365f3251f9d', class: "add-button" }, this.renderAddButton(), this.renderAddGroupButton()))));
80
187
  }
81
188
  getSubheading() {
82
- if (this.expression.exp.length <= 1) {
83
- return '';
84
- }
85
- return this.expression.op === Zt.AND
86
- ? 'All of these conditions are true'
87
- : 'Any of these conditions are true';
189
+ return getFilterGroupSubheading(this.expression.op, this.expression.exp.length);
88
190
  }
89
191
  renderAddButton() {
90
192
  const label = this.getAddButtonLabel();
@@ -95,18 +197,10 @@ const LimeQueryFilterGroupComponent = class {
95
197
  return (h("limel-button", { label: label, icon: "tree_structure", onClick: this.handleAddChildGroup }));
96
198
  }
97
199
  getAddButtonLabel() {
98
- const isAnd = this.expression.op === Zt.AND;
99
- if (this.expression.exp.length === 0) {
100
- return 'Add a condition';
101
- }
102
- return isAnd ? 'Add another condition' : 'Add alternative';
200
+ return getAddConditionButtonLabel(this.expression.op, this.expression.exp.length);
103
201
  }
104
202
  getAddGroupButtonLabel() {
105
- const isAnd = this.expression.op === Zt.AND;
106
- if (this.expression.exp.length === 0) {
107
- return 'Add a group';
108
- }
109
- return isAnd ? 'Add another group' : 'Add alternative group';
203
+ return getAddGroupButtonLabel(this.expression.op, this.expression.exp.length);
110
204
  }
111
205
  };
112
206
  LimeQueryFilterGroupComponent.style = LimebbLimeQueryFilterGroupStyle0;
@@ -133,7 +227,7 @@ const LimeQueryFilterNotComponent = class {
133
227
  };
134
228
  }
135
229
  render() {
136
- return (h("div", { key: '9ab4a6b1e99668a0bcee3e3ba8cbbbe5185222e0', class: "expression" }, this.label && h("limel-header", { key: '85e997b0f96db306dd7a4433da959a74303aacfa', heading: this.label }), h("limebb-lime-query-filter-expression", { key: '14f634e125ee78f2aa70c7537b270a31699ba7c2', platform: this.platform, context: this.context, label: "Not", limetype: this.limetype, activeLimetype: this.activeLimetype, expression: this.expression.exp, onExpressionChange: this.handleExpressionChange })));
230
+ return (h("div", { key: '29770b10d0b892750ad2aab3520cec5a82063774', class: "expression" }, this.label && h("limel-header", { key: '9e47d14c6cb526c9c31d67e11a5ed5ec665c7f62', heading: this.label }), h("limebb-lime-query-filter-expression", { key: '943c1529057aa6cc918dc935f1a5782b149351ae', platform: this.platform, context: this.context, label: "Not", limetype: this.limetype, activeLimetype: this.activeLimetype, expression: this.expression.exp, onExpressionChange: this.handleExpressionChange })));
137
231
  }
138
232
  };
139
233
  LimeQueryFilterNotComponent.style = LimebbLimeQueryFilterNotStyle0;
@@ -37,9 +37,9 @@ const OrderByItemComponent = class {
37
37
  render() {
38
38
  const propertyPath = Object.keys(this.item)[0] || '';
39
39
  const direction = this.item[propertyPath] || 'ASC';
40
- return (h("div", { key: 'e0faeb5b370d8aba00a668f0861e8e1cb4eec495', class: "order-by-controls" }, h("div", { key: 'd013e829ca193b6ce9cc3756c3700584984f4478', class: "property-path" }, h("limebb-property-selector", { key: '11dee28e5de28d0dc6934abdfe613e87a8b8fbed', platform: this.platform, context: this.context, limetype: this.limetype, label: "Property", value: propertyPath, required: true, onChange: this.handlePathChange })), h("div", { key: '66aa416b1f9683a15357d609e3685379d8993733', class: "control-buttons" }, h("limel-icon-button", { key: '360f271ecd3cf42581ae21617d297c84ee93569e', icon: direction === 'ASC'
40
+ return (h("div", { key: '1587617d84be8905a858059ea966b7a9e0d6df78', class: "order-by-controls" }, h("div", { key: '8d4f47423c56cad20e91142f82a5726a7325233b', class: "property-path" }, h("limebb-property-selector", { key: '42c54528d2d2ee72e5b3f6ca4b31eb7bbcb9b325', platform: this.platform, context: this.context, limetype: this.limetype, label: "Property", value: propertyPath, required: true, onChange: this.handlePathChange })), h("div", { key: '1011a34f626c94608a926567e464d380faded349', class: "control-buttons" }, h("limel-icon-button", { key: '510a7c333397792a66f3e17a3501f2af96183db9', icon: direction === 'ASC'
41
41
  ? 'sort_ascending'
42
- : 'sort_descending', label: direction === 'ASC' ? 'Ascending' : 'Descending', onClick: this.handleToggleDirection }), h("limel-icon-button", { key: '3cbb13bff679a0ca95bb30b7853551b8bc276520', icon: "trash", label: "Remove", onClick: this.handleRemove }))));
42
+ : 'sort_descending', label: direction === 'ASC' ? 'Ascending' : 'Descending', onClick: this.handleToggleDirection }), h("limel-icon-button", { key: '5bc160b38c565e30cca03a88d6f2d181284cefdd', icon: "trash", label: "Remove", onClick: this.handleRemove }))));
43
43
  }
44
44
  };
45
45
  OrderByItemComponent.style = LimebbLimeQueryOrderByItemStyle0;