@oneuptime/common 10.0.69 → 10.0.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/Models/DatabaseModels/KubernetesCluster.ts +7 -0
  2. package/Models/DatabaseModels/Project.ts +5 -5
  3. package/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.ts +11 -8
  4. package/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.ts +137 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.ts +17 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/AIBillingService.ts +2 -2
  8. package/Server/Services/BillingService.ts +116 -48
  9. package/Server/Services/DatabaseService.ts +10 -27
  10. package/Server/Services/KubernetesResourceService.ts +33 -10
  11. package/Server/Services/NotificationService.ts +2 -2
  12. package/Server/Types/Database/QueryHelper.ts +127 -0
  13. package/Server/Types/Database/QueryUtil.ts +250 -0
  14. package/Server/Utils/Monitor/MonitorAlert.ts +79 -0
  15. package/Server/Utils/Monitor/MonitorIncident.ts +79 -0
  16. package/Types/BaseDatabase/EndsWith.ts +41 -0
  17. package/Types/BaseDatabase/IncludesAll.ts +45 -0
  18. package/Types/BaseDatabase/IncludesNone.ts +45 -0
  19. package/Types/BaseDatabase/NotContains.ts +41 -0
  20. package/Types/BaseDatabase/StartsWith.ts +41 -0
  21. package/Types/Email.ts +50 -0
  22. package/Types/JSON.ts +20 -0
  23. package/Types/SerializableObjectDictionary.ts +10 -0
  24. package/UI/Components/Filters/BooleanFilter.tsx +1 -0
  25. package/UI/Components/Filters/DateFilter.tsx +220 -25
  26. package/UI/Components/Filters/DropdownFilter.tsx +1 -0
  27. package/UI/Components/Filters/EntityFilter.tsx +229 -41
  28. package/UI/Components/Filters/FilterViewer.tsx +231 -147
  29. package/UI/Components/Filters/FilterViewerItem.tsx +1 -11
  30. package/UI/Components/Filters/FiltersForm.tsx +146 -97
  31. package/UI/Components/Filters/NumberFilter.tsx +220 -34
  32. package/UI/Components/Filters/OperatorSelector.tsx +91 -0
  33. package/UI/Components/Filters/TextFilter.tsx +183 -71
  34. package/UI/Components/Filters/Types/FilterOperator.ts +73 -0
  35. package/UI/Components/ModelTable/BaseModelTable.tsx +10 -0
  36. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +9 -1
  37. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  38. package/build/dist/Models/DatabaseModels/Project.js +5 -5
  39. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  40. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.js +1 -1
  41. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.js.map +1 -1
  42. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.js +125 -0
  43. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.js.map +1 -0
  44. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js +12 -0
  45. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js.map +1 -0
  46. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  47. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  48. package/build/dist/Server/Services/AIBillingService.js +2 -2
  49. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  50. package/build/dist/Server/Services/BillingService.js +99 -39
  51. package/build/dist/Server/Services/BillingService.js.map +1 -1
  52. package/build/dist/Server/Services/DatabaseService.js +9 -6
  53. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  54. package/build/dist/Server/Services/KubernetesResourceService.js +4 -2
  55. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  56. package/build/dist/Server/Services/NotificationService.js +2 -2
  57. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  58. package/build/dist/Server/Types/Database/QueryHelper.js +110 -0
  59. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  60. package/build/dist/Server/Types/Database/QueryUtil.js +186 -0
  61. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  62. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +68 -0
  63. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  64. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +68 -0
  65. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  66. package/build/dist/Types/BaseDatabase/EndsWith.js +31 -0
  67. package/build/dist/Types/BaseDatabase/EndsWith.js.map +1 -0
  68. package/build/dist/Types/BaseDatabase/IncludesAll.js +34 -0
  69. package/build/dist/Types/BaseDatabase/IncludesAll.js.map +1 -0
  70. package/build/dist/Types/BaseDatabase/IncludesNone.js +34 -0
  71. package/build/dist/Types/BaseDatabase/IncludesNone.js.map +1 -0
  72. package/build/dist/Types/BaseDatabase/NotContains.js +31 -0
  73. package/build/dist/Types/BaseDatabase/NotContains.js.map +1 -0
  74. package/build/dist/Types/BaseDatabase/StartsWith.js +31 -0
  75. package/build/dist/Types/BaseDatabase/StartsWith.js.map +1 -0
  76. package/build/dist/Types/Email.js +42 -0
  77. package/build/dist/Types/Email.js.map +1 -1
  78. package/build/dist/Types/JSON.js +5 -0
  79. package/build/dist/Types/JSON.js.map +1 -1
  80. package/build/dist/Types/SerializableObjectDictionary.js +10 -0
  81. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  82. package/build/dist/UI/Components/Filters/BooleanFilter.js +1 -1
  83. package/build/dist/UI/Components/Filters/BooleanFilter.js.map +1 -1
  84. package/build/dist/UI/Components/Filters/DateFilter.js +155 -14
  85. package/build/dist/UI/Components/Filters/DateFilter.js.map +1 -1
  86. package/build/dist/UI/Components/Filters/DropdownFilter.js +1 -1
  87. package/build/dist/UI/Components/Filters/DropdownFilter.js.map +1 -1
  88. package/build/dist/UI/Components/Filters/EntityFilter.js +181 -30
  89. package/build/dist/UI/Components/Filters/EntityFilter.js.map +1 -1
  90. package/build/dist/UI/Components/Filters/FilterViewer.js +188 -98
  91. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  92. package/build/dist/UI/Components/Filters/FilterViewerItem.js +1 -6
  93. package/build/dist/UI/Components/Filters/FilterViewerItem.js.map +1 -1
  94. package/build/dist/UI/Components/Filters/FiltersForm.js +46 -38
  95. package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
  96. package/build/dist/UI/Components/Filters/NumberFilter.js +164 -23
  97. package/build/dist/UI/Components/Filters/NumberFilter.js.map +1 -1
  98. package/build/dist/UI/Components/Filters/OperatorSelector.js +41 -0
  99. package/build/dist/UI/Components/Filters/OperatorSelector.js.map +1 -0
  100. package/build/dist/UI/Components/Filters/TextFilter.js +131 -53
  101. package/build/dist/UI/Components/Filters/TextFilter.js.map +1 -1
  102. package/build/dist/UI/Components/Filters/Types/FilterOperator.js +63 -0
  103. package/build/dist/UI/Components/Filters/Types/FilterOperator.js.map +1 -0
  104. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +9 -0
  105. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  106. package/package.json +1 -1
@@ -1,8 +1,21 @@
1
+ import Icon, { SizeProp } from "../Icon/Icon";
1
2
  import Includes from "../../../Types/BaseDatabase/Includes";
3
+ import IncludesAll from "../../../Types/BaseDatabase/IncludesAll";
4
+ import IncludesNone from "../../../Types/BaseDatabase/IncludesNone";
5
+ import StartsWith from "../../../Types/BaseDatabase/StartsWith";
6
+ import EndsWith from "../../../Types/BaseDatabase/EndsWith";
7
+ import NotContains from "../../../Types/BaseDatabase/NotContains";
8
+ import EqualTo from "../../../Types/BaseDatabase/EqualTo";
9
+ import NotEqual from "../../../Types/BaseDatabase/NotEqual";
10
+ import GreaterThan from "../../../Types/BaseDatabase/GreaterThan";
11
+ import LessThan from "../../../Types/BaseDatabase/LessThan";
12
+ import GreaterThanOrEqual from "../../../Types/BaseDatabase/GreaterThanOrEqual";
13
+ import LessThanOrEqual from "../../../Types/BaseDatabase/LessThanOrEqual";
14
+ import IsNull from "../../../Types/BaseDatabase/IsNull";
15
+ import NotNull from "../../../Types/BaseDatabase/NotNull";
2
16
  import Button, { ButtonStyleType } from "../Button/Button";
3
17
  import { DropdownOption } from "../Dropdown/Dropdown";
4
18
  import ErrorMessage from "../ErrorMessage/ErrorMessage";
5
- import { SizeProp } from "../Icon/Icon";
6
19
  import Modal, { ModalWidth } from "../Modal/Modal";
7
20
  import FieldType from "../Types/FieldType";
8
21
  import FilterViewerItem from "./FilterViewerItem";
@@ -151,13 +164,12 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
151
164
 
152
165
  if (data.filter.type === FieldType.Boolean) {
153
166
  filterText = (
154
- <div>
155
- {" "}
167
+ <span>
156
168
  <span className="font-medium">{data.filter.title}</span> is{" "}
157
169
  <span className="font-medium">
158
170
  {data.filterData[data.filter.key] ? "Yes" : "No"}
159
- </span>{" "}
160
- </div>
171
+ </span>
172
+ </span>
161
173
  );
162
174
  return filterText;
163
175
  }
@@ -168,34 +180,83 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
168
180
  data.filter.type === FieldType.Email ||
169
181
  data.filter.type === FieldType.Phone ||
170
182
  data.filter.type === FieldType.URL ||
171
- data.filter.type === FieldType.Hostname
183
+ data.filter.type === FieldType.Hostname ||
184
+ data.filter.type === FieldType.LongText ||
185
+ data.filter.type === FieldType.Name ||
186
+ data.filter.type === FieldType.Port ||
187
+ data.filter.type === FieldType.ObjectID
172
188
  ) {
173
189
  const key: keyof T = data.filter.key;
190
+ const value: unknown = data.filterData[key];
174
191
 
175
- if (data.filterData[key] && data.filterData[key] instanceof Search) {
176
- filterText = (
177
- <div>
178
- {" "}
179
- <span className="font-medium">
180
- {data.filter.title}
181
- </span> contains{" "}
182
- <span className="font-medium">
183
- {data.filterData[data.filter.key]?.toString()}
184
- </span>{" "}
185
- </div>
192
+ type RenderFunction = (verb: string, display: string) => ReactElement;
193
+ const render: RenderFunction = (
194
+ verb: string,
195
+ display: string,
196
+ ): ReactElement => {
197
+ return (
198
+ <span>
199
+ <span className="font-medium">{data.filter.title}</span> {verb}{" "}
200
+ <span className="font-medium">{display}</span>
201
+ </span>
186
202
  );
187
- } else if (data.filterData[key]) {
188
- filterText = (
189
- <div>
190
- {" "}
191
- <span className="font-medium">{data.filter.title}</span> is{" "}
192
- <span className="font-medium">
193
- {data.filterData[data.filter.key]?.toString()}
194
- </span>{" "}
195
- </div>
203
+ };
204
+
205
+ if (value instanceof IsNull) {
206
+ return (
207
+ <span>
208
+ <span className="font-medium">{data.filter.title}</span> is empty
209
+ </span>
196
210
  );
197
211
  }
198
- return filterText;
212
+ if (value instanceof NotNull) {
213
+ return (
214
+ <span>
215
+ <span className="font-medium">{data.filter.title}</span> is not
216
+ empty
217
+ </span>
218
+ );
219
+ }
220
+ if (value instanceof Search) {
221
+ return render("contains", value.toString());
222
+ }
223
+ if (value instanceof NotContains) {
224
+ return render("does not contain", value.toString());
225
+ }
226
+ if (value instanceof StartsWith) {
227
+ return render("starts with", value.toString());
228
+ }
229
+ if (value instanceof EndsWith) {
230
+ return render("ends with", value.toString());
231
+ }
232
+ if (value instanceof InBetween) {
233
+ return render(
234
+ "is between",
235
+ `${value.startValue} and ${value.endValue}`,
236
+ );
237
+ }
238
+ if (value instanceof GreaterThanOrEqual) {
239
+ return render("is ≥", value.toString());
240
+ }
241
+ if (value instanceof LessThanOrEqual) {
242
+ return render("is ≤", value.toString());
243
+ }
244
+ if (value instanceof GreaterThan) {
245
+ return render("is greater than", value.toString());
246
+ }
247
+ if (value instanceof LessThan) {
248
+ return render("is less than", value.toString());
249
+ }
250
+ if (value instanceof NotEqual) {
251
+ return render("does not equal", value.toString());
252
+ }
253
+ if (value instanceof EqualTo) {
254
+ return render("equals", value.toString());
255
+ }
256
+ if (value !== undefined && value !== null && value !== "") {
257
+ return render("is", (value as any).toString());
258
+ }
259
+ return null;
199
260
  }
200
261
 
201
262
  if (
@@ -203,62 +264,67 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
203
264
  data.filter.type === FieldType.DateTime
204
265
  ) {
205
266
  const key: keyof T = data.filter.key;
206
-
207
- const startAndEndDates: InBetween<Date> = data.filterData[
208
- key
209
- ] as InBetween<Date>;
267
+ const value: unknown = data.filterData[key];
210
268
 
211
269
  const shouldOnlyShowDate: boolean = data.filter.type === FieldType.Date;
212
270
  const shouldShowSeconds: boolean =
213
271
  data.filter.type === FieldType.DateTime;
214
272
 
215
- if (
216
- OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
217
- startAndEndDates.startValue as Date,
273
+ type FormatFunction = (d: Date) => string;
274
+ const format: FormatFunction = (d: Date): string => {
275
+ return OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
276
+ d,
218
277
  shouldOnlyShowDate,
219
278
  shouldShowSeconds,
220
- ) ===
221
- OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
222
- startAndEndDates.endValue as Date,
223
- shouldOnlyShowDate,
224
- shouldShowSeconds,
225
- )
226
- ) {
279
+ );
280
+ };
281
+
282
+ type RenderFunction = (verb: string, display: string) => ReactElement;
283
+ const render: RenderFunction = (
284
+ verb: string,
285
+ display: string,
286
+ ): ReactElement => {
227
287
  return (
228
- <div>
229
- {" "}
230
- <span className="font-medium">{data.filter.title}</span> at{" "}
231
- <span className="font-medium">
232
- {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
233
- startAndEndDates.startValue as Date,
234
- data.filter.type === FieldType.Date,
235
- shouldShowSeconds,
236
- )}
237
- </span>{" "}
238
- </div>
288
+ <span>
289
+ <span className="font-medium">{data.filter.title}</span> {verb}{" "}
290
+ <span className="font-medium">{display}</span>
291
+ </span>
292
+ );
293
+ };
294
+
295
+ if (value instanceof IsNull) {
296
+ return (
297
+ <span>
298
+ <span className="font-medium">{data.filter.title}</span> is empty
299
+ </span>
239
300
  );
240
301
  }
241
- return (
242
- <div>
243
- {" "}
244
- <span className="font-medium">{data.filter.title}</span> is in between{" "}
245
- <span className="font-medium">
246
- {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
247
- startAndEndDates.startValue as Date,
248
- shouldOnlyShowDate,
249
- shouldShowSeconds,
250
- )}
251
- </span>{" "}
252
- and{" "}
253
- <span className="font-medium">
254
- {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
255
- startAndEndDates.endValue as Date,
256
- shouldOnlyShowDate,
257
- shouldShowSeconds,
258
- )}
259
- </span>{" "}
260
- </div>
261
- );
302
+ if (value instanceof NotNull) {
303
+ return (
304
+ <span>
305
+ <span className="font-medium">{data.filter.title}</span> is not
306
+ empty
307
+ </span>
308
+ );
309
+ }
310
+ if (value instanceof InBetween) {
311
+ const start: Date = value.startValue as unknown as Date;
312
+ const end: Date = value.endValue as unknown as Date;
313
+ if (format(start) === format(end)) {
314
+ return render("is", format(start));
315
+ }
316
+ return render("is between", `${format(start)} and ${format(end)}`);
317
+ }
318
+ if (value instanceof GreaterThan) {
319
+ return render("is after", format(value.value as unknown as Date));
320
+ }
321
+ if (value instanceof LessThan) {
322
+ return render("is before", format(value.value as unknown as Date));
323
+ }
324
+ if (value instanceof EqualTo) {
325
+ return render("is", format(value.value as unknown as Date));
326
+ }
327
+ return null;
262
328
  }
263
329
 
264
330
  if (data.filter.type === FieldType.JSON) {
@@ -277,14 +343,11 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
277
343
  const isPlural: boolean = Object.keys(json).length > 1;
278
344
 
279
345
  return (
280
- <div className="flex space-x-1">
281
- {" "}
282
- <div className="font-medium">{data.filter.title}</div>{" "}
283
- <div>
284
- {isPlural ? "are" : "is"} {""}
285
- </div>
286
- <div className="font-medium">{formatJson(json)}</div>{" "}
287
- </div>
346
+ <span className="inline-flex items-center space-x-1">
347
+ <span className="font-medium">{data.filter.title}</span>
348
+ <span>{isPlural ? "are" : "is"}</span>
349
+ <span className="font-medium">{formatJson(json)}</span>
350
+ </span>
288
351
  );
289
352
  }
290
353
 
@@ -295,56 +358,83 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
295
358
  data.filter.type === FieldType.EntityArray
296
359
  ) {
297
360
  const key: keyof T = data.filter.key;
361
+ const rawValue: unknown = data.filterData[key];
298
362
 
299
- let items: Array<string> = data.filterData[key] as Array<string>;
300
-
301
- if (typeof items === "string") {
302
- items = [items];
363
+ if (rawValue instanceof IsNull) {
364
+ return (
365
+ <span>
366
+ <span className="font-medium">{data.filter.title}</span> is empty
367
+ </span>
368
+ );
303
369
  }
304
-
305
- if (items instanceof Includes) {
306
- items = items.values as Array<string>;
370
+ if (rawValue instanceof NotNull) {
371
+ return (
372
+ <span>
373
+ <span className="font-medium">{data.filter.title}</span> is not
374
+ empty
375
+ </span>
376
+ );
307
377
  }
308
378
 
309
- const isMoreItems: boolean = items.length > 1;
310
-
311
- if (items && items instanceof Array) {
312
- const entityNames: string = (items as Array<string>)
313
- .map((item: string) => {
314
- // item is the id of the entity. We need to find the name of the entity from the list of entities.
315
-
316
- const entity: DropdownOption | undefined =
317
- data.filter.filterDropdownOptions?.find(
318
- (entity: DropdownOption | undefined) => {
319
- return entity?.value.toString() === item.toString();
320
- },
321
- );
322
-
323
- if (entity) {
324
- return entity.label.toString();
325
- }
326
-
327
- return null;
328
- })
329
- .filter((item: string | null) => {
330
- return item !== null;
331
- })
332
- .join(", ");
379
+ let items: Array<string> = [];
380
+ type MatchMode = "any" | "all" | "none";
381
+ let matchMode: MatchMode = "any";
382
+
383
+ if (rawValue instanceof IncludesAll) {
384
+ items = rawValue.values as Array<string>;
385
+ matchMode = "all";
386
+ } else if (rawValue instanceof IncludesNone) {
387
+ items = rawValue.values as Array<string>;
388
+ matchMode = "none";
389
+ } else if (rawValue instanceof Includes) {
390
+ items = rawValue.values as Array<string>;
391
+ } else if (Array.isArray(rawValue)) {
392
+ items = rawValue as Array<string>;
393
+ } else if (typeof rawValue === "string") {
394
+ items = [rawValue];
395
+ }
333
396
 
334
- if (!entityNames) {
397
+ const entityNames: string = items
398
+ .map((item: string) => {
399
+ const entity: DropdownOption | undefined =
400
+ data.filter.filterDropdownOptions?.find(
401
+ (e: DropdownOption | undefined) => {
402
+ return e?.value.toString() === item.toString();
403
+ },
404
+ );
405
+ if (entity) {
406
+ return entity.label.toString();
407
+ }
335
408
  return null;
336
- }
409
+ })
410
+ .filter((name: string | null) => {
411
+ return name !== null;
412
+ })
413
+ .join(", ");
337
414
 
338
- return (
339
- <div>
340
- <span className="font-medium">{data.filter.title}</span>
341
- {isMoreItems ? " is any of these values: " : " is "}
342
- <span className="font-medium">{entityNames}</span>
343
- </div>
344
- );
415
+ if (!entityNames) {
416
+ return null;
345
417
  }
346
418
 
347
- return filterText;
419
+ const isMoreItems: boolean = items.length > 1;
420
+ let joiner: string;
421
+ if (matchMode === "all") {
422
+ joiner = " has all of: ";
423
+ } else if (matchMode === "none") {
424
+ joiner = " has none of: ";
425
+ } else if (isMoreItems) {
426
+ joiner = " is any of: ";
427
+ } else {
428
+ joiner = " is ";
429
+ }
430
+
431
+ return (
432
+ <span>
433
+ <span className="font-medium">{data.filter.title}</span>
434
+ {joiner}
435
+ <span className="font-medium">{entityNames}</span>
436
+ </span>
437
+ );
348
438
  }
349
439
 
350
440
  return filterText;
@@ -365,36 +455,30 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
365
455
  <div>
366
456
  {showViewer && (
367
457
  <div>
368
- <div className="mt-5 mb-5 bg-gray-50 rounded-xl p-5 border-2 border-gray-100">
369
- <div className="flex mt-1 mb-2">
370
- <div className="flex-auto py-0.5 text-sm leading-5">
458
+ <div className="mt-4 mb-4 bg-gray-50 rounded-xl p-4 border border-gray-200">
459
+ <div className="flex items-center justify-between mb-3">
460
+ <div className="flex items-center gap-2 text-sm text-gray-700">
461
+ <Icon icon={IconProp.Filter} size={SizeProp.Smaller} />
371
462
  <span className="font-semibold">
372
- Filter {props.pluralLabel + " " || ""}
373
- by the following criteria:
374
- </span>{" "}
463
+ Showing {props.pluralLabel || "results"} that match
464
+ </span>
375
465
  </div>
376
466
  </div>
377
467
 
378
- <ul role="list" className="space-y-3">
468
+ <div className="flex flex-wrap gap-2">
379
469
  {filterTexts.map((filterText: ReactElement, index: number) => {
380
- const isLastItem: boolean = index === filterTexts.length - 1;
381
470
  return (
382
- <li className="relative flex gap-x-2" key={index}>
383
- {!isLastItem && (
384
- <div className="absolute left-0 top-0 flex w-6 justify-center -bottom-6">
385
- <div className="w-px bg-gray-200"></div>
386
- </div>
387
- )}
388
- <div className="relative flex h-6 w-6 flex-none items-center justify-center bg-gray-50">
389
- <div className="h-1.5 w-1.5 rounded-full bg-gray-100 ring-1 ring-gray-300"></div>
390
- </div>
391
- <FilterViewerItem key={index} text={filterText} />{" "}
392
- </li>
471
+ <div
472
+ key={index}
473
+ className="inline-flex items-center rounded-full bg-white border border-gray-200 px-3 py-1 text-sm text-gray-700 shadow-sm whitespace-nowrap"
474
+ >
475
+ <FilterViewerItem key={index} text={filterText} />
476
+ </div>
393
477
  );
394
478
  })}
395
- </ul>
479
+ </div>
396
480
 
397
- <div className="flex -ml-3 mt-3 -mb-2">
481
+ <div className="flex -ml-3 mt-3 -mb-1">
398
482
  {/** Edit Filter Button */}
399
483
  <Button
400
484
  className="font-medium text-gray-900"
@@ -425,10 +509,10 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
425
509
  <Modal
426
510
  modalWidth={ModalWidth.Large}
427
511
  isLoading={props.isModalLoading}
428
- title={`${props.singularLabel + " " || ""}Filters`}
429
- description={`Filter ${
430
- props.pluralLabel || ""
431
- } by the following criteria:`}
512
+ title={`Filter ${props.pluralLabel || props.singularLabel || "results"}`}
513
+ description={`Narrow down ${
514
+ props.pluralLabel || "results"
515
+ } by one or more criteria below.`}
432
516
  submitButtonText={`Apply Filters`}
433
517
  onClose={() => {
434
518
  props.onFilterModalClose?.();
@@ -11,17 +11,7 @@ type FilterViewerItemComponentFunction = (
11
11
  const FilterViewerItem: FilterViewerItemComponentFunction = (
12
12
  props: ComponentProps,
13
13
  ): ReactElement => {
14
- const { text } = props;
15
-
16
- return (
17
- <div className="flex w-full -ml-3">
18
- <div className="flex">
19
- <div className="ml-1 flex-auto py-0.5 text-sm leading-5 text-gray-500">
20
- <span className="text-gray-900">{text}</span>{" "}
21
- </div>
22
- </div>
23
- </div>
24
- );
14
+ return <span className="text-gray-800 leading-5">{props.text}</span>;
25
15
  };
26
16
 
27
17
  export default FilterViewerItem;