@oneuptime/common 10.0.68 → 10.0.70

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 (95) hide show
  1. package/Models/DatabaseModels/KubernetesCluster.ts +5 -0
  2. package/Models/DatabaseModels/KubernetesResource.ts +19 -0
  3. package/Server/API/KubernetesResourceAPI.ts +2 -0
  4. package/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.ts +17 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.ts +134 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  7. package/Server/Services/DatabaseService.ts +19 -4
  8. package/Server/Services/KubernetesResourceService.ts +323 -8
  9. package/Server/Types/Database/QueryHelper.ts +127 -0
  10. package/Server/Types/Database/QueryUtil.ts +244 -0
  11. package/Server/Utils/VM/VMRunner.ts +39 -22
  12. package/Types/BaseDatabase/EndsWith.ts +41 -0
  13. package/Types/BaseDatabase/IncludesAll.ts +45 -0
  14. package/Types/BaseDatabase/IncludesNone.ts +48 -0
  15. package/Types/BaseDatabase/NotContains.ts +41 -0
  16. package/Types/BaseDatabase/StartsWith.ts +41 -0
  17. package/Types/IsolatedVM/ReturnResult.ts +6 -0
  18. package/Types/JSON.ts +20 -0
  19. package/Types/Kubernetes/KubernetesInventoryExtractor.ts +15 -1
  20. package/Types/SerializableObjectDictionary.ts +10 -0
  21. package/UI/Components/Filters/BooleanFilter.tsx +1 -0
  22. package/UI/Components/Filters/DateFilter.tsx +212 -25
  23. package/UI/Components/Filters/DropdownFilter.tsx +1 -0
  24. package/UI/Components/Filters/EntityFilter.tsx +214 -41
  25. package/UI/Components/Filters/FilterViewer.tsx +228 -146
  26. package/UI/Components/Filters/FilterViewerItem.tsx +1 -11
  27. package/UI/Components/Filters/FiltersForm.tsx +148 -97
  28. package/UI/Components/Filters/NumberFilter.tsx +219 -34
  29. package/UI/Components/Filters/OperatorSelector.tsx +91 -0
  30. package/UI/Components/Filters/TextFilter.tsx +182 -71
  31. package/UI/Components/Filters/Types/FilterOperator.ts +73 -0
  32. package/UI/Components/ModelTable/BaseModelTable.tsx +8 -0
  33. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +7 -1
  34. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  35. package/build/dist/Models/DatabaseModels/KubernetesResource.js +20 -0
  36. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
  37. package/build/dist/Server/API/KubernetesResourceAPI.js +2 -0
  38. package/build/dist/Server/API/KubernetesResourceAPI.js.map +1 -1
  39. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.js +12 -0
  40. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.js.map +1 -0
  41. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.js +123 -0
  42. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.js.map +1 -0
  43. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  44. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  45. package/build/dist/Server/Services/DatabaseService.js +18 -4
  46. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  47. package/build/dist/Server/Services/KubernetesResourceService.js +204 -8
  48. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  49. package/build/dist/Server/Types/Database/QueryHelper.js +110 -0
  50. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  51. package/build/dist/Server/Types/Database/QueryUtil.js +180 -0
  52. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  53. package/build/dist/Server/Utils/VM/VMRunner.js +33 -19
  54. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  55. package/build/dist/Types/BaseDatabase/EndsWith.js +31 -0
  56. package/build/dist/Types/BaseDatabase/EndsWith.js.map +1 -0
  57. package/build/dist/Types/BaseDatabase/IncludesAll.js +34 -0
  58. package/build/dist/Types/BaseDatabase/IncludesAll.js.map +1 -0
  59. package/build/dist/Types/BaseDatabase/IncludesNone.js +34 -0
  60. package/build/dist/Types/BaseDatabase/IncludesNone.js.map +1 -0
  61. package/build/dist/Types/BaseDatabase/NotContains.js +31 -0
  62. package/build/dist/Types/BaseDatabase/NotContains.js.map +1 -0
  63. package/build/dist/Types/BaseDatabase/StartsWith.js +31 -0
  64. package/build/dist/Types/BaseDatabase/StartsWith.js.map +1 -0
  65. package/build/dist/Types/JSON.js +5 -0
  66. package/build/dist/Types/JSON.js.map +1 -1
  67. package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js +7 -1
  68. package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js.map +1 -1
  69. package/build/dist/Types/SerializableObjectDictionary.js +10 -0
  70. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  71. package/build/dist/UI/Components/Filters/BooleanFilter.js +1 -1
  72. package/build/dist/UI/Components/Filters/BooleanFilter.js.map +1 -1
  73. package/build/dist/UI/Components/Filters/DateFilter.js +158 -14
  74. package/build/dist/UI/Components/Filters/DateFilter.js.map +1 -1
  75. package/build/dist/UI/Components/Filters/DropdownFilter.js +1 -1
  76. package/build/dist/UI/Components/Filters/DropdownFilter.js.map +1 -1
  77. package/build/dist/UI/Components/Filters/EntityFilter.js +174 -30
  78. package/build/dist/UI/Components/Filters/EntityFilter.js.map +1 -1
  79. package/build/dist/UI/Components/Filters/FilterViewer.js +188 -97
  80. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  81. package/build/dist/UI/Components/Filters/FilterViewerItem.js +1 -6
  82. package/build/dist/UI/Components/Filters/FilterViewerItem.js.map +1 -1
  83. package/build/dist/UI/Components/Filters/FiltersForm.js +46 -38
  84. package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
  85. package/build/dist/UI/Components/Filters/NumberFilter.js +165 -23
  86. package/build/dist/UI/Components/Filters/NumberFilter.js.map +1 -1
  87. package/build/dist/UI/Components/Filters/OperatorSelector.js +41 -0
  88. package/build/dist/UI/Components/Filters/OperatorSelector.js.map +1 -0
  89. package/build/dist/UI/Components/Filters/TextFilter.js +130 -53
  90. package/build/dist/UI/Components/Filters/TextFilter.js.map +1 -1
  91. package/build/dist/UI/Components/Filters/Types/FilterOperator.js +63 -0
  92. package/build/dist/UI/Components/Filters/Types/FilterOperator.js.map +1 -0
  93. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +7 -0
  94. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  95. package/package.json +1 -1
@@ -1,4 +1,18 @@
1
+ import Icon 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";
@@ -151,13 +165,12 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
151
165
 
152
166
  if (data.filter.type === FieldType.Boolean) {
153
167
  filterText = (
154
- <div>
155
- {" "}
168
+ <span>
156
169
  <span className="font-medium">{data.filter.title}</span> is{" "}
157
170
  <span className="font-medium">
158
171
  {data.filterData[data.filter.key] ? "Yes" : "No"}
159
- </span>{" "}
160
- </div>
172
+ </span>
173
+ </span>
161
174
  );
162
175
  return filterText;
163
176
  }
@@ -168,34 +181,82 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
168
181
  data.filter.type === FieldType.Email ||
169
182
  data.filter.type === FieldType.Phone ||
170
183
  data.filter.type === FieldType.URL ||
171
- data.filter.type === FieldType.Hostname
184
+ data.filter.type === FieldType.Hostname ||
185
+ data.filter.type === FieldType.LongText ||
186
+ data.filter.type === FieldType.Name ||
187
+ data.filter.type === FieldType.Port ||
188
+ data.filter.type === FieldType.ObjectID
172
189
  ) {
173
190
  const key: keyof T = data.filter.key;
191
+ const value: unknown = data.filterData[key];
174
192
 
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>
193
+ type RenderFunction = (verb: string, display: string) => ReactElement;
194
+ const render: RenderFunction = (
195
+ verb: string,
196
+ display: string,
197
+ ): ReactElement => {
198
+ return (
199
+ <span>
200
+ <span className="font-medium">{data.filter.title}</span> {verb}{" "}
201
+ <span className="font-medium">{display}</span>
202
+ </span>
186
203
  );
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>
204
+ };
205
+
206
+ if (value instanceof IsNull) {
207
+ return (
208
+ <span>
209
+ <span className="font-medium">{data.filter.title}</span> is empty
210
+ </span>
196
211
  );
197
212
  }
198
- return filterText;
213
+ if (value instanceof NotNull) {
214
+ return (
215
+ <span>
216
+ <span className="font-medium">{data.filter.title}</span> is not 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,66 @@ 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 empty
306
+ </span>
307
+ );
308
+ }
309
+ if (value instanceof InBetween) {
310
+ const start: Date = value.startValue as unknown as Date;
311
+ const end: Date = value.endValue as unknown as Date;
312
+ if (format(start) === format(end)) {
313
+ return render("is", format(start));
314
+ }
315
+ return render("is between", `${format(start)} and ${format(end)}`);
316
+ }
317
+ if (value instanceof GreaterThan) {
318
+ return render("is after", format(value.value as unknown as Date));
319
+ }
320
+ if (value instanceof LessThan) {
321
+ return render("is before", format(value.value as unknown as Date));
322
+ }
323
+ if (value instanceof EqualTo) {
324
+ return render("is", format(value.value as unknown as Date));
325
+ }
326
+ return null;
262
327
  }
263
328
 
264
329
  if (data.filter.type === FieldType.JSON) {
@@ -277,14 +342,11 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
277
342
  const isPlural: boolean = Object.keys(json).length > 1;
278
343
 
279
344
  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>
345
+ <span className="inline-flex items-center space-x-1">
346
+ <span className="font-medium">{data.filter.title}</span>
347
+ <span>{isPlural ? "are" : "is"}</span>
348
+ <span className="font-medium">{formatJson(json)}</span>
349
+ </span>
288
350
  );
289
351
  }
290
352
 
@@ -295,56 +357,82 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
295
357
  data.filter.type === FieldType.EntityArray
296
358
  ) {
297
359
  const key: keyof T = data.filter.key;
360
+ const rawValue: unknown = data.filterData[key];
298
361
 
299
- let items: Array<string> = data.filterData[key] as Array<string>;
300
-
301
- if (typeof items === "string") {
302
- items = [items];
362
+ if (rawValue instanceof IsNull) {
363
+ return (
364
+ <span>
365
+ <span className="font-medium">{data.filter.title}</span> is empty
366
+ </span>
367
+ );
303
368
  }
304
-
305
- if (items instanceof Includes) {
306
- items = items.values as Array<string>;
369
+ if (rawValue instanceof NotNull) {
370
+ return (
371
+ <span>
372
+ <span className="font-medium">{data.filter.title}</span> is not empty
373
+ </span>
374
+ );
307
375
  }
308
376
 
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(", ");
377
+ let items: Array<string> = [];
378
+ type MatchMode = "any" | "all" | "none";
379
+ let matchMode: MatchMode = "any";
380
+
381
+ if (rawValue instanceof IncludesAll) {
382
+ items = rawValue.values as Array<string>;
383
+ matchMode = "all";
384
+ } else if (rawValue instanceof IncludesNone) {
385
+ items = rawValue.values as Array<string>;
386
+ matchMode = "none";
387
+ } else if (rawValue instanceof Includes) {
388
+ items = rawValue.values as Array<string>;
389
+ } else if (Array.isArray(rawValue)) {
390
+ items = rawValue as Array<string>;
391
+ } else if (typeof rawValue === "string") {
392
+ items = [rawValue];
393
+ }
333
394
 
334
- if (!entityNames) {
395
+ const entityNames: string = items
396
+ .map((item: string) => {
397
+ const entity: DropdownOption | undefined =
398
+ data.filter.filterDropdownOptions?.find(
399
+ (e: DropdownOption | undefined) => {
400
+ return e?.value.toString() === item.toString();
401
+ },
402
+ );
403
+ if (entity) {
404
+ return entity.label.toString();
405
+ }
335
406
  return null;
336
- }
407
+ })
408
+ .filter((name: string | null) => {
409
+ return name !== null;
410
+ })
411
+ .join(", ");
337
412
 
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
- );
413
+ if (!entityNames) {
414
+ return null;
345
415
  }
346
416
 
347
- return filterText;
417
+ const isMoreItems: boolean = items.length > 1;
418
+ let joiner: string;
419
+ if (matchMode === "all") {
420
+ joiner = " has all of: ";
421
+ } else if (matchMode === "none") {
422
+ joiner = " has none of: ";
423
+ } else if (isMoreItems) {
424
+ joiner = " is any of: ";
425
+ } else {
426
+ joiner = " is ";
427
+ }
428
+
429
+ return (
430
+ <span>
431
+ <span className="font-medium">{data.filter.title}</span>
432
+ {joiner}
433
+ <span className="font-medium">{entityNames}</span>
434
+ </span>
435
+ );
348
436
  }
349
437
 
350
438
  return filterText;
@@ -365,36 +453,30 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
365
453
  <div>
366
454
  {showViewer && (
367
455
  <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">
456
+ <div className="mt-4 mb-4 bg-gray-50 rounded-xl p-4 border border-gray-200">
457
+ <div className="flex items-center justify-between mb-3">
458
+ <div className="flex items-center gap-2 text-sm text-gray-700">
459
+ <Icon icon={IconProp.Filter} size={SizeProp.Smaller} />
371
460
  <span className="font-semibold">
372
- Filter {props.pluralLabel + " " || ""}
373
- by the following criteria:
374
- </span>{" "}
461
+ Showing {props.pluralLabel || "results"} that match
462
+ </span>
375
463
  </div>
376
464
  </div>
377
465
 
378
- <ul role="list" className="space-y-3">
466
+ <div className="flex flex-wrap gap-2">
379
467
  {filterTexts.map((filterText: ReactElement, index: number) => {
380
- const isLastItem: boolean = index === filterTexts.length - 1;
381
468
  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>
469
+ <div
470
+ key={index}
471
+ 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"
472
+ >
473
+ <FilterViewerItem key={index} text={filterText} />
474
+ </div>
393
475
  );
394
476
  })}
395
- </ul>
477
+ </div>
396
478
 
397
- <div className="flex -ml-3 mt-3 -mb-2">
479
+ <div className="flex -ml-3 mt-3 -mb-1">
398
480
  {/** Edit Filter Button */}
399
481
  <Button
400
482
  className="font-medium text-gray-900"
@@ -425,10 +507,10 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
425
507
  <Modal
426
508
  modalWidth={ModalWidth.Large}
427
509
  isLoading={props.isModalLoading}
428
- title={`${props.singularLabel + " " || ""}Filters`}
429
- description={`Filter ${
430
- props.pluralLabel || ""
431
- } by the following criteria:`}
510
+ title={`Filter ${props.pluralLabel || props.singularLabel || "results"}`}
511
+ description={`Narrow down ${
512
+ props.pluralLabel || "results"
513
+ } by one or more criteria below.`}
432
514
  submitButtonText={`Apply Filters`}
433
515
  onClose={() => {
434
516
  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;