@solidxai/core-ui 0.1.9-beta.12 → 0.1.9-beta.14
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/dist/components/common/SettingsComponent.js +1 -1
- package/dist/components/common/SettingsComponent.js.map +1 -1
- package/dist/components/common/SettingsComponent.module.css +17 -0
- package/dist/components/common/SettingsComponent.tsx +1 -1
- package/dist/components/core/chatter/SolidChatter.d.ts.map +1 -1
- package/dist/components/core/chatter/SolidChatter.js +24 -11
- package/dist/components/core/chatter/SolidChatter.js.map +1 -1
- package/dist/components/core/chatter/SolidChatter.tsx +20 -6
- package/dist/components/core/chatter/SolidChatterHeader.d.ts.map +1 -1
- package/dist/components/core/chatter/SolidChatterHeader.js +1 -1
- package/dist/components/core/chatter/SolidChatterHeader.js.map +1 -1
- package/dist/components/core/chatter/SolidChatterHeader.tsx +4 -0
- package/dist/components/core/chatter/SolidChatterMessageBox.d.ts +1 -0
- package/dist/components/core/chatter/SolidChatterMessageBox.d.ts.map +1 -1
- package/dist/components/core/chatter/SolidChatterMessageBox.js +150 -11
- package/dist/components/core/chatter/SolidChatterMessageBox.js.map +1 -1
- package/dist/components/core/chatter/SolidChatterMessageBox.tsx +252 -11
- package/dist/components/core/chatter/SolidMessageComposer.js +2 -2
- package/dist/components/core/chatter/SolidMessageComposer.js.map +1 -1
- package/dist/components/core/chatter/SolidMessageComposer.tsx +2 -2
- package/dist/components/core/chatter/chatter.module.css +1 -1
- package/dist/components/core/common/SolidGlobalSearchElement.d.ts.map +1 -1
- package/dist/components/core/common/SolidGlobalSearchElement.js +13 -2
- package/dist/components/core/common/SolidGlobalSearchElement.js.map +1 -1
- package/dist/components/core/common/SolidGlobalSearchElement.tsx +11 -2
- package/dist/components/core/form/SolidFormView.d.ts.map +1 -1
- package/dist/components/core/form/SolidFormView.js +6 -2
- package/dist/components/core/form/SolidFormView.js.map +1 -1
- package/dist/components/core/form/SolidFormView.tsx +6 -1
- package/dist/components/core/form/field-quality-check-fixes.md +201 -0
- package/dist/components/core/form/fields/SolidLongTextField.d.ts +0 -1
- package/dist/components/core/form/fields/SolidLongTextField.d.ts.map +1 -1
- package/dist/components/core/form/fields/SolidLongTextField.js +0 -52
- package/dist/components/core/form/fields/SolidLongTextField.js.map +1 -1
- package/dist/components/core/form/fields/SolidLongTextField.tsx +0 -95
- package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.d.ts.map +1 -1
- package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.js +16 -14
- package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.js.map +1 -1
- package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.tsx +9 -1
- package/dist/components/core/form/fields/relations/SolidRelationManyToOneField.d.ts.map +1 -1
- package/dist/components/core/form/fields/relations/SolidRelationManyToOneField.js +12 -12
- package/dist/components/core/form/fields/relations/SolidRelationManyToOneField.js.map +1 -1
- package/dist/components/core/form/fields/relations/SolidRelationManyToOneField.tsx +10 -6
- package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.d.ts.map +1 -1
- package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.js +9 -7
- package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.js.map +1 -1
- package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.tsx +7 -1
- package/dist/components/core/list/SolidListView.d.ts.map +1 -1
- package/dist/components/core/list/SolidListView.js +2 -0
- package/dist/components/core/list/SolidListView.js.map +1 -1
- package/dist/components/core/list/SolidListView.tsx +2 -0
- package/dist/components/core/list/SolidListViewColumn.d.ts +2 -1
- package/dist/components/core/list/SolidListViewColumn.d.ts.map +1 -1
- package/dist/components/core/list/SolidListViewColumn.js +2 -2
- package/dist/components/core/list/SolidListViewColumn.js.map +1 -1
- package/dist/components/core/list/SolidListViewColumn.tsx +4 -3
- package/dist/components/core/list/columns/SolidRelationColumn.d.ts +1 -1
- package/dist/components/core/list/columns/SolidRelationColumn.d.ts.map +1 -1
- package/dist/components/core/list/columns/SolidRelationColumn.js +2 -2
- package/dist/components/core/list/columns/SolidRelationColumn.js.map +1 -1
- package/dist/components/core/list/columns/SolidRelationColumn.tsx +2 -2
- package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.d.ts +2 -2
- package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.d.ts.map +1 -1
- package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.js +9 -4
- package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.js.map +1 -1
- package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.tsx +14 -4
- package/dist/components/core/list/field-quality-check-fixes.md +178 -0
- package/dist/components/layout/AdminTopHeader.d.ts.map +1 -1
- package/dist/components/layout/AdminTopHeader.js +5 -1
- package/dist/components/layout/AdminTopHeader.js.map +1 -1
- package/dist/components/layout/AdminTopHeader.tsx +5 -1
- package/dist/components/shad-cn-ui/SolidAutocomplete.d.ts +2 -1
- package/dist/components/shad-cn-ui/SolidAutocomplete.d.ts.map +1 -1
- package/dist/components/shad-cn-ui/SolidAutocomplete.js +45 -6
- package/dist/components/shad-cn-ui/SolidAutocomplete.js.map +1 -1
- package/dist/components/shad-cn-ui/SolidAutocomplete.tsx +68 -22
- package/dist/components/shad-cn-ui/SolidDialog.d.ts.map +1 -1
- package/dist/components/shad-cn-ui/SolidDialog.js +38 -4
- package/dist/components/shad-cn-ui/SolidDialog.js.map +1 -1
- package/dist/components/shad-cn-ui/SolidDialog.tsx +47 -3
- package/dist/helpers/registry.js.map +1 -1
- package/dist/helpers/registry.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.ts +1 -0
- package/dist/redux/api/solidChatterMessageApi.d.ts +2 -1
- package/dist/redux/api/solidChatterMessageApi.d.ts.map +1 -1
- package/dist/redux/api/solidChatterMessageApi.js +11 -1
- package/dist/redux/api/solidChatterMessageApi.js.map +1 -1
- package/dist/redux/api/solidChatterMessageApi.ts +10 -1
- package/dist/redux/store/defaultStoreConfig.d.ts +1 -0
- package/dist/redux/store/defaultStoreConfig.d.ts.map +1 -1
- package/dist/resources/globals.css +5 -0
- package/dist/resources/shadcn-base.css +24 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/solid-core.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
|
|
2
2
|
import { getTextColor, stringToColor } from '../../../helpers/getRandomColors'
|
|
3
3
|
import Image from "../../common/Image"
|
|
4
|
-
import { useMemo, useState } from 'react'
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
5
5
|
import styles from './chatter.module.css'
|
|
6
6
|
import { SolidChatterCustomMessage } from './SolidChatterCustomMessage'
|
|
7
7
|
import { SolidChatterAuditMessage } from './SolidChatterAuditMessage'
|
|
8
|
-
import { Check, GitBranch, MessageSquare } from 'lucide-react'
|
|
9
|
-
import { SolidButton, SolidLightbox, SolidTag, SolidTooltip, SolidTooltipContent, SolidTooltipTrigger, SolidIcon, type SolidIconName } from '../../shad-cn-ui'
|
|
8
|
+
import { Check, GitBranch, MessageSquare, Paperclip, Pencil, Trash2, X } from 'lucide-react'
|
|
9
|
+
import { SolidButton, SolidLightbox, SolidTag, SolidTooltip, SolidTooltipContent, SolidTooltipTrigger, SolidIcon, SolidTextarea, type SolidIconName } from '../../shad-cn-ui'
|
|
10
10
|
import type { SolidLightboxSlide } from '../../shad-cn-ui/SolidLightbox'
|
|
11
|
-
import { usePatchChatterMessageMutation } from '../../../redux/api/solidChatterMessageApi'
|
|
11
|
+
import { usePatchChatterMessageMutation, useUpdateChatterNoteMessageMutation } from '../../../redux/api/solidChatterMessageApi'
|
|
12
|
+
import { useSession } from '../../../hooks/useSession'
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
messageId?: number | string,
|
|
15
16
|
user: string,
|
|
17
|
+
userId?: number,
|
|
16
18
|
messageType?: string,
|
|
17
19
|
message?: any,
|
|
18
20
|
time?: string,
|
|
@@ -54,11 +56,22 @@ const getFileIcon = (mimeType: string): SolidIconName => {
|
|
|
54
56
|
};
|
|
55
57
|
|
|
56
58
|
export const SolidChatterMessageBox = (props: Props) => {
|
|
57
|
-
const { messageId, user, messageType, message, time, auditRecord, media, messageSubType, status, modelDisplayName, modelUserKey, onRefresh } = props;
|
|
59
|
+
const { messageId, user, userId, messageType, message, time, auditRecord, media, messageSubType, status, modelDisplayName, modelUserKey, onRefresh } = props;
|
|
58
60
|
const [lightboxSlides, setLightboxSlides] = useState<SolidLightboxSlide[]>([]);
|
|
59
61
|
const [openLightbox, setOpenLightbox] = useState(false);
|
|
60
62
|
const [taskStatus, setTaskStatus] = useState<string | undefined>(status);
|
|
63
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
64
|
+
const [localMessage, setLocalMessage] = useState(message ?? '');
|
|
65
|
+
const [editedMessage, setEditedMessage] = useState(message ?? '');
|
|
66
|
+
const [hasPendingOptimisticUpdate, setHasPendingOptimisticUpdate] = useState(false);
|
|
67
|
+
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
|
68
|
+
const [removedAttachmentIds, setRemovedAttachmentIds] = useState<number[]>([]);
|
|
69
|
+
const [optimisticRemovedAttachmentIds, setOptimisticRemovedAttachmentIds] = useState<number[]>([]);
|
|
70
|
+
const [hasPendingOptimisticAttachmentUpdate, setHasPendingOptimisticAttachmentUpdate] = useState(false);
|
|
71
|
+
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
61
72
|
const [patchChatterMessage, { isLoading: isUpdatingTaskStatus }] = usePatchChatterMessageMutation();
|
|
73
|
+
const [updateChatterNoteMessage, { isLoading: isUpdatingNote }] = useUpdateChatterNoteMessageMutation();
|
|
74
|
+
const { data: session } = useSession();
|
|
62
75
|
|
|
63
76
|
const avatarStyle = useMemo(() => {
|
|
64
77
|
const bg = stringToColor(user)
|
|
@@ -116,6 +129,56 @@ export const SolidChatterMessageBox = (props: Props) => {
|
|
|
116
129
|
|
|
117
130
|
const isTaskMessage = messageSubType === 'task';
|
|
118
131
|
const isTaskCompleted = (taskStatus ?? '').toLowerCase() === 'completed';
|
|
132
|
+
const isCustomMessage = messageType === 'custom';
|
|
133
|
+
const isEditableSubtype = messageSubType === 'custom' || messageSubType === 'note';
|
|
134
|
+
const isCurrentUserAuthor = !!(session?.user?.id && userId && Number(session.user.id) === Number(userId));
|
|
135
|
+
const canEditNote = Boolean(messageId && isCustomMessage && isEditableSubtype && isCurrentUserAuthor);
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
const incomingMessage = message ?? '';
|
|
139
|
+
|
|
140
|
+
// Keep optimistic message visible until server data catches up.
|
|
141
|
+
if (hasPendingOptimisticUpdate && incomingMessage !== localMessage) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (hasPendingOptimisticUpdate && incomingMessage === localMessage) {
|
|
146
|
+
setHasPendingOptimisticUpdate(false);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
setLocalMessage(incomingMessage);
|
|
150
|
+
if (!isEditing) {
|
|
151
|
+
setEditedMessage(incomingMessage);
|
|
152
|
+
}
|
|
153
|
+
}, [message, isEditing, hasPendingOptimisticUpdate, localMessage]);
|
|
154
|
+
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (!isEditing) {
|
|
157
|
+
setSelectedFiles([]);
|
|
158
|
+
if (!hasPendingOptimisticAttachmentUpdate) {
|
|
159
|
+
setRemovedAttachmentIds([]);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}, [isEditing, hasPendingOptimisticAttachmentUpdate]);
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (!hasPendingOptimisticAttachmentUpdate) return;
|
|
166
|
+
const latestAttachmentIds = (media?.messageAttachments || []).map((attachment) => attachment.id);
|
|
167
|
+
const stillPresent = optimisticRemovedAttachmentIds.some((id) => latestAttachmentIds.includes(id));
|
|
168
|
+
if (!stillPresent) {
|
|
169
|
+
setHasPendingOptimisticAttachmentUpdate(false);
|
|
170
|
+
setOptimisticRemovedAttachmentIds([]);
|
|
171
|
+
setRemovedAttachmentIds([]);
|
|
172
|
+
}
|
|
173
|
+
}, [media?.messageAttachments, hasPendingOptimisticAttachmentUpdate, optimisticRemovedAttachmentIds]);
|
|
174
|
+
|
|
175
|
+
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
176
|
+
if (event.target.files) {
|
|
177
|
+
const files = Array.from(event.target.files);
|
|
178
|
+
setSelectedFiles(prev => [...prev, ...files]);
|
|
179
|
+
event.target.value = '';
|
|
180
|
+
}
|
|
181
|
+
};
|
|
119
182
|
|
|
120
183
|
const handleMarkTaskDone = async () => {
|
|
121
184
|
if (!messageId || isUpdatingTaskStatus) return;
|
|
@@ -128,6 +191,72 @@ export const SolidChatterMessageBox = (props: Props) => {
|
|
|
128
191
|
}
|
|
129
192
|
};
|
|
130
193
|
|
|
194
|
+
const handleEditSave = async () => {
|
|
195
|
+
if (!messageId || isUpdatingNote) return;
|
|
196
|
+
const trimmedMessage = editedMessage?.trim();
|
|
197
|
+
const hasBodyChange = trimmedMessage && trimmedMessage !== (message ?? '').trim();
|
|
198
|
+
const hasAttachmentOps = removedAttachmentIds.length > 0 || selectedFiles.length > 0;
|
|
199
|
+
if (!hasBodyChange && !hasAttachmentOps) return;
|
|
200
|
+
if (!trimmedMessage) return;
|
|
201
|
+
const nextMessage = trimmedMessage;
|
|
202
|
+
// Optimistic local update to remove UI lag before refetch resolves.
|
|
203
|
+
setLocalMessage(nextMessage);
|
|
204
|
+
setHasPendingOptimisticUpdate(true);
|
|
205
|
+
if (removedAttachmentIds.length > 0) {
|
|
206
|
+
setOptimisticRemovedAttachmentIds((prev) => Array.from(new Set([...prev, ...removedAttachmentIds])));
|
|
207
|
+
setHasPendingOptimisticAttachmentUpdate(true);
|
|
208
|
+
}
|
|
209
|
+
setIsEditing(false);
|
|
210
|
+
try {
|
|
211
|
+
const formData = new FormData();
|
|
212
|
+
formData.append('messageBody', nextMessage);
|
|
213
|
+
if (removedAttachmentIds.length > 0) {
|
|
214
|
+
formData.append('removeAttachmentIds', removedAttachmentIds.join(','));
|
|
215
|
+
}
|
|
216
|
+
selectedFiles.forEach((file) => formData.append('messageAttachments', file));
|
|
217
|
+
|
|
218
|
+
await updateChatterNoteMessage({ id: messageId, data: formData }).unwrap();
|
|
219
|
+
onRefresh?.();
|
|
220
|
+
} catch (e) {
|
|
221
|
+
// Revert optimistic update on failure.
|
|
222
|
+
setLocalMessage(message ?? '');
|
|
223
|
+
setHasPendingOptimisticUpdate(false);
|
|
224
|
+
setHasPendingOptimisticAttachmentUpdate(false);
|
|
225
|
+
setOptimisticRemovedAttachmentIds([]);
|
|
226
|
+
setIsEditing(true);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const handleCancelEdit = () => {
|
|
231
|
+
setEditedMessage(localMessage ?? '');
|
|
232
|
+
setSelectedFiles([]);
|
|
233
|
+
setRemovedAttachmentIds([]);
|
|
234
|
+
setIsEditing(false);
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const formatFileSize = (size: number) => {
|
|
238
|
+
if (!size) return '';
|
|
239
|
+
return size >= 1024 * 1024
|
|
240
|
+
? `${(size / (1024 * 1024)).toFixed(1)} MB`
|
|
241
|
+
: `${(size / 1024).toFixed(1)} KB`;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const hiddenAttachmentIds = new Set([
|
|
245
|
+
...removedAttachmentIds,
|
|
246
|
+
...optimisticRemovedAttachmentIds,
|
|
247
|
+
]);
|
|
248
|
+
const visibleAttachments = (media?.messageAttachments || []).filter(
|
|
249
|
+
(attachment) => !hiddenAttachmentIds.has(attachment.id)
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const toggleRemoveAttachment = (attachmentId: number) => {
|
|
253
|
+
setRemovedAttachmentIds(prev =>
|
|
254
|
+
prev.includes(attachmentId)
|
|
255
|
+
? prev.filter(id => id !== attachmentId)
|
|
256
|
+
: [...prev, attachmentId]
|
|
257
|
+
);
|
|
258
|
+
};
|
|
259
|
+
|
|
131
260
|
return (
|
|
132
261
|
<div className={styles.solidChatterMessageBox}>
|
|
133
262
|
<div className={styles.solidChatterMessageCard}>
|
|
@@ -153,7 +282,21 @@ export const SolidChatterMessageBox = (props: Props) => {
|
|
|
153
282
|
</SolidTooltipContent>
|
|
154
283
|
</SolidTooltip>
|
|
155
284
|
</div>
|
|
156
|
-
<
|
|
285
|
+
<div className='flex align-items-center gap-2'>
|
|
286
|
+
{canEditNote && !isEditing && (
|
|
287
|
+
<SolidButton
|
|
288
|
+
type="button"
|
|
289
|
+
size="sm"
|
|
290
|
+
variant="ghost"
|
|
291
|
+
className="solid-icon-button"
|
|
292
|
+
leftIcon={<Pencil size={12} />}
|
|
293
|
+
onClick={() => setIsEditing(true)}
|
|
294
|
+
aria-label="Edit note"
|
|
295
|
+
title="Edit note"
|
|
296
|
+
/>
|
|
297
|
+
)}
|
|
298
|
+
<span className={styles.solidChatterTime}>{time}</span>
|
|
299
|
+
</div>
|
|
157
300
|
</div>
|
|
158
301
|
{modelDisplayName && (
|
|
159
302
|
<p className={`${styles.solidChatterMeta} m-0`}>
|
|
@@ -161,17 +304,115 @@ export const SolidChatterMessageBox = (props: Props) => {
|
|
|
161
304
|
{modelUserKey && <> · <span className='font-medium'>{modelUserKey}</span></>}
|
|
162
305
|
</p>
|
|
163
306
|
)}
|
|
164
|
-
{
|
|
307
|
+
{localMessage && !isEditing && (
|
|
165
308
|
<div className={styles.solidMessageWrapper}>
|
|
166
|
-
{
|
|
309
|
+
{messageType === 'audit'
|
|
310
|
+
? <SolidChatterAuditMessage auditRecord={auditRecord} />
|
|
311
|
+
: <SolidChatterCustomMessage message={localMessage} />}
|
|
312
|
+
</div>
|
|
313
|
+
)}
|
|
314
|
+
{isEditing && (
|
|
315
|
+
<div className='flex flex-column gap-2'>
|
|
316
|
+
<SolidTextarea
|
|
317
|
+
value={editedMessage}
|
|
318
|
+
onChange={(e) => setEditedMessage(e.target.value)}
|
|
319
|
+
rows={4}
|
|
320
|
+
className="w-full py-2"
|
|
321
|
+
/>
|
|
322
|
+
<div className='flex flex-column gap-2'>
|
|
323
|
+
<input
|
|
324
|
+
ref={fileInputRef}
|
|
325
|
+
id={`note-edit-file-${messageId}`}
|
|
326
|
+
type="file"
|
|
327
|
+
multiple
|
|
328
|
+
onChange={handleFileSelect}
|
|
329
|
+
style={{ display: 'none' }}
|
|
330
|
+
/>
|
|
331
|
+
{selectedFiles.length > 0 && (
|
|
332
|
+
<div className='flex flex-column gap-1'>
|
|
333
|
+
{selectedFiles.map((file, index) => (
|
|
334
|
+
<div key={`${file.name}-${index}`} className='flex align-items-center justify-content-between text-xs'>
|
|
335
|
+
<span>{file.name} ({formatFileSize(file.size)})</span>
|
|
336
|
+
<SolidButton
|
|
337
|
+
type="button"
|
|
338
|
+
size="sm"
|
|
339
|
+
variant="ghost"
|
|
340
|
+
className='solid-icon-button'
|
|
341
|
+
leftIcon={<X size={12} />}
|
|
342
|
+
onClick={() => setSelectedFiles(prev => prev.filter((_, i) => i !== index))}
|
|
343
|
+
aria-label={`Remove ${file.name}`}
|
|
344
|
+
/>
|
|
345
|
+
</div>
|
|
346
|
+
))}
|
|
347
|
+
</div>
|
|
348
|
+
)}
|
|
349
|
+
</div>
|
|
350
|
+
<div className='flex align-items-center justify-content-between gap-2 flex-wrap'>
|
|
351
|
+
<div className='flex align-items-center gap-2'>
|
|
352
|
+
<SolidButton
|
|
353
|
+
type="button"
|
|
354
|
+
size="sm"
|
|
355
|
+
variant="ghost"
|
|
356
|
+
className="solid-icon-button"
|
|
357
|
+
leftIcon={<Paperclip size={14} />}
|
|
358
|
+
onClick={() => fileInputRef.current?.click()}
|
|
359
|
+
aria-label="Attach files"
|
|
360
|
+
title="Attach files"
|
|
361
|
+
/>
|
|
362
|
+
<span className='text-xs text-color-secondary'>Attach file</span>
|
|
363
|
+
</div>
|
|
364
|
+
<div className='flex align-items-center justify-content-end gap-2'>
|
|
365
|
+
<SolidButton
|
|
366
|
+
type="button"
|
|
367
|
+
size="sm"
|
|
368
|
+
variant="outline"
|
|
369
|
+
leftIcon={<X size={12} />}
|
|
370
|
+
onClick={handleCancelEdit}
|
|
371
|
+
>
|
|
372
|
+
Cancel
|
|
373
|
+
</SolidButton>
|
|
374
|
+
<SolidButton
|
|
375
|
+
type="button"
|
|
376
|
+
size="sm"
|
|
377
|
+
variant="primary"
|
|
378
|
+
loading={isUpdatingNote}
|
|
379
|
+
leftIcon={<Check size={12} />}
|
|
380
|
+
onClick={handleEditSave}
|
|
381
|
+
disabled={!editedMessage?.trim() || (removedAttachmentIds.length === 0 && selectedFiles.length === 0 && editedMessage.trim() === (message ?? '').trim())}
|
|
382
|
+
>
|
|
383
|
+
Save
|
|
384
|
+
</SolidButton>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
167
387
|
</div>
|
|
168
388
|
)}
|
|
169
|
-
{
|
|
389
|
+
{visibleAttachments.length > 0 && (
|
|
170
390
|
<div className={styles.solidChatterAttachments}>
|
|
171
|
-
{
|
|
391
|
+
{visibleAttachments.map((attachment) => {
|
|
172
392
|
const isImage = attachment.mimeType.startsWith('image/');
|
|
173
393
|
return (
|
|
174
|
-
<div key={attachment.id} className={styles.solidChatterAttachment}>
|
|
394
|
+
<div key={attachment.id} className={styles.solidChatterAttachment} style={{ position: 'relative' }}>
|
|
395
|
+
{isEditing && canEditNote && (
|
|
396
|
+
<SolidButton
|
|
397
|
+
type="button"
|
|
398
|
+
size="sm"
|
|
399
|
+
variant="ghost"
|
|
400
|
+
className="solid-icon-button"
|
|
401
|
+
leftIcon={<Trash2 size={12} color="#dc2626" />}
|
|
402
|
+
onClick={() => toggleRemoveAttachment(attachment.id)}
|
|
403
|
+
aria-label={`Remove ${attachment.originalFileName}`}
|
|
404
|
+
title={`Remove ${attachment.originalFileName}`}
|
|
405
|
+
style={{
|
|
406
|
+
position: 'absolute',
|
|
407
|
+
top: -8,
|
|
408
|
+
right: -8,
|
|
409
|
+
zIndex: 2,
|
|
410
|
+
background: '#fff',
|
|
411
|
+
border: '1px solid #fecaca',
|
|
412
|
+
borderRadius: '999px',
|
|
413
|
+
}}
|
|
414
|
+
/>
|
|
415
|
+
)}
|
|
175
416
|
{isImage ? (
|
|
176
417
|
<div
|
|
177
418
|
className='cursor-pointer'
|
|
@@ -84,7 +84,7 @@ export var SolidMessageComposer = function (_a) {
|
|
|
84
84
|
_a.trys.push([1, 3, , 4]);
|
|
85
85
|
formData_1 = new FormData();
|
|
86
86
|
formData_1.append('messageType', "custom");
|
|
87
|
-
formData_1.append('messageSubType', "
|
|
87
|
+
formData_1.append('messageSubType', "note");
|
|
88
88
|
formData_1.append('messageBody', message);
|
|
89
89
|
formData_1.append('coModelEntityId', id);
|
|
90
90
|
formData_1.append('coModelName', modelSingularName);
|
|
@@ -120,7 +120,7 @@ export var SolidMessageComposer = function (_a) {
|
|
|
120
120
|
? "".concat((size / (1024 * 1024)).toFixed(1), " MB")
|
|
121
121
|
: "".concat((size / 1024).toFixed(1), " KB");
|
|
122
122
|
};
|
|
123
|
-
return (_jsxs("form", { className: styles.chatterMessageComposer, onSubmit: handleSubmit, children: [_jsxs("div", { className: "".concat(styles.solidMessageWrapper, " flex flex-column gap-2 w-full"), children: [_jsx("div", { className: 'flex align-items-center justify-content-between', children: _jsx("p", { className: 'form-field-label m-0', children: type === 'email' ? 'Email Message' : 'Internal Note' }) }), _jsx(SolidTextarea, { value: message, onChange: function (e) { return setMessage(e.target.value); }, placeholder: type === 'email' ? 'Send a message to followers' : 'Log an internal note.', className: "w-full p-
|
|
123
|
+
return (_jsxs("form", { className: styles.chatterMessageComposer, onSubmit: handleSubmit, children: [_jsxs("div", { className: "".concat(styles.solidMessageWrapper, " flex flex-column gap-2 w-full"), children: [_jsx("div", { className: 'flex align-items-center justify-content-between', children: _jsx("p", { className: 'form-field-label m-0', children: type === 'email' ? 'Email Message' : 'Internal Note' }) }), _jsx(SolidTextarea, { value: message, onChange: function (e) { return setMessage(e.target.value); }, placeholder: type === 'email' ? 'Send a message to followers' : 'Log an internal note.', className: "w-full p-2", rows: 4 }), _jsxs("div", { className: 'flex align-items-center justify-content-between flex-wrap gap-2', children: [_jsxs("div", { className: 'flex align-items-center gap-2', children: [_jsx("input", { type: "file", ref: fileInputRef, onChange: handleFileSelect, multiple: true, style: { display: 'none' } }), _jsx(SolidButton, { type: "button", variant: "outline", size: "sm", className: "solid-icon-button", leftIcon: _jsx(Paperclip, { size: 14 }), onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, "aria-label": "Attach files", title: "Attach files" }), _jsx("span", { className: 'text-xs text-color-secondary', children: "Attach file" })] }), _jsxs("div", { className: 'flex align-items-center gap-2', children: [_jsx(SolidButton, { type: 'submit', size: 'sm', className: 'gap-2 solid-purple-button', variant: 'primary', loading: isLoading, children: type === 'email' ? 'Send' : 'Log' }), _jsx(SolidButton, { type: 'button', size: 'sm', variant: 'ghost', onClick: function () {
|
|
124
124
|
setMessage('');
|
|
125
125
|
setSelectedFiles([]);
|
|
126
126
|
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolidMessageComposer.js","sourceRoot":"","sources":["../../../../src/components/core/chatter/SolidMessageComposer.tsx"],"names":[],"mappings":"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","sourcesContent":["import styles from './chatter.module.css'\nimport { useCreateChatterMessageMutation } from '../../../redux/api/solidChatterMessageApi'\nimport { useEffect, useState, useRef } from 'react'\nimport { ERROR_MESSAGES } from '../../../constants/error-messages'\nimport { useSession } from '../../../hooks/useSession'\nimport { SolidButton, SolidTextarea } from '../../shad-cn-ui'\nimport { FileText, Paperclip, X } from 'lucide-react'\n\ninterface SolidMessageComposerProps {\n type?: string;\n modelSingularName?: any;\n refetch?: any;\n id?: any;\n onCancel?: () => void;\n modelUserKey?: string;\n}\n\nexport const SolidMessageComposer = ({ type, modelSingularName, refetch, id, onCancel, modelUserKey }: SolidMessageComposerProps) => {\n const [message, setMessage] = useState('');\n const [selectedFiles, setSelectedFiles] = useState<File[]>([]);\n\n const { data: session, status } = useSession();\n const user = session?.user;\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // const { data: viewLayoutData } = useGetSolidViewLayoutQuery(null);\n const [createChatterMessage, { isLoading, isSuccess, isError }] = useCreateChatterMessageMutation();\n\n const tempEmails = [\n \"johndoe@gmal.com\",\n \"tempmail@gmail.com\",\n \"example@mail.com\"\n ]\n\n const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (event.target.files) {\n const files = Array.from(event.target.files);\n setSelectedFiles(prev => [...prev, ...files]);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!message.trim() && selectedFiles.length === 0) return;\n\n try {\n const formData = new FormData();\n formData.append('messageType', \"custom\");\n formData.append('messageSubType', \"custom\");\n formData.append('messageBody', message);\n formData.append('coModelEntityId', id);\n formData.append('coModelName', modelSingularName);\n formData.append('userId', user?.id || 1);\n\n if (modelUserKey) formData.append('modelUserKey', modelUserKey);\n selectedFiles.forEach((file, index) => {\n formData.append(`messageAttachments`, file);\n });\n\n await createChatterMessage(formData).unwrap();\n setMessage('');\n setSelectedFiles([]);\n } catch (error) {\n console.error(ERROR_MESSAGES.FETCHING_MESSAGE, error);\n }\n };\n\n useEffect(() => {\n if (isSuccess) {\n refetch()\n }\n }, [isSuccess]);\n\n const formatFileSize = (size: number) => {\n if (!size) return \"\";\n return size >= 1024 * 1024\n ? `${(size / (1024 * 1024)).toFixed(1)} MB`\n : `${(size / 1024).toFixed(1)} KB`;\n };\n\n return (\n <form className={styles.chatterMessageComposer} onSubmit={handleSubmit}>\n {/* {type === 'email' &&\n <div className='flex align-items-center gap-1 text-sm mb-2'>\n <span className='font-bold'>To:</span>\n <div className={styles.chatterEmails}>\n {tempEmails.map((mail, index) => (\n <span key={index}>\n {mail}\n </span>\n ))}\n </div>\n <div className={`si si-sort-down-fill text-primary ${styles.emailTooltipIcon}`} style={{ fontSize: 8 }}>\n <div className={styles.emailsTooltip}>\n {tempEmails.map((mail, index) => (\n <span key={index} className='text-color text-sm'>\n {mail}\n </span>\n ))}\n </div>\n </div>\n </div>\n } */}\n <div className={`${styles.solidMessageWrapper} flex flex-column gap-2 w-full`}>\n <div className='flex align-items-center justify-content-between'>\n <p className='form-field-label m-0'>\n {type === 'email' ? 'Email Message' : 'Internal Note'}\n </p>\n </div>\n <SolidTextarea\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n placeholder={type === 'email' ? 'Send a message to followers' : 'Log an internal note.'}\n className=\"w-full p-1\"\n rows={4}\n />\n <div className='flex align-items-center justify-content-between flex-wrap gap-2'>\n <div className='flex align-items-center gap-2'>\n <input\n type=\"file\"\n ref={fileInputRef}\n onChange={handleFileSelect}\n multiple\n style={{ display: 'none' }}\n />\n <SolidButton\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"solid-icon-button\"\n leftIcon={<Paperclip size={14} />}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n />\n <span className='text-xs text-color-secondary'>Attach file</span>\n </div>\n <div className='flex align-items-center gap-2'>\n <SolidButton\n type='submit'\n size='sm'\n className='gap-2 solid-purple-button'\n variant='primary'\n loading={isLoading}\n >\n {type === 'email' ? 'Send' : 'Log'}\n </SolidButton>\n <SolidButton\n type='button'\n size='sm'\n variant='ghost'\n onClick={() => {\n setMessage('');\n setSelectedFiles([]);\n onCancel?.();\n }}\n >\n Cancel\n </SolidButton>\n </div>\n </div>\n </div>\n {selectedFiles.length > 0 && (\n <div className={styles.chatterSelectedFiles}>\n {selectedFiles.map((file, index) => (\n <div key={index} className={styles.chatterSelectedFileCard}>\n <div className={styles.chatterSelectedFileIcon}>\n <FileText size={16} />\n </div>\n <div className={styles.chatterSelectedFileMeta}>\n <p className={styles.chatterSelectedFileName}>{file.name}</p>\n <span className={styles.chatterSelectedFileSize}>{formatFileSize(file.size)}</span>\n </div>\n <SolidButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"solid-icon-button\"\n leftIcon={<X size={12} />}\n onClick={() => setSelectedFiles(prev => prev.filter((_, i) => i !== index))}\n aria-label={`Remove ${file.name}`}\n />\n </div>\n ))}\n </div>\n )}\n </form>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SolidMessageComposer.js","sourceRoot":"","sources":["../../../../src/components/core/chatter/SolidMessageComposer.tsx"],"names":[],"mappings":"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","sourcesContent":["import styles from './chatter.module.css'\nimport { useCreateChatterMessageMutation } from '../../../redux/api/solidChatterMessageApi'\nimport { useEffect, useState, useRef } from 'react'\nimport { ERROR_MESSAGES } from '../../../constants/error-messages'\nimport { useSession } from '../../../hooks/useSession'\nimport { SolidButton, SolidTextarea } from '../../shad-cn-ui'\nimport { FileText, Paperclip, X } from 'lucide-react'\n\ninterface SolidMessageComposerProps {\n type?: string;\n modelSingularName?: any;\n refetch?: any;\n id?: any;\n onCancel?: () => void;\n modelUserKey?: string;\n}\n\nexport const SolidMessageComposer = ({ type, modelSingularName, refetch, id, onCancel, modelUserKey }: SolidMessageComposerProps) => {\n const [message, setMessage] = useState('');\n const [selectedFiles, setSelectedFiles] = useState<File[]>([]);\n\n const { data: session, status } = useSession();\n const user = session?.user;\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // const { data: viewLayoutData } = useGetSolidViewLayoutQuery(null);\n const [createChatterMessage, { isLoading, isSuccess, isError }] = useCreateChatterMessageMutation();\n\n const tempEmails = [\n \"johndoe@gmal.com\",\n \"tempmail@gmail.com\",\n \"example@mail.com\"\n ]\n\n const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (event.target.files) {\n const files = Array.from(event.target.files);\n setSelectedFiles(prev => [...prev, ...files]);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!message.trim() && selectedFiles.length === 0) return;\n\n try {\n const formData = new FormData();\n formData.append('messageType', \"custom\");\n formData.append('messageSubType', \"note\");\n formData.append('messageBody', message);\n formData.append('coModelEntityId', id);\n formData.append('coModelName', modelSingularName);\n formData.append('userId', user?.id || 1);\n\n if (modelUserKey) formData.append('modelUserKey', modelUserKey);\n selectedFiles.forEach((file, index) => {\n formData.append(`messageAttachments`, file);\n });\n\n await createChatterMessage(formData).unwrap();\n setMessage('');\n setSelectedFiles([]);\n } catch (error) {\n console.error(ERROR_MESSAGES.FETCHING_MESSAGE, error);\n }\n };\n\n useEffect(() => {\n if (isSuccess) {\n refetch()\n }\n }, [isSuccess]);\n\n const formatFileSize = (size: number) => {\n if (!size) return \"\";\n return size >= 1024 * 1024\n ? `${(size / (1024 * 1024)).toFixed(1)} MB`\n : `${(size / 1024).toFixed(1)} KB`;\n };\n\n return (\n <form className={styles.chatterMessageComposer} onSubmit={handleSubmit}>\n {/* {type === 'email' &&\n <div className='flex align-items-center gap-1 text-sm mb-2'>\n <span className='font-bold'>To:</span>\n <div className={styles.chatterEmails}>\n {tempEmails.map((mail, index) => (\n <span key={index}>\n {mail}\n </span>\n ))}\n </div>\n <div className={`si si-sort-down-fill text-primary ${styles.emailTooltipIcon}`} style={{ fontSize: 8 }}>\n <div className={styles.emailsTooltip}>\n {tempEmails.map((mail, index) => (\n <span key={index} className='text-color text-sm'>\n {mail}\n </span>\n ))}\n </div>\n </div>\n </div>\n } */}\n <div className={`${styles.solidMessageWrapper} flex flex-column gap-2 w-full`}>\n <div className='flex align-items-center justify-content-between'>\n <p className='form-field-label m-0'>\n {type === 'email' ? 'Email Message' : 'Internal Note'}\n </p>\n </div>\n <SolidTextarea\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n placeholder={type === 'email' ? 'Send a message to followers' : 'Log an internal note.'}\n className=\"w-full p-2\"\n rows={4}\n />\n <div className='flex align-items-center justify-content-between flex-wrap gap-2'>\n <div className='flex align-items-center gap-2'>\n <input\n type=\"file\"\n ref={fileInputRef}\n onChange={handleFileSelect}\n multiple\n style={{ display: 'none' }}\n />\n <SolidButton\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"solid-icon-button\"\n leftIcon={<Paperclip size={14} />}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n />\n <span className='text-xs text-color-secondary'>Attach file</span>\n </div>\n <div className='flex align-items-center gap-2'>\n <SolidButton\n type='submit'\n size='sm'\n className='gap-2 solid-purple-button'\n variant='primary'\n loading={isLoading}\n >\n {type === 'email' ? 'Send' : 'Log'}\n </SolidButton>\n <SolidButton\n type='button'\n size='sm'\n variant='ghost'\n onClick={() => {\n setMessage('');\n setSelectedFiles([]);\n onCancel?.();\n }}\n >\n Cancel\n </SolidButton>\n </div>\n </div>\n </div>\n {selectedFiles.length > 0 && (\n <div className={styles.chatterSelectedFiles}>\n {selectedFiles.map((file, index) => (\n <div key={index} className={styles.chatterSelectedFileCard}>\n <div className={styles.chatterSelectedFileIcon}>\n <FileText size={16} />\n </div>\n <div className={styles.chatterSelectedFileMeta}>\n <p className={styles.chatterSelectedFileName}>{file.name}</p>\n <span className={styles.chatterSelectedFileSize}>{formatFileSize(file.size)}</span>\n </div>\n <SolidButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"solid-icon-button\"\n leftIcon={<X size={12} />}\n onClick={() => setSelectedFiles(prev => prev.filter((_, i) => i !== index))}\n aria-label={`Remove ${file.name}`}\n />\n </div>\n ))}\n </div>\n )}\n </form>\n )\n}\n"]}
|
|
@@ -46,7 +46,7 @@ export const SolidMessageComposer = ({ type, modelSingularName, refetch, id, onC
|
|
|
46
46
|
try {
|
|
47
47
|
const formData = new FormData();
|
|
48
48
|
formData.append('messageType', "custom");
|
|
49
|
-
formData.append('messageSubType', "
|
|
49
|
+
formData.append('messageSubType', "note");
|
|
50
50
|
formData.append('messageBody', message);
|
|
51
51
|
formData.append('coModelEntityId', id);
|
|
52
52
|
formData.append('coModelName', modelSingularName);
|
|
@@ -111,7 +111,7 @@ export const SolidMessageComposer = ({ type, modelSingularName, refetch, id, onC
|
|
|
111
111
|
value={message}
|
|
112
112
|
onChange={(e) => setMessage(e.target.value)}
|
|
113
113
|
placeholder={type === 'email' ? 'Send a message to followers' : 'Log an internal note.'}
|
|
114
|
-
className="w-full p-
|
|
114
|
+
className="w-full p-2"
|
|
115
115
|
rows={4}
|
|
116
116
|
/>
|
|
117
117
|
<div className='flex align-items-center justify-content-between flex-wrap gap-2'>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolidGlobalSearchElement.d.ts","sourceRoot":"","sources":["../../../../src/components/core/common/SolidGlobalSearchElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgF,MAAM,OAAO,CAAC;AAYrG,OAA0B,EAAE,eAAe,EAAE,YAAY,EAAsB,MAAM,qBAAqB,CAAC;AA0B3G,MAAM,MAAM,eAAe,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACrB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,MAAM,CAAC;CAClC,CAAA;
|
|
1
|
+
{"version":3,"file":"SolidGlobalSearchElement.d.ts","sourceRoot":"","sources":["../../../../src/components/core/common/SolidGlobalSearchElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgF,MAAM,OAAO,CAAC;AAYrG,OAA0B,EAAE,eAAe,EAAE,YAAY,EAAsB,MAAM,qBAAqB,CAAC;AA0B3G,MAAM,MAAM,eAAe,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACrB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,MAAM,CAAC;CAClC,CAAA;AAoUD,eAAO,MAAM,2BAA2B,sBAAuB,GAAG,aAAa,GAAG,yBAAyB,MAAM,iBAAiB,MAAM,QAavI,CAAA;AAGD,eAAO,MAAM,mBAAmB,iBAAkB,GAAG,gBAAgB,GAAG,eAAe,GAAG,qBAAqB,GAAG,kBAAkB,YAAY,EAAE,qBAAqB,eAAe,EAAE,QAwBvL,CAAA;AA0HD,eAAO,MAAM,wBAAwB,kFAumDnC,CAAC"}
|
|
@@ -185,8 +185,19 @@ var transformRulesToFilters = function (input, viewData) {
|
|
|
185
185
|
var _a, _b, _c, _d;
|
|
186
186
|
var _e, _f;
|
|
187
187
|
if (rule.value !== undefined && rule.value !== null) {
|
|
188
|
-
// Ensure rule.value is always an array
|
|
189
|
-
|
|
188
|
+
// Ensure rule.value is always an array of primitive values.
|
|
189
|
+
// Mixed arrays like ["failed", { label: "pending", value: "pending" }]
|
|
190
|
+
// must be normalized before query serialization.
|
|
191
|
+
var rawValues = Array.isArray(rule === null || rule === void 0 ? void 0 : rule.value) ? rule.value : [rule === null || rule === void 0 ? void 0 : rule.value];
|
|
192
|
+
var values = rawValues.map(function (item) {
|
|
193
|
+
if (item && typeof item === "object") {
|
|
194
|
+
if (Object.prototype.hasOwnProperty.call(item, "value"))
|
|
195
|
+
return item.value;
|
|
196
|
+
if (Object.prototype.hasOwnProperty.call(item, "label"))
|
|
197
|
+
return item.label;
|
|
198
|
+
}
|
|
199
|
+
return item;
|
|
200
|
+
});
|
|
190
201
|
if (rule.matchMode !== '$in' && rule.matchMode !== '$notIn' && rule.matchMode !== '$between' && rule.matchMode !== '$null' && rule.matchMode !== '$notNull') {
|
|
191
202
|
values = values[0];
|
|
192
203
|
}
|