@limetech/lime-crm-building-blocks 1.103.5 → 1.103.7
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.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/limebb-lime-query-builder.cjs.entry.js +2 -4
- package/dist/cjs/limebb-lime-query-filter-group_3.cjs.entry.js +123 -12
- package/dist/cjs/limebb-lime-query-response-format-editor_2.cjs.entry.js +48 -34
- package/dist/collection/components/lime-query-builder/expressions/lime-query-value-input.js +15 -12
- package/dist/collection/components/lime-query-builder/lime-query-builder.js +2 -4
- package/dist/collection/components/lime-query-builder/response-format/response-format-editor.js +48 -34
- package/dist/collection/components/lime-query-builder/type-resolution.js +108 -0
- package/dist/components/lime-query-value-input.js +123 -12
- package/dist/components/limebb-lime-query-builder.js +2 -4
- package/dist/components/response-format-editor.js +48 -34
- package/dist/esm/limebb-lime-query-builder.entry.js +2 -4
- package/dist/esm/limebb-lime-query-filter-group_3.entry.js +123 -12
- package/dist/esm/limebb-lime-query-response-format-editor_2.entry.js +48 -34
- package/dist/lime-crm-building-blocks/lime-crm-building-blocks.esm.js +1 -1
- package/dist/lime-crm-building-blocks/p-908dd7d5.entry.js +1 -0
- package/dist/lime-crm-building-blocks/p-adfb9e90.entry.js +1 -0
- package/dist/lime-crm-building-blocks/p-fe6a94a1.entry.js +1 -0
- package/dist/types/components/lime-query-builder/expressions/lime-query-value-input.d.ts +1 -2
- package/dist/types/components/lime-query-builder/response-format/response-format-editor.d.ts +16 -0
- package/dist/types/components/lime-query-builder/type-resolution.d.ts +73 -0
- package/package.json +1 -1
- package/dist/lime-crm-building-blocks/p-47f4f505.entry.js +0 -1
- package/dist/lime-crm-building-blocks/p-4f605428.entry.js +0 -1
- package/dist/lime-crm-building-blocks/p-d635e6fc.entry.js +0 -1
|
@@ -2,6 +2,115 @@ import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/
|
|
|
2
2
|
import { T as Te, Z as Zt } from './index.esm.js';
|
|
3
3
|
import { g as getPropertyFromPath, d as defineCustomElement$1 } from './property-selector.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* System property name to actual type mapping.
|
|
7
|
+
*
|
|
8
|
+
* Maps system property names (with or without underscore prefix) to their actual data types.
|
|
9
|
+
* This mapping is necessary because system properties have `type='system'` in the metadata
|
|
10
|
+
* (for historical reasons - database schema fieldtype 255), but we need to know their
|
|
11
|
+
* actual data types to render appropriate inputs.
|
|
12
|
+
*/
|
|
13
|
+
const SYSTEM_TYPE_MAP = {
|
|
14
|
+
timestamp: 'time',
|
|
15
|
+
createdtime: 'time',
|
|
16
|
+
updatedtime: 'time',
|
|
17
|
+
id: 'integer',
|
|
18
|
+
createduser: 'integer',
|
|
19
|
+
updateduser: 'integer',
|
|
20
|
+
descriptive: 'string',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Lime CRM date/time property type to Lime Elements date picker type mapping.
|
|
24
|
+
*
|
|
25
|
+
* Maps Lime CRM property types to the corresponding Lime Elements date picker types,
|
|
26
|
+
* as they use different naming conventions.
|
|
27
|
+
*/
|
|
28
|
+
const DATE_TIME_TYPE_MAP = {
|
|
29
|
+
date: 'date',
|
|
30
|
+
time: 'datetime',
|
|
31
|
+
timeofday: 'time',
|
|
32
|
+
month: 'month',
|
|
33
|
+
quarter: 'quarter',
|
|
34
|
+
year: 'year',
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Get the actual type of a property, resolving 'system' type to the underlying type.
|
|
38
|
+
*
|
|
39
|
+
* System properties in Lime CRM have `type: 'system'` in the metadata (a categorical marker
|
|
40
|
+
* from the database schema fieldtype 255), but we need to know their actual data types
|
|
41
|
+
* to render appropriate input controls.
|
|
42
|
+
*
|
|
43
|
+
* @param property - The property to get the type for
|
|
44
|
+
* @param property.type
|
|
45
|
+
* @param property.name
|
|
46
|
+
* @returns The actual property type (resolves 'system' to the underlying type)
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const property = { name: '_timestamp', type: 'system' };
|
|
51
|
+
* getActualPropertyType(property); // Returns 'time'
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
function getActualPropertyType(property) {
|
|
55
|
+
if (property.type === 'system') {
|
|
56
|
+
return resolveSystemPropertyType(property.name);
|
|
57
|
+
}
|
|
58
|
+
return property.type;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Map system property names to their actual data types.
|
|
62
|
+
*
|
|
63
|
+
* This mapping is necessary because system properties have `type='system'` in the metadata
|
|
64
|
+
* (for historical reasons - database schema fieldtype 255), but we need to know their
|
|
65
|
+
* actual data types to render appropriate inputs.
|
|
66
|
+
*
|
|
67
|
+
* The mapping is based on the Lime CRM database schema:
|
|
68
|
+
* - System datetime fields: `timestamp`, `createdtime`, `updatedtime`
|
|
69
|
+
* - System integer fields: `id`, `createduser`, `updateduser`
|
|
70
|
+
* - System string fields: `descriptive`
|
|
71
|
+
*
|
|
72
|
+
* @param propertyName - The system property name (with or without underscore prefix)
|
|
73
|
+
* @returns The actual property type
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* resolveSystemPropertyType('_timestamp'); // Returns 'time'
|
|
78
|
+
* resolveSystemPropertyType('timestamp'); // Returns 'time'
|
|
79
|
+
* resolveSystemPropertyType('_id'); // Returns 'integer'
|
|
80
|
+
* resolveSystemPropertyType('unknown'); // Returns 'string' (default)
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
function resolveSystemPropertyType(propertyName) {
|
|
84
|
+
const name = propertyName.replace(/^_/, '');
|
|
85
|
+
return SYSTEM_TYPE_MAP[name] || 'string';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Map Lime CRM property types to Lime Elements date picker types.
|
|
89
|
+
*
|
|
90
|
+
* Lime CRM and Lime Elements use different naming conventions for date/time types,
|
|
91
|
+
* so we need to translate between them:
|
|
92
|
+
*
|
|
93
|
+
* - `'date'` → `'date'` - Date only
|
|
94
|
+
* - `'time'` → `'datetime'` - Full datetime (date + time) in Lime CRM
|
|
95
|
+
* - `'timeofday'` → `'time'` - Time only (hh:mm)
|
|
96
|
+
* - `'month'` → `'month'` - Month picker (YYYY-MM)
|
|
97
|
+
* - `'quarter'` → `'quarter'` - Quarter picker
|
|
98
|
+
* - `'year'` → `'year'` - Year picker
|
|
99
|
+
*
|
|
100
|
+
* @param propertyType - The Lime CRM date/time property type
|
|
101
|
+
* @returns The corresponding Lime Elements date picker type
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* mapPropertyTypeToPickerType('time'); // Returns 'datetime'
|
|
106
|
+
* mapPropertyTypeToPickerType('timeofday'); // Returns 'time'
|
|
107
|
+
* mapPropertyTypeToPickerType('date'); // Returns 'date'
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
function mapPropertyTypeToPickerType(propertyType) {
|
|
111
|
+
return DATE_TIME_TYPE_MAP[propertyType] || 'date';
|
|
112
|
+
}
|
|
113
|
+
|
|
5
114
|
const limeQueryValueInputCss = ":host{display:flex;gap:0.5rem}:host>*{flex-grow:1}*{box-sizing:border-box}.value-input-container{display:flex;flex-direction:row;align-items:flex-start;gap:0.5rem;width:100%}.mode-toggle{flex-shrink:0;flex-grow:0}.placeholder-input{flex-grow:1;display:flex;flex-direction:column;gap:0.5rem}.placeholder-preview{display:flex;align-items:center;gap:0.5rem;padding:0.5rem;background-color:rgba(var(--color-blue-light), 0.1);border-radius:var(--border-radius-small);font-size:0.875rem;color:rgb(var(--color-blue-default));border-left:3px solid rgb(var(--color-blue-default))}.placeholder-preview limel-icon{flex-shrink:0;color:rgb(var(--color-blue-default))}.placeholder-preview span{font-family:var(--font-monospace);word-break:break-all}";
|
|
6
115
|
const LimebbLimeQueryValueInputStyle0 = limeQueryValueInputCss;
|
|
7
116
|
|
|
@@ -166,10 +275,12 @@ const LimeQueryValueInput = /*@__PURE__*/ proxyCustomElement(class LimeQueryValu
|
|
|
166
275
|
if (!property) {
|
|
167
276
|
return this.renderTextInput();
|
|
168
277
|
}
|
|
169
|
-
|
|
278
|
+
// Resolve 'system' type to actual type
|
|
279
|
+
const actualType = getActualPropertyType(property);
|
|
280
|
+
switch (actualType) {
|
|
170
281
|
case 'integer':
|
|
171
282
|
case 'decimal': {
|
|
172
|
-
return this.renderNumberInput(
|
|
283
|
+
return this.renderNumberInput(actualType);
|
|
173
284
|
}
|
|
174
285
|
case 'yesno': {
|
|
175
286
|
return this.renderBooleanInput();
|
|
@@ -177,11 +288,13 @@ const LimeQueryValueInput = /*@__PURE__*/ proxyCustomElement(class LimeQueryValu
|
|
|
177
288
|
case 'option': {
|
|
178
289
|
return this.renderOptionInput(property);
|
|
179
290
|
}
|
|
180
|
-
case 'date':
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
case '
|
|
184
|
-
|
|
291
|
+
case 'date':
|
|
292
|
+
case 'time':
|
|
293
|
+
case 'timeofday':
|
|
294
|
+
case 'year':
|
|
295
|
+
case 'month':
|
|
296
|
+
case 'quarter': {
|
|
297
|
+
return this.renderDateTimeInput(actualType);
|
|
185
298
|
}
|
|
186
299
|
default: {
|
|
187
300
|
return this.renderTextInput();
|
|
@@ -217,13 +330,11 @@ const LimeQueryValueInput = /*@__PURE__*/ proxyCustomElement(class LimeQueryValu
|
|
|
217
330
|
const selectedOption = options.find((o) => o.value === this.value);
|
|
218
331
|
return (h("limel-select", { label: this.label, options: options, value: selectedOption, onChange: this.handleSelectChange }));
|
|
219
332
|
}
|
|
220
|
-
|
|
333
|
+
renderDateTimeInput(type) {
|
|
221
334
|
// Convert string to Date if needed
|
|
222
335
|
const dateValue = typeof this.value === 'string' ? new Date(this.value) : this.value;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
renderTimeInput() {
|
|
226
|
-
return (h("limel-input-field", { label: this.label, type: "time", value: this.value || '', onChange: this.handleTextChange }));
|
|
336
|
+
const pickerType = mapPropertyTypeToPickerType(type);
|
|
337
|
+
return (h("limel-date-picker", { label: this.label, value: dateValue, type: pickerType, onChange: this.handleDateChange }));
|
|
227
338
|
}
|
|
228
339
|
renderMultiValueInput() {
|
|
229
340
|
// For IN operator, allow comma-separated values
|
|
@@ -39,11 +39,9 @@ const LimeQueryBuilder = /*@__PURE__*/ proxyCustomElement(class LimeQueryBuilder
|
|
|
39
39
|
this.limetype = event.detail;
|
|
40
40
|
// Reset filter when limetype changes
|
|
41
41
|
this.filter = undefined;
|
|
42
|
-
// Reset response format when limetype changes
|
|
42
|
+
// Reset response format when limetype changes - empty state
|
|
43
43
|
this.internalResponseFormat = {
|
|
44
|
-
object: {
|
|
45
|
-
_id: null,
|
|
46
|
-
},
|
|
44
|
+
object: {},
|
|
47
45
|
};
|
|
48
46
|
this.emitChange();
|
|
49
47
|
};
|
|
@@ -196,46 +196,29 @@ const ResponseFormatEditor = /*@__PURE__*/ proxyCustomElement(class ResponseForm
|
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
componentWillLoad() {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
// Keep items empty for truly empty objects
|
|
199
|
+
if (!this.value) {
|
|
200
|
+
// No value provided at all, use default _id
|
|
201
|
+
this.items = [{ path: '_id' }];
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (this.isEmptyResponseFormat(this.value)) {
|
|
205
|
+
// Show empty state for explicit empty objects
|
|
207
206
|
this.items = [];
|
|
208
207
|
}
|
|
209
|
-
else if (
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.items = converted;
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
// Empty object property, but not a truly empty value
|
|
216
|
-
// Use default _id for backward compatibility
|
|
217
|
-
this.items = [{ path: '_id' }];
|
|
218
|
-
}
|
|
208
|
+
else if (this.value.object) {
|
|
209
|
+
// Has object property with actual properties
|
|
210
|
+
this.items = propertySelectionToItems(this.value.object);
|
|
219
211
|
}
|
|
220
|
-
else
|
|
221
|
-
//
|
|
222
|
-
this.items = [
|
|
212
|
+
else {
|
|
213
|
+
// If value has aggregates but no object property, initialize items to empty array
|
|
214
|
+
this.items = [];
|
|
223
215
|
}
|
|
224
216
|
}
|
|
225
217
|
componentWillUpdate() {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const isTrulyEmpty = this.value &&
|
|
229
|
-
Object.keys(this.value).length === 0 &&
|
|
230
|
-
!this.value.object &&
|
|
231
|
-
!this.value.aggregates;
|
|
232
|
-
if (isTrulyEmpty) {
|
|
233
|
-
// Keep items empty for truly empty objects
|
|
234
|
-
if (this.items.length > 0) {
|
|
235
|
-
this.items = [];
|
|
236
|
-
}
|
|
218
|
+
if (!this.value) {
|
|
219
|
+
return;
|
|
237
220
|
}
|
|
238
|
-
|
|
221
|
+
if (this.value.object && !this.isEmptyResponseFormat(this.value)) {
|
|
239
222
|
const currentItems = propertySelectionToItems(this.value.object);
|
|
240
223
|
// Check if items have changed
|
|
241
224
|
const itemsChanged = currentItems.length !== this.items.length ||
|
|
@@ -247,10 +230,15 @@ const ResponseFormatEditor = /*@__PURE__*/ proxyCustomElement(class ResponseForm
|
|
|
247
230
|
item.description === current.description);
|
|
248
231
|
});
|
|
249
232
|
if (itemsChanged) {
|
|
250
|
-
// Allow empty items array - don't force _id
|
|
251
233
|
this.items = currentItems;
|
|
252
234
|
}
|
|
253
235
|
}
|
|
236
|
+
else {
|
|
237
|
+
// Either empty response format or no object property - clear items
|
|
238
|
+
if (this.items.length > 0) {
|
|
239
|
+
this.items = [];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
254
242
|
}
|
|
255
243
|
render() {
|
|
256
244
|
if (!this.limetype) {
|
|
@@ -281,6 +269,32 @@ const ResponseFormatEditor = /*@__PURE__*/ proxyCustomElement(class ResponseForm
|
|
|
281
269
|
};
|
|
282
270
|
this.change.emit(responseFormat);
|
|
283
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Check if the response format is empty
|
|
274
|
+
*
|
|
275
|
+
* A response format is considered empty in the following cases:
|
|
276
|
+
* - Empty object: `{}`
|
|
277
|
+
* - Object with empty object property and no aggregates: `{ object: {} }`
|
|
278
|
+
*
|
|
279
|
+
* Returns false for:
|
|
280
|
+
* - `null` or `undefined`
|
|
281
|
+
* - Objects with properties: `{ object: { _id: null } }`
|
|
282
|
+
* - Objects with aggregates: `{ aggregates: {...} }`
|
|
283
|
+
*
|
|
284
|
+
* @param value - The ResponseFormat to check
|
|
285
|
+
* @returns True if the response format is empty, false otherwise
|
|
286
|
+
*/
|
|
287
|
+
isEmptyResponseFormat(value) {
|
|
288
|
+
if (!value) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
if (Object.keys(value).length === 0) {
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
return !!(value.object &&
|
|
295
|
+
Object.keys(value.object).length === 0 &&
|
|
296
|
+
!value.aggregates);
|
|
297
|
+
}
|
|
284
298
|
static get style() { return LimebbLimeQueryResponseFormatEditorStyle0; }
|
|
285
299
|
}, [1, "limebb-lime-query-response-format-editor", {
|
|
286
300
|
"platform": [16],
|
|
@@ -28,11 +28,9 @@ const LimeQueryBuilder = class {
|
|
|
28
28
|
this.limetype = event.detail;
|
|
29
29
|
// Reset filter when limetype changes
|
|
30
30
|
this.filter = undefined;
|
|
31
|
-
// Reset response format when limetype changes
|
|
31
|
+
// Reset response format when limetype changes - empty state
|
|
32
32
|
this.internalResponseFormat = {
|
|
33
|
-
object: {
|
|
34
|
-
_id: null,
|
|
35
|
-
},
|
|
33
|
+
object: {},
|
|
36
34
|
};
|
|
37
35
|
this.emitChange();
|
|
38
36
|
};
|
|
@@ -242,6 +242,115 @@ const LimeQueryFilterNotComponent = class {
|
|
|
242
242
|
};
|
|
243
243
|
LimeQueryFilterNotComponent.style = LimebbLimeQueryFilterNotStyle0;
|
|
244
244
|
|
|
245
|
+
/**
|
|
246
|
+
* System property name to actual type mapping.
|
|
247
|
+
*
|
|
248
|
+
* Maps system property names (with or without underscore prefix) to their actual data types.
|
|
249
|
+
* This mapping is necessary because system properties have `type='system'` in the metadata
|
|
250
|
+
* (for historical reasons - database schema fieldtype 255), but we need to know their
|
|
251
|
+
* actual data types to render appropriate inputs.
|
|
252
|
+
*/
|
|
253
|
+
const SYSTEM_TYPE_MAP = {
|
|
254
|
+
timestamp: 'time',
|
|
255
|
+
createdtime: 'time',
|
|
256
|
+
updatedtime: 'time',
|
|
257
|
+
id: 'integer',
|
|
258
|
+
createduser: 'integer',
|
|
259
|
+
updateduser: 'integer',
|
|
260
|
+
descriptive: 'string',
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Lime CRM date/time property type to Lime Elements date picker type mapping.
|
|
264
|
+
*
|
|
265
|
+
* Maps Lime CRM property types to the corresponding Lime Elements date picker types,
|
|
266
|
+
* as they use different naming conventions.
|
|
267
|
+
*/
|
|
268
|
+
const DATE_TIME_TYPE_MAP = {
|
|
269
|
+
date: 'date',
|
|
270
|
+
time: 'datetime',
|
|
271
|
+
timeofday: 'time',
|
|
272
|
+
month: 'month',
|
|
273
|
+
quarter: 'quarter',
|
|
274
|
+
year: 'year',
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* Get the actual type of a property, resolving 'system' type to the underlying type.
|
|
278
|
+
*
|
|
279
|
+
* System properties in Lime CRM have `type: 'system'` in the metadata (a categorical marker
|
|
280
|
+
* from the database schema fieldtype 255), but we need to know their actual data types
|
|
281
|
+
* to render appropriate input controls.
|
|
282
|
+
*
|
|
283
|
+
* @param property - The property to get the type for
|
|
284
|
+
* @param property.type
|
|
285
|
+
* @param property.name
|
|
286
|
+
* @returns The actual property type (resolves 'system' to the underlying type)
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* const property = { name: '_timestamp', type: 'system' };
|
|
291
|
+
* getActualPropertyType(property); // Returns 'time'
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
function getActualPropertyType(property) {
|
|
295
|
+
if (property.type === 'system') {
|
|
296
|
+
return resolveSystemPropertyType(property.name);
|
|
297
|
+
}
|
|
298
|
+
return property.type;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Map system property names to their actual data types.
|
|
302
|
+
*
|
|
303
|
+
* This mapping is necessary because system properties have `type='system'` in the metadata
|
|
304
|
+
* (for historical reasons - database schema fieldtype 255), but we need to know their
|
|
305
|
+
* actual data types to render appropriate inputs.
|
|
306
|
+
*
|
|
307
|
+
* The mapping is based on the Lime CRM database schema:
|
|
308
|
+
* - System datetime fields: `timestamp`, `createdtime`, `updatedtime`
|
|
309
|
+
* - System integer fields: `id`, `createduser`, `updateduser`
|
|
310
|
+
* - System string fields: `descriptive`
|
|
311
|
+
*
|
|
312
|
+
* @param propertyName - The system property name (with or without underscore prefix)
|
|
313
|
+
* @returns The actual property type
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* resolveSystemPropertyType('_timestamp'); // Returns 'time'
|
|
318
|
+
* resolveSystemPropertyType('timestamp'); // Returns 'time'
|
|
319
|
+
* resolveSystemPropertyType('_id'); // Returns 'integer'
|
|
320
|
+
* resolveSystemPropertyType('unknown'); // Returns 'string' (default)
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
function resolveSystemPropertyType(propertyName) {
|
|
324
|
+
const name = propertyName.replace(/^_/, '');
|
|
325
|
+
return SYSTEM_TYPE_MAP[name] || 'string';
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Map Lime CRM property types to Lime Elements date picker types.
|
|
329
|
+
*
|
|
330
|
+
* Lime CRM and Lime Elements use different naming conventions for date/time types,
|
|
331
|
+
* so we need to translate between them:
|
|
332
|
+
*
|
|
333
|
+
* - `'date'` → `'date'` - Date only
|
|
334
|
+
* - `'time'` → `'datetime'` - Full datetime (date + time) in Lime CRM
|
|
335
|
+
* - `'timeofday'` → `'time'` - Time only (hh:mm)
|
|
336
|
+
* - `'month'` → `'month'` - Month picker (YYYY-MM)
|
|
337
|
+
* - `'quarter'` → `'quarter'` - Quarter picker
|
|
338
|
+
* - `'year'` → `'year'` - Year picker
|
|
339
|
+
*
|
|
340
|
+
* @param propertyType - The Lime CRM date/time property type
|
|
341
|
+
* @returns The corresponding Lime Elements date picker type
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* mapPropertyTypeToPickerType('time'); // Returns 'datetime'
|
|
346
|
+
* mapPropertyTypeToPickerType('timeofday'); // Returns 'time'
|
|
347
|
+
* mapPropertyTypeToPickerType('date'); // Returns 'date'
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
function mapPropertyTypeToPickerType(propertyType) {
|
|
351
|
+
return DATE_TIME_TYPE_MAP[propertyType] || 'date';
|
|
352
|
+
}
|
|
353
|
+
|
|
245
354
|
const limeQueryValueInputCss = ":host{display:flex;gap:0.5rem}:host>*{flex-grow:1}*{box-sizing:border-box}.value-input-container{display:flex;flex-direction:row;align-items:flex-start;gap:0.5rem;width:100%}.mode-toggle{flex-shrink:0;flex-grow:0}.placeholder-input{flex-grow:1;display:flex;flex-direction:column;gap:0.5rem}.placeholder-preview{display:flex;align-items:center;gap:0.5rem;padding:0.5rem;background-color:rgba(var(--color-blue-light), 0.1);border-radius:var(--border-radius-small);font-size:0.875rem;color:rgb(var(--color-blue-default));border-left:3px solid rgb(var(--color-blue-default))}.placeholder-preview limel-icon{flex-shrink:0;color:rgb(var(--color-blue-default))}.placeholder-preview span{font-family:var(--font-monospace);word-break:break-all}";
|
|
246
355
|
const LimebbLimeQueryValueInputStyle0 = limeQueryValueInputCss;
|
|
247
356
|
|
|
@@ -404,10 +513,12 @@ const LimeQueryValueInput = class {
|
|
|
404
513
|
if (!property) {
|
|
405
514
|
return this.renderTextInput();
|
|
406
515
|
}
|
|
407
|
-
|
|
516
|
+
// Resolve 'system' type to actual type
|
|
517
|
+
const actualType = getActualPropertyType(property);
|
|
518
|
+
switch (actualType) {
|
|
408
519
|
case 'integer':
|
|
409
520
|
case 'decimal': {
|
|
410
|
-
return this.renderNumberInput(
|
|
521
|
+
return this.renderNumberInput(actualType);
|
|
411
522
|
}
|
|
412
523
|
case 'yesno': {
|
|
413
524
|
return this.renderBooleanInput();
|
|
@@ -415,11 +526,13 @@ const LimeQueryValueInput = class {
|
|
|
415
526
|
case 'option': {
|
|
416
527
|
return this.renderOptionInput(property);
|
|
417
528
|
}
|
|
418
|
-
case 'date':
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
case '
|
|
422
|
-
|
|
529
|
+
case 'date':
|
|
530
|
+
case 'time':
|
|
531
|
+
case 'timeofday':
|
|
532
|
+
case 'year':
|
|
533
|
+
case 'month':
|
|
534
|
+
case 'quarter': {
|
|
535
|
+
return this.renderDateTimeInput(actualType);
|
|
423
536
|
}
|
|
424
537
|
default: {
|
|
425
538
|
return this.renderTextInput();
|
|
@@ -455,13 +568,11 @@ const LimeQueryValueInput = class {
|
|
|
455
568
|
const selectedOption = options.find((o) => o.value === this.value);
|
|
456
569
|
return (h("limel-select", { label: this.label, options: options, value: selectedOption, onChange: this.handleSelectChange }));
|
|
457
570
|
}
|
|
458
|
-
|
|
571
|
+
renderDateTimeInput(type) {
|
|
459
572
|
// Convert string to Date if needed
|
|
460
573
|
const dateValue = typeof this.value === 'string' ? new Date(this.value) : this.value;
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
renderTimeInput() {
|
|
464
|
-
return (h("limel-input-field", { label: this.label, type: "time", value: this.value || '', onChange: this.handleTextChange }));
|
|
574
|
+
const pickerType = mapPropertyTypeToPickerType(type);
|
|
575
|
+
return (h("limel-date-picker", { label: this.label, value: dateValue, type: pickerType, onChange: this.handleDateChange }));
|
|
465
576
|
}
|
|
466
577
|
renderMultiValueInput() {
|
|
467
578
|
// For IN operator, allow comma-separated values
|
|
@@ -192,46 +192,29 @@ const ResponseFormatEditor = class {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
componentWillLoad() {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// Keep items empty for truly empty objects
|
|
195
|
+
if (!this.value) {
|
|
196
|
+
// No value provided at all, use default _id
|
|
197
|
+
this.items = [{ path: '_id' }];
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (this.isEmptyResponseFormat(this.value)) {
|
|
201
|
+
// Show empty state for explicit empty objects
|
|
203
202
|
this.items = [];
|
|
204
203
|
}
|
|
205
|
-
else if (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
this.items = converted;
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
// Empty object property, but not a truly empty value
|
|
212
|
-
// Use default _id for backward compatibility
|
|
213
|
-
this.items = [{ path: '_id' }];
|
|
214
|
-
}
|
|
204
|
+
else if (this.value.object) {
|
|
205
|
+
// Has object property with actual properties
|
|
206
|
+
this.items = propertySelectionToItems(this.value.object);
|
|
215
207
|
}
|
|
216
|
-
else
|
|
217
|
-
//
|
|
218
|
-
this.items = [
|
|
208
|
+
else {
|
|
209
|
+
// If value has aggregates but no object property, initialize items to empty array
|
|
210
|
+
this.items = [];
|
|
219
211
|
}
|
|
220
212
|
}
|
|
221
213
|
componentWillUpdate() {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const isTrulyEmpty = this.value &&
|
|
225
|
-
Object.keys(this.value).length === 0 &&
|
|
226
|
-
!this.value.object &&
|
|
227
|
-
!this.value.aggregates;
|
|
228
|
-
if (isTrulyEmpty) {
|
|
229
|
-
// Keep items empty for truly empty objects
|
|
230
|
-
if (this.items.length > 0) {
|
|
231
|
-
this.items = [];
|
|
232
|
-
}
|
|
214
|
+
if (!this.value) {
|
|
215
|
+
return;
|
|
233
216
|
}
|
|
234
|
-
|
|
217
|
+
if (this.value.object && !this.isEmptyResponseFormat(this.value)) {
|
|
235
218
|
const currentItems = propertySelectionToItems(this.value.object);
|
|
236
219
|
// Check if items have changed
|
|
237
220
|
const itemsChanged = currentItems.length !== this.items.length ||
|
|
@@ -243,10 +226,15 @@ const ResponseFormatEditor = class {
|
|
|
243
226
|
item.description === current.description);
|
|
244
227
|
});
|
|
245
228
|
if (itemsChanged) {
|
|
246
|
-
// Allow empty items array - don't force _id
|
|
247
229
|
this.items = currentItems;
|
|
248
230
|
}
|
|
249
231
|
}
|
|
232
|
+
else {
|
|
233
|
+
// Either empty response format or no object property - clear items
|
|
234
|
+
if (this.items.length > 0) {
|
|
235
|
+
this.items = [];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
250
238
|
}
|
|
251
239
|
render() {
|
|
252
240
|
if (!this.limetype) {
|
|
@@ -277,6 +265,32 @@ const ResponseFormatEditor = class {
|
|
|
277
265
|
};
|
|
278
266
|
this.change.emit(responseFormat);
|
|
279
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Check if the response format is empty
|
|
270
|
+
*
|
|
271
|
+
* A response format is considered empty in the following cases:
|
|
272
|
+
* - Empty object: `{}`
|
|
273
|
+
* - Object with empty object property and no aggregates: `{ object: {} }`
|
|
274
|
+
*
|
|
275
|
+
* Returns false for:
|
|
276
|
+
* - `null` or `undefined`
|
|
277
|
+
* - Objects with properties: `{ object: { _id: null } }`
|
|
278
|
+
* - Objects with aggregates: `{ aggregates: {...} }`
|
|
279
|
+
*
|
|
280
|
+
* @param value - The ResponseFormat to check
|
|
281
|
+
* @returns True if the response format is empty, false otherwise
|
|
282
|
+
*/
|
|
283
|
+
isEmptyResponseFormat(value) {
|
|
284
|
+
if (!value) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
if (Object.keys(value).length === 0) {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
return !!(value.object &&
|
|
291
|
+
Object.keys(value.object).length === 0 &&
|
|
292
|
+
!value.aggregates);
|
|
293
|
+
}
|
|
280
294
|
};
|
|
281
295
|
ResponseFormatEditor.style = LimebbLimeQueryResponseFormatEditorStyle0;
|
|
282
296
|
|