@oneuptime/common 8.0.5571 → 8.0.5572
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/Models/DatabaseModels/AlertFeed.ts +2 -0
- package/Models/DatabaseModels/AlertSeverity.ts +2 -0
- package/Models/DatabaseModels/AlertState.ts +2 -0
- package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +5 -0
- package/Models/DatabaseModels/IncidentSeverity.ts +2 -0
- package/Models/DatabaseModels/IncidentState.ts +2 -0
- package/Models/DatabaseModels/Label.ts +2 -0
- package/Models/DatabaseModels/MonitorStatus.ts +2 -0
- package/Models/DatabaseModels/ScheduledMaintenanceFeed.ts +2 -0
- package/Models/DatabaseModels/ScheduledMaintenanceState.ts +2 -0
- package/Models/DatabaseModels/ServiceCatalog.ts +2 -0
- package/Models/DatabaseModels/TelemetryService.ts +2 -0
- package/Tests/UI/Components/Pill.test.tsx +8 -0
- package/Types/Color.ts +2 -2
- package/Types/Database/ColorField.ts +64 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/UI/Components/Dropdown/Dropdown.tsx +503 -10
- package/UI/Components/Forms/ModelForm.tsx +63 -26
- package/UI/Components/Icon/Icon.tsx +4 -0
- package/UI/Components/Label/Label.tsx +50 -0
- package/UI/Components/Label/Labels.tsx +35 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +134 -6
- package/UI/Components/Page/Page.tsx +7 -23
- package/UI/Components/Pill/Pill.tsx +13 -3
- package/UI/Utils/Dropdown.ts +19 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +2 -0
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertState.js +2 -0
- package/build/dist/Models/DatabaseModels/AlertState.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +4 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +2 -0
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentState.js +2 -0
- package/build/dist/Models/DatabaseModels/IncidentState.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Label.js +2 -0
- package/build/dist/Models/DatabaseModels/Label.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorStatus.js +2 -0
- package/build/dist/Models/DatabaseModels/MonitorStatus.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceState.js +2 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceState.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceCatalog.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceCatalog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryService.js +2 -0
- package/build/dist/Models/DatabaseModels/TelemetryService.js.map +1 -1
- package/build/dist/Tests/UI/Components/Pill.test.js +6 -0
- package/build/dist/Tests/UI/Components/Pill.test.js.map +1 -1
- package/build/dist/Types/Color.js +1 -1
- package/build/dist/Types/Color.js.map +1 -1
- package/build/dist/Types/Database/ColorField.js +27 -0
- package/build/dist/Types/Database/ColorField.js.map +1 -0
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +264 -8
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +33 -10
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +5 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Label/Label.js +32 -0
- package/build/dist/UI/Components/Label/Label.js.map +1 -0
- package/build/dist/UI/Components/Label/Labels.js +13 -0
- package/build/dist/UI/Components/Label/Labels.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +82 -6
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +3 -14
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pill/Pill.js +4 -4
- package/build/dist/UI/Components/Pill/Pill.js.map +1 -1
- package/build/dist/UI/Utils/Dropdown.js +11 -1
- package/build/dist/UI/Utils/Dropdown.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,13 +6,32 @@ import React, {
|
|
|
6
6
|
useRef,
|
|
7
7
|
useState,
|
|
8
8
|
} from "react";
|
|
9
|
-
import
|
|
9
|
+
import Color from "../../../Types/Color";
|
|
10
|
+
import Label from "../../../Models/DatabaseModels/Label";
|
|
11
|
+
import Select, {
|
|
12
|
+
ControlProps,
|
|
13
|
+
CSSObjectWithLabel,
|
|
14
|
+
FormatOptionLabelMeta,
|
|
15
|
+
GroupBase,
|
|
16
|
+
OptionProps,
|
|
17
|
+
} from "react-select";
|
|
10
18
|
|
|
11
19
|
export type DropdownValue = string | number | boolean;
|
|
12
20
|
|
|
21
|
+
export type DropdownOptionLabel =
|
|
22
|
+
| Label
|
|
23
|
+
| {
|
|
24
|
+
id?: string;
|
|
25
|
+
name: string;
|
|
26
|
+
color?: Color;
|
|
27
|
+
};
|
|
28
|
+
|
|
13
29
|
export interface DropdownOption {
|
|
14
30
|
value: DropdownValue;
|
|
15
31
|
label: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
labels?: Array<DropdownOptionLabel>;
|
|
34
|
+
color?: Color;
|
|
16
35
|
}
|
|
17
36
|
|
|
18
37
|
export interface ComponentProps {
|
|
@@ -111,6 +130,333 @@ const Dropdown: FunctionComponent<ComponentProps> = (
|
|
|
111
130
|
|
|
112
131
|
const firstUpdate: React.MutableRefObject<boolean> = useRef(true);
|
|
113
132
|
|
|
133
|
+
interface NormalizedDropdownLabel {
|
|
134
|
+
id?: string;
|
|
135
|
+
name: string;
|
|
136
|
+
color?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const normalizeLabelColor: (
|
|
140
|
+
color?: Color | string | null,
|
|
141
|
+
) => string | undefined = (
|
|
142
|
+
color?: Color | string | null,
|
|
143
|
+
): string | undefined => {
|
|
144
|
+
if (!color) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (color instanceof Color) {
|
|
149
|
+
return color.toString();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (typeof color === "string" && color.trim().length > 0) {
|
|
153
|
+
return color;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return undefined;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const normalizeDropdownLabel: (
|
|
160
|
+
label: DropdownOptionLabel,
|
|
161
|
+
) => NormalizedDropdownLabel | null = (
|
|
162
|
+
label: DropdownOptionLabel,
|
|
163
|
+
): NormalizedDropdownLabel | null => {
|
|
164
|
+
if (!label) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const getValueFromModel: (
|
|
169
|
+
columnName: string,
|
|
170
|
+
) => string | Color | null | undefined = (
|
|
171
|
+
columnName: string,
|
|
172
|
+
): string | Color | null | undefined => {
|
|
173
|
+
if (
|
|
174
|
+
typeof (label as Label).getColumnValue === "function" &&
|
|
175
|
+
typeof (label as Label).getTableColumnMetadata === "function"
|
|
176
|
+
) {
|
|
177
|
+
return (label as Label).getColumnValue(columnName) as
|
|
178
|
+
| string
|
|
179
|
+
| Color
|
|
180
|
+
| null
|
|
181
|
+
| undefined;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return (label as any)?.[columnName] as string | Color | null | undefined;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const labelName: string | undefined = (() => {
|
|
188
|
+
const valueFromGetter: string | null | undefined = getValueFromModel(
|
|
189
|
+
"name",
|
|
190
|
+
) as string | undefined | null;
|
|
191
|
+
|
|
192
|
+
if (valueFromGetter && valueFromGetter.trim().length > 0) {
|
|
193
|
+
return valueFromGetter;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const fallbackName: string | undefined = (label as any)?.name;
|
|
197
|
+
if (fallbackName && fallbackName.trim().length > 0) {
|
|
198
|
+
return fallbackName;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return undefined;
|
|
202
|
+
})();
|
|
203
|
+
|
|
204
|
+
if (!labelName) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const rawColor: Color | string | null | undefined = getValueFromModel(
|
|
209
|
+
"color",
|
|
210
|
+
) as Color | string | null | undefined;
|
|
211
|
+
const color: string | undefined =
|
|
212
|
+
normalizeLabelColor(rawColor) ||
|
|
213
|
+
normalizeLabelColor((label as any)?.color);
|
|
214
|
+
|
|
215
|
+
const idValue: string | undefined = (() => {
|
|
216
|
+
if (typeof (label as Label).id !== "undefined") {
|
|
217
|
+
const idFromGetter: ObjectID | null | undefined = (label as Label).id;
|
|
218
|
+
if (idFromGetter) {
|
|
219
|
+
return idFromGetter.toString();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const fallbackId: string | undefined =
|
|
224
|
+
(label as any)?._id || (label as any)?.id;
|
|
225
|
+
|
|
226
|
+
if (fallbackId) {
|
|
227
|
+
return fallbackId;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return undefined;
|
|
231
|
+
})();
|
|
232
|
+
|
|
233
|
+
const normalized: NormalizedDropdownLabel = {
|
|
234
|
+
name: labelName,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
if (idValue) {
|
|
238
|
+
normalized.id = idValue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (color) {
|
|
242
|
+
normalized.color = color;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return normalized;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const normalizeLabelCollection: (
|
|
249
|
+
labels?: Array<DropdownOptionLabel>,
|
|
250
|
+
) => Array<NormalizedDropdownLabel> = (
|
|
251
|
+
labels?: Array<DropdownOptionLabel>,
|
|
252
|
+
): Array<NormalizedDropdownLabel> => {
|
|
253
|
+
if (!labels || labels.length === 0) {
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return labels
|
|
258
|
+
.map((label: DropdownOptionLabel) => {
|
|
259
|
+
return normalizeDropdownLabel(label);
|
|
260
|
+
})
|
|
261
|
+
.filter(
|
|
262
|
+
(
|
|
263
|
+
label: NormalizedDropdownLabel | null,
|
|
264
|
+
): label is NormalizedDropdownLabel => {
|
|
265
|
+
return label !== null;
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const renderOptionColorIndicator: (
|
|
271
|
+
color?: Color | string,
|
|
272
|
+
) => ReactElement | null = (color?: Color | string): ReactElement | null => {
|
|
273
|
+
const normalizedColor: string | undefined = color
|
|
274
|
+
? new Color(color).toString()
|
|
275
|
+
: undefined;
|
|
276
|
+
|
|
277
|
+
if (!normalizedColor) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<span
|
|
283
|
+
aria-hidden="true"
|
|
284
|
+
className="h-2.5 w-2.5 flex-none rounded-full border border-gray-200"
|
|
285
|
+
style={{
|
|
286
|
+
backgroundColor: normalizedColor,
|
|
287
|
+
}}
|
|
288
|
+
title={normalizedColor}
|
|
289
|
+
></span>
|
|
290
|
+
);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const getLabelStyle: (color?: string) => {
|
|
294
|
+
backgroundColor: string;
|
|
295
|
+
color: string;
|
|
296
|
+
} = (color?: string): { backgroundColor: string; color: string } => {
|
|
297
|
+
if (!color) {
|
|
298
|
+
return {
|
|
299
|
+
backgroundColor: "#e5e7eb", // gray-200
|
|
300
|
+
color: "#374151", // gray-700
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
const parsedColor: Color = Color.fromString(color);
|
|
306
|
+
return {
|
|
307
|
+
backgroundColor: parsedColor.toString(),
|
|
308
|
+
color: Color.shouldUseDarkText(parsedColor)
|
|
309
|
+
? "#111827" // gray-900
|
|
310
|
+
: "#f9fafb", // gray-50
|
|
311
|
+
};
|
|
312
|
+
} catch {
|
|
313
|
+
return {
|
|
314
|
+
backgroundColor: color,
|
|
315
|
+
color: "#111827",
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const defaultSelectedLabelAccentColor: string = "#6366f1"; // indigo-500
|
|
321
|
+
|
|
322
|
+
const resolveSelectedLabelColor: (color?: string) => string = (
|
|
323
|
+
color?: string,
|
|
324
|
+
): string => {
|
|
325
|
+
if (!color) {
|
|
326
|
+
return defaultSelectedLabelAccentColor;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
return Color.fromString(color).toString();
|
|
331
|
+
} catch {
|
|
332
|
+
return defaultSelectedLabelAccentColor;
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const renderAssociatedLabels: (
|
|
337
|
+
labels: Array<NormalizedDropdownLabel>,
|
|
338
|
+
context: FormatOptionLabelMeta<DropdownOption>["context"],
|
|
339
|
+
hiddenLabelCount: number,
|
|
340
|
+
) => ReactElement | null = (
|
|
341
|
+
labels: Array<NormalizedDropdownLabel>,
|
|
342
|
+
context: FormatOptionLabelMeta<DropdownOption>["context"],
|
|
343
|
+
hiddenLabelCount: number,
|
|
344
|
+
): ReactElement | null => {
|
|
345
|
+
if (labels.length === 0 && hiddenLabelCount === 0) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (context === "value") {
|
|
350
|
+
return (
|
|
351
|
+
<div className="flex flex-wrap items-center gap-1">
|
|
352
|
+
{labels.map((label: NormalizedDropdownLabel, index: number) => {
|
|
353
|
+
const accentColor: string = resolveSelectedLabelColor(label.color);
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<span
|
|
357
|
+
key={`${label.id || label.name}-selected-${index}`}
|
|
358
|
+
className="inline-flex items-center gap-1 rounded-full border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-600"
|
|
359
|
+
style={{
|
|
360
|
+
borderColor: accentColor,
|
|
361
|
+
}}
|
|
362
|
+
title={label.name}
|
|
363
|
+
>
|
|
364
|
+
<span
|
|
365
|
+
aria-hidden="true"
|
|
366
|
+
className="h-1.5 w-1.5 rounded-full"
|
|
367
|
+
style={{
|
|
368
|
+
backgroundColor: accentColor,
|
|
369
|
+
}}
|
|
370
|
+
></span>
|
|
371
|
+
{label.name}
|
|
372
|
+
</span>
|
|
373
|
+
);
|
|
374
|
+
})}
|
|
375
|
+
{hiddenLabelCount > 0 ? (
|
|
376
|
+
<span className="inline-flex items-center rounded-full border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-500">
|
|
377
|
+
+{hiddenLabelCount}
|
|
378
|
+
</span>
|
|
379
|
+
) : null}
|
|
380
|
+
</div>
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return (
|
|
385
|
+
<div className="flex flex-wrap gap-1">
|
|
386
|
+
{labels.map((label: NormalizedDropdownLabel, index: number) => {
|
|
387
|
+
const { backgroundColor, color } = getLabelStyle(label.color);
|
|
388
|
+
|
|
389
|
+
return (
|
|
390
|
+
<span
|
|
391
|
+
key={`${label.id || label.name}-menu-${index}`}
|
|
392
|
+
className="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium shadow-sm"
|
|
393
|
+
style={{ backgroundColor, color }}
|
|
394
|
+
>
|
|
395
|
+
{label.name}
|
|
396
|
+
</span>
|
|
397
|
+
);
|
|
398
|
+
})}
|
|
399
|
+
{hiddenLabelCount > 0 ? (
|
|
400
|
+
<span className="inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600">
|
|
401
|
+
+{hiddenLabelCount}
|
|
402
|
+
</span>
|
|
403
|
+
) : null}
|
|
404
|
+
</div>
|
|
405
|
+
);
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
const formatDropdownOptionLabel: (
|
|
409
|
+
option: DropdownOption,
|
|
410
|
+
meta: FormatOptionLabelMeta<DropdownOption>,
|
|
411
|
+
) => ReactElement = (
|
|
412
|
+
option: DropdownOption,
|
|
413
|
+
meta: FormatOptionLabelMeta<DropdownOption>,
|
|
414
|
+
): ReactElement => {
|
|
415
|
+
const normalizedLabels: Array<NormalizedDropdownLabel> =
|
|
416
|
+
normalizeLabelCollection(option.labels);
|
|
417
|
+
|
|
418
|
+
const maxVisibleLabels: number = meta.context === "menu" ? 4 : 2;
|
|
419
|
+
const visibleLabels: Array<NormalizedDropdownLabel> =
|
|
420
|
+
normalizedLabels.slice(0, maxVisibleLabels);
|
|
421
|
+
const hiddenLabelCount: number = Math.max(
|
|
422
|
+
normalizedLabels.length - visibleLabels.length,
|
|
423
|
+
0,
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
if (meta.context === "value") {
|
|
427
|
+
return (
|
|
428
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
429
|
+
<div className="flex items-center gap-2">
|
|
430
|
+
{renderOptionColorIndicator(option.color)}
|
|
431
|
+
<span className="text-sm font-medium text-gray-900">
|
|
432
|
+
{option.label}
|
|
433
|
+
</span>
|
|
434
|
+
</div>
|
|
435
|
+
{renderAssociatedLabels(
|
|
436
|
+
visibleLabels,
|
|
437
|
+
meta.context,
|
|
438
|
+
hiddenLabelCount,
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return (
|
|
445
|
+
<div className="flex flex-col gap-1">
|
|
446
|
+
<div className="flex items-center gap-2">
|
|
447
|
+
{renderOptionColorIndicator(option.color)}
|
|
448
|
+
<span className="text-sm font-medium text-gray-900">
|
|
449
|
+
{option.label}
|
|
450
|
+
</span>
|
|
451
|
+
</div>
|
|
452
|
+
{option.description ? (
|
|
453
|
+
<span className="text-xs text-gray-500">{option.description}</span>
|
|
454
|
+
) : null}
|
|
455
|
+
{renderAssociatedLabels(visibleLabels, meta.context, hiddenLabelCount)}
|
|
456
|
+
</div>
|
|
457
|
+
);
|
|
458
|
+
};
|
|
459
|
+
|
|
114
460
|
useLayoutEffect(() => {
|
|
115
461
|
if (firstUpdate.current && props.initialValue) {
|
|
116
462
|
firstUpdate.current = false;
|
|
@@ -138,6 +484,9 @@ const Dropdown: FunctionComponent<ComponentProps> = (
|
|
|
138
484
|
}}
|
|
139
485
|
>
|
|
140
486
|
<Select
|
|
487
|
+
classNamePrefix="ou-select"
|
|
488
|
+
unstyled={false}
|
|
489
|
+
formatOptionLabel={formatDropdownOptionLabel}
|
|
141
490
|
onBlur={() => {
|
|
142
491
|
props.onBlur?.();
|
|
143
492
|
}}
|
|
@@ -150,25 +499,169 @@ const Dropdown: FunctionComponent<ComponentProps> = (
|
|
|
150
499
|
}}
|
|
151
500
|
classNames={{
|
|
152
501
|
control: (
|
|
153
|
-
state: ControlProps<
|
|
502
|
+
state: ControlProps<DropdownOption, boolean, GroupBase<any>>,
|
|
154
503
|
): string => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
504
|
+
const classes: Array<string> = [
|
|
505
|
+
"!min-h-[40px] !rounded-lg !border !bg-white !shadow-sm !transition-all !duration-150",
|
|
506
|
+
state.isFocused
|
|
507
|
+
? "!border-indigo-400 !ring-2 !ring-indigo-100"
|
|
508
|
+
: "!border-gray-300 hover:!border-indigo-300",
|
|
509
|
+
state.isDisabled
|
|
510
|
+
? "!bg-gray-100 !text-gray-400"
|
|
511
|
+
: "!cursor-pointer",
|
|
512
|
+
];
|
|
513
|
+
|
|
514
|
+
if (props.error) {
|
|
515
|
+
classes.push("!border-red-400 !ring-2 !ring-red-100");
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return classes.join(" ");
|
|
519
|
+
},
|
|
520
|
+
valueContainer: () => {
|
|
521
|
+
return "!gap-2 !px-2";
|
|
522
|
+
},
|
|
523
|
+
placeholder: () => {
|
|
524
|
+
return "text-sm text-gray-400";
|
|
525
|
+
},
|
|
526
|
+
input: () => {
|
|
527
|
+
return "text-sm text-gray-900";
|
|
528
|
+
},
|
|
529
|
+
singleValue: () => {
|
|
530
|
+
return "text-sm text-gray-900 font-medium";
|
|
531
|
+
},
|
|
532
|
+
indicatorsContainer: () => {
|
|
533
|
+
return "!gap-1 !px-1";
|
|
534
|
+
},
|
|
535
|
+
dropdownIndicator: () => {
|
|
536
|
+
return "text-gray-500 transition-colors duration-150 hover:text-indigo-400";
|
|
537
|
+
},
|
|
538
|
+
clearIndicator: () => {
|
|
539
|
+
return "text-gray-400 transition-colors duration-150 hover:text-red-500";
|
|
540
|
+
},
|
|
541
|
+
menu: () => {
|
|
542
|
+
return "!mt-2 !rounded-xl !border !border-gray-100 !bg-white !shadow-xl";
|
|
543
|
+
},
|
|
544
|
+
menuList: () => {
|
|
545
|
+
return "!py-2";
|
|
158
546
|
},
|
|
159
547
|
option: (
|
|
160
|
-
state: OptionProps<
|
|
548
|
+
state: OptionProps<DropdownOption, boolean, GroupBase<any>>,
|
|
161
549
|
): string => {
|
|
162
550
|
if (state.isDisabled) {
|
|
163
|
-
return "
|
|
551
|
+
return "px-3 py-2 text-sm text-gray-300 cursor-not-allowed";
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (state.isSelected) {
|
|
555
|
+
return "px-3 py-2 text-sm bg-indigo-200 text-indigo-900";
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (state.isFocused) {
|
|
559
|
+
return "px-3 py-2 text-sm bg-indigo-100 text-indigo-700";
|
|
164
560
|
}
|
|
561
|
+
|
|
562
|
+
return "px-3 py-2 text-sm text-gray-700";
|
|
563
|
+
},
|
|
564
|
+
noOptionsMessage: () => {
|
|
565
|
+
return "px-3 py-2 text-sm text-gray-500";
|
|
566
|
+
},
|
|
567
|
+
multiValue: () => {
|
|
568
|
+
return "flex items-center gap-2 rounded-lg border border-indigo-100 bg-indigo-50 px-2 py-1";
|
|
569
|
+
},
|
|
570
|
+
multiValueLabel: () => {
|
|
571
|
+
return "flex flex-wrap items-center gap-2 text-sm font-medium text-indigo-900";
|
|
572
|
+
},
|
|
573
|
+
multiValueRemove: () => {
|
|
574
|
+
return "text-indigo-400 hover:text-indigo-600 transition-colors duration-150";
|
|
575
|
+
},
|
|
576
|
+
}}
|
|
577
|
+
styles={{
|
|
578
|
+
dropdownIndicator: (
|
|
579
|
+
provided: CSSObjectWithLabel,
|
|
580
|
+
): CSSObjectWithLabel => {
|
|
581
|
+
return {
|
|
582
|
+
...provided,
|
|
583
|
+
padding: 8,
|
|
584
|
+
};
|
|
585
|
+
},
|
|
586
|
+
clearIndicator: (
|
|
587
|
+
provided: CSSObjectWithLabel,
|
|
588
|
+
): CSSObjectWithLabel => {
|
|
589
|
+
return {
|
|
590
|
+
...provided,
|
|
591
|
+
padding: 8,
|
|
592
|
+
};
|
|
593
|
+
},
|
|
594
|
+
indicatorSeparator: (): CSSObjectWithLabel => {
|
|
595
|
+
return {
|
|
596
|
+
display: "none",
|
|
597
|
+
} as CSSObjectWithLabel;
|
|
598
|
+
},
|
|
599
|
+
option: (
|
|
600
|
+
provided: CSSObjectWithLabel,
|
|
601
|
+
state: OptionProps<
|
|
602
|
+
DropdownOption,
|
|
603
|
+
boolean,
|
|
604
|
+
GroupBase<DropdownOption>
|
|
605
|
+
>,
|
|
606
|
+
): CSSObjectWithLabel => {
|
|
165
607
|
if (state.isSelected) {
|
|
166
|
-
return
|
|
608
|
+
return {
|
|
609
|
+
...provided,
|
|
610
|
+
backgroundColor: "#c7d2fe", // indigo-200
|
|
611
|
+
color: "#1e1b4b", // indigo-900
|
|
612
|
+
};
|
|
167
613
|
}
|
|
614
|
+
|
|
168
615
|
if (state.isFocused) {
|
|
169
|
-
return
|
|
616
|
+
return {
|
|
617
|
+
...provided,
|
|
618
|
+
backgroundColor: "#e0e7ff", // indigo-100
|
|
619
|
+
color: "#312e81", // indigo-800
|
|
620
|
+
};
|
|
170
621
|
}
|
|
171
|
-
|
|
622
|
+
|
|
623
|
+
return {
|
|
624
|
+
...provided,
|
|
625
|
+
color: "#374151", // gray-700
|
|
626
|
+
};
|
|
627
|
+
},
|
|
628
|
+
multiValue: (provided: CSSObjectWithLabel): CSSObjectWithLabel => {
|
|
629
|
+
return {
|
|
630
|
+
...provided,
|
|
631
|
+
backgroundColor: "#eef2ff", // indigo-50
|
|
632
|
+
borderRadius: 8,
|
|
633
|
+
border: "1px solid #c7d2fe", // indigo-200
|
|
634
|
+
paddingLeft: 4,
|
|
635
|
+
paddingRight: 4,
|
|
636
|
+
};
|
|
637
|
+
},
|
|
638
|
+
multiValueLabel: (
|
|
639
|
+
provided: CSSObjectWithLabel,
|
|
640
|
+
): CSSObjectWithLabel => {
|
|
641
|
+
return {
|
|
642
|
+
...provided,
|
|
643
|
+
color: "#312e81", // indigo-800
|
|
644
|
+
fontSize: "0.875rem",
|
|
645
|
+
fontWeight: 500,
|
|
646
|
+
};
|
|
647
|
+
},
|
|
648
|
+
multiValueRemove: (
|
|
649
|
+
provided: CSSObjectWithLabel,
|
|
650
|
+
): CSSObjectWithLabel => {
|
|
651
|
+
return {
|
|
652
|
+
...provided,
|
|
653
|
+
color: "#6366f1", // indigo-500
|
|
654
|
+
":hover": {
|
|
655
|
+
color: "#4f46e5", // indigo-600
|
|
656
|
+
backgroundColor: "transparent",
|
|
657
|
+
},
|
|
658
|
+
};
|
|
659
|
+
},
|
|
660
|
+
menuPortal: (base: CSSObjectWithLabel): CSSObjectWithLabel => {
|
|
661
|
+
return {
|
|
662
|
+
...base,
|
|
663
|
+
zIndex: 50,
|
|
664
|
+
};
|
|
172
665
|
},
|
|
173
666
|
}}
|
|
174
667
|
isClearable={true}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
CategoryCheckboxOption,
|
|
13
13
|
CheckboxCategory,
|
|
14
14
|
} from "../CategoryCheckbox/CategoryCheckboxTypes";
|
|
15
|
+
import type { DropdownOption } from "../Dropdown/Dropdown";
|
|
15
16
|
import Loader, { LoaderType } from "../Loader/Loader";
|
|
16
17
|
import Pill, { PillSize } from "../Pill/Pill";
|
|
17
18
|
import { FormErrors, FormProps, FormSummaryConfig } from "./BasicForm";
|
|
@@ -24,6 +25,7 @@ import AnalyticsBaseModel from "../../../Models/AnalyticsModels/AnalyticsBaseMod
|
|
|
24
25
|
import AccessControlModel from "../../../Models/DatabaseModels/DatabaseBaseModel/AccessControlModel";
|
|
25
26
|
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
26
27
|
import FileModel from "../../../Models/DatabaseModels/DatabaseBaseModel/FileModel";
|
|
28
|
+
import Label from "../../../Models/DatabaseModels/Label";
|
|
27
29
|
import URL from "../../../Types/API/URL";
|
|
28
30
|
import { ColumnAccessControl } from "../../../Types/BaseDatabase/AccessControl";
|
|
29
31
|
import { Black, VeryLightGray } from "../../../Types/BrandColors";
|
|
@@ -412,17 +414,26 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
|
|
412
414
|
[field.dropdownModal.valueField]: true,
|
|
413
415
|
} as any;
|
|
414
416
|
|
|
415
|
-
let
|
|
417
|
+
let colorColumnName: string | null = null;
|
|
418
|
+
let shouldSelectColorColumn: boolean = false;
|
|
419
|
+
|
|
420
|
+
colorColumnName = tempModel.getFirstColorColumn();
|
|
421
|
+
|
|
422
|
+
if (colorColumnName) {
|
|
423
|
+
select[colorColumnName] = true;
|
|
424
|
+
shouldSelectColorColumn = true;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const accessControlColumnName: string | null =
|
|
428
|
+
tempModel.getAccessControlColumn();
|
|
416
429
|
|
|
417
430
|
// also select labels, so they can select resources by labels. This is useful for resources like monitors, etc.
|
|
418
|
-
if (
|
|
419
|
-
select[
|
|
431
|
+
if (accessControlColumnName) {
|
|
432
|
+
select[accessControlColumnName] = {
|
|
420
433
|
_id: true,
|
|
421
434
|
name: true,
|
|
422
435
|
color: true,
|
|
423
436
|
} as any;
|
|
424
|
-
|
|
425
|
-
hasAccessControlColumn = true;
|
|
426
437
|
}
|
|
427
438
|
|
|
428
439
|
const listResult: ListResult<BaseModel> =
|
|
@@ -436,22 +447,51 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
|
|
436
447
|
});
|
|
437
448
|
|
|
438
449
|
if (listResult.data && listResult.data.length > 0) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
450
|
+
const dropdownOptions: Array<DropdownOption> = listResult.data.map(
|
|
451
|
+
(item: BaseModel) => {
|
|
452
|
+
if (!field.dropdownModal) {
|
|
453
|
+
throw new BadDataException("Dropdown Modal value mot found");
|
|
454
|
+
}
|
|
443
455
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
456
|
+
const option: DropdownOption = {
|
|
457
|
+
label: (item as any)[
|
|
458
|
+
field.dropdownModal?.labelField
|
|
459
|
+
].toString(),
|
|
460
|
+
value: (item as any)[
|
|
461
|
+
field.dropdownModal?.valueField
|
|
462
|
+
].toString(),
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
if (colorColumnName && shouldSelectColorColumn) {
|
|
466
|
+
const color: Color = item.getColumnValue(
|
|
467
|
+
colorColumnName,
|
|
468
|
+
) as Color;
|
|
469
|
+
if (color) {
|
|
470
|
+
option.color = color;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (accessControlColumnName) {
|
|
475
|
+
const labelsForItem: Array<AccessControlModel> = (
|
|
476
|
+
((item as any)[
|
|
477
|
+
accessControlColumnName
|
|
478
|
+
] as Array<AccessControlModel>) || []
|
|
479
|
+
).filter((label: AccessControlModel | null) => {
|
|
480
|
+
return Boolean(label);
|
|
481
|
+
}) as Array<AccessControlModel>;
|
|
482
|
+
|
|
483
|
+
if (labelsForItem.length > 0) {
|
|
484
|
+
option.labels = labelsForItem as Array<Label>;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return option;
|
|
489
|
+
},
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
field.dropdownOptions = dropdownOptions;
|
|
453
493
|
|
|
454
|
-
if (
|
|
494
|
+
if (accessControlColumnName) {
|
|
455
495
|
const categories: Array<CheckboxCategory> = [];
|
|
456
496
|
|
|
457
497
|
// populate categories.
|
|
@@ -459,8 +499,7 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
|
|
459
499
|
let localLabels: Array<AccessControlModel> = [];
|
|
460
500
|
|
|
461
501
|
for (const item of listResult.data) {
|
|
462
|
-
const accessControlColumn: string
|
|
463
|
-
tempModel.getAccessControlColumn()!;
|
|
502
|
+
const accessControlColumn: string = accessControlColumnName;
|
|
464
503
|
const labels: Array<AccessControlModel> =
|
|
465
504
|
((item as any)[
|
|
466
505
|
accessControlColumn
|
|
@@ -516,8 +555,7 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
|
|
516
555
|
const options: Array<CategoryCheckboxOption> = [];
|
|
517
556
|
|
|
518
557
|
for (const item of listResult.data) {
|
|
519
|
-
const accessControlColumn: string =
|
|
520
|
-
tempModel.getAccessControlColumn()!;
|
|
558
|
+
const accessControlColumn: string = accessControlColumnName;
|
|
521
559
|
const labels: Array<AccessControlModel> =
|
|
522
560
|
((item as any)[
|
|
523
561
|
accessControlColumn
|
|
@@ -554,9 +592,8 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
|
|
554
592
|
options: options,
|
|
555
593
|
},
|
|
556
594
|
accessControlColumnTitle:
|
|
557
|
-
tempModel.getTableColumnMetadata(
|
|
558
|
-
|
|
559
|
-
).title || "",
|
|
595
|
+
tempModel.getTableColumnMetadata(accessControlColumnName)
|
|
596
|
+
.title || "",
|
|
560
597
|
};
|
|
561
598
|
}
|
|
562
599
|
} else {
|