@lavalogic/scoria 0.40.28 → 0.40.29

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 (127) hide show
  1. package/dist/Components/AccordionGroup.svelte +1 -1
  2. package/dist/Components/AlertModal.svelte +3 -2
  3. package/dist/Components/Base/Pagination.svelte +20 -12
  4. package/dist/Components/Base/PaginationProps.d.ts +5 -0
  5. package/dist/Components/Base/Snippets.svelte +4 -3
  6. package/dist/Components/Button.svelte +9 -8
  7. package/dist/Components/Checkbox.svelte +2 -2
  8. package/dist/Components/ChipsInput.svelte +6 -6
  9. package/dist/Components/CollapsibleCard.svelte +3 -3
  10. package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +7 -6
  11. package/dist/Components/Contexts/ContextMenu.svelte +3 -2
  12. package/dist/Components/Contexts/Toast.svelte +4 -3
  13. package/dist/Components/Contexts/ToastContainer.svelte +6 -5
  14. package/dist/Components/Contexts/Tooltip.svelte +2 -2
  15. package/dist/Components/DataMatrixIcon.svelte +4 -3
  16. package/dist/Components/DateInput.svelte +25 -26
  17. package/dist/Components/DesktopModal.svelte +1 -1
  18. package/dist/Components/DimensionInput.svelte +30 -31
  19. package/dist/Components/DragMenu/DragMenuHolder.svelte +6 -6
  20. package/dist/Components/DragMenu/DraggableCard.svelte +3 -3
  21. package/dist/Components/FileCard.svelte +3 -2
  22. package/dist/Components/FileUpload.svelte +24 -25
  23. package/dist/Components/GridInput.svelte +2 -2
  24. package/dist/Components/HorizontalTabGroup.svelte +1 -1
  25. package/dist/Components/Icon.svelte +8 -2
  26. package/dist/Components/IconProps.d.ts +7 -0
  27. package/dist/Components/Icons.js +365 -365
  28. package/dist/Components/LoadingAnimation.svelte +50 -30
  29. package/dist/Components/LoadingAnimation.svelte.d.ts +1 -1
  30. package/dist/Components/LoadingModal.svelte +3 -2
  31. package/dist/Components/Modal.svelte +9 -9
  32. package/dist/Components/MultiSelect.svelte +37 -18
  33. package/dist/Components/MultiSelectCommonProps.d.ts +15 -1
  34. package/dist/Components/Nav/Nav.svelte +13 -13
  35. package/dist/Components/Nav/ServiceMenuItem.svelte +2 -0
  36. package/dist/Components/Nav/ServicesNav.svelte +6 -6
  37. package/dist/Components/NumberInput.svelte +25 -26
  38. package/dist/Components/PasswordInput.svelte +25 -24
  39. package/dist/Components/PopoverButton.svelte +8 -8
  40. package/dist/Components/QuerySelect.svelte +33 -16
  41. package/dist/Components/QuerySelectProps.d.ts +10 -1
  42. package/dist/Components/ResourceCalendar/ResourceCalendar.svelte +23 -22
  43. package/dist/Components/SidebarPanel.svelte +1 -1
  44. package/dist/Components/SingleSelect.svelte +30 -15
  45. package/dist/Components/SingleSelectCommonProps.d.ts +10 -1
  46. package/dist/Components/StepForm.svelte +6 -5
  47. package/dist/Components/Switch.svelte +5 -5
  48. package/dist/Components/Table/Body/QuickSearchCell.svelte +363 -351
  49. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +5 -6
  50. package/dist/Components/Table/Body/Rows/ColumnList.svelte +3 -2
  51. package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +7 -6
  52. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +6 -7
  53. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +8 -7
  54. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +11 -9
  55. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +7 -8
  56. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +5 -5
  57. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +3 -2
  58. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +3 -3
  59. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +5 -4
  60. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +9 -6
  61. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +4 -4
  62. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +4 -4
  63. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +3 -3
  64. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +9 -7
  65. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +7 -6
  66. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +6 -7
  67. package/dist/Components/Table/Body/Rows/TableRow.svelte +6 -5
  68. package/dist/Components/Table/Body/TableBody.svelte +2 -2
  69. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +3 -2
  70. package/dist/Components/Table/Headers/SelectAllHeader.svelte +4 -3
  71. package/dist/Components/Table/Headers/TableHead.svelte +6 -5
  72. package/dist/Components/Table/Misc/ColumnPanel.svelte +5 -4
  73. package/dist/Components/Table/Misc/ColumnPanelModal.svelte +5 -4
  74. package/dist/Components/Table/Misc/FilterInput.svelte +23 -14
  75. package/dist/Components/Table/Misc/FilterPanel.svelte +12 -11
  76. package/dist/Components/Table/Misc/FilterPanelModal.svelte +3 -2
  77. package/dist/Components/Table/Misc/ShareViewModal.svelte +25 -15
  78. package/dist/Components/Table/Misc/SidePanel.svelte +2 -2
  79. package/dist/Components/Table/Misc/TableConfigurationModal.svelte +50 -40
  80. package/dist/Components/Table/Misc/TableFooter.svelte +18 -12
  81. package/dist/Components/Table/Misc/TableHorizontalBar.svelte +8 -7
  82. package/dist/Components/Table/Misc/TableSidebar.svelte +8 -7
  83. package/dist/Components/Table/Misc/TableViewDropdown.svelte +6 -2
  84. package/dist/Components/Table/Misc/ToolboxPanel.svelte +8 -7
  85. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +9 -8
  86. package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +23 -14
  87. package/dist/Components/Table/Misc/numberDateFilterTypes.d.ts +7 -4
  88. package/dist/Components/Table/Misc/numberDateFilterTypes.js +27 -15
  89. package/dist/Components/Table/Misc/stringFilterTypes.d.ts +7 -3
  90. package/dist/Components/Table/Misc/stringFilterTypes.js +26 -16
  91. package/dist/Components/Table/NestedTable.svelte +4 -0
  92. package/dist/Components/Table/Table.svelte +19 -18
  93. package/dist/Components/Table/Types/Columns/Definitions/Actions/ActionsDef.svelte.js +2 -1
  94. package/dist/Components/Table/Types/Columns/Definitions/RowSelection/RowSelectionDef.svelte.js +2 -1
  95. package/dist/Components/Table/Types/Context/ClipboardState.svelte.js +3 -2
  96. package/dist/Components/Table/Types/Context/ViewState.svelte.js +5 -2
  97. package/dist/Components/Table/Types/DataRepository/IDataRepository.d.ts +6 -0
  98. package/dist/Components/Table/Types/DataRepository/TableDataRepository.svelte.d.ts +8 -0
  99. package/dist/Components/Table/Types/DataRepository/TableDataRepository.svelte.js +14 -0
  100. package/dist/Components/Table/Types/Public/CreateTableOptions.d.ts +3 -0
  101. package/dist/Components/Table/createTable.svelte.js +3 -0
  102. package/dist/Components/TextArea.svelte +24 -23
  103. package/dist/Components/TextInput.svelte +25 -26
  104. package/dist/Components/ThreeStateRadio.svelte +21 -16
  105. package/dist/Components/Touch/BoolCard.svelte +2 -2
  106. package/dist/Components/Touch/DateModal.svelte +5 -4
  107. package/dist/Components/Touch/EditCard.svelte +7 -7
  108. package/dist/Components/Touch/NumberKeyboard.svelte +3 -2
  109. package/dist/Components/Touch/NumberModal.svelte +4 -3
  110. package/dist/Components/Touch/PlusMinusCard.svelte +6 -5
  111. package/dist/Components/Touch/SelectModal.svelte +5 -4
  112. package/dist/Components/Touch/SummaryCard.svelte +9 -9
  113. package/dist/Components/Touch/TextAreaModal.svelte +4 -3
  114. package/dist/Components/Touch/TextModal.svelte +4 -3
  115. package/dist/Components/Touch/TouchCard.svelte +4 -3
  116. package/dist/Components/Touch/TouchModal.svelte +9 -8
  117. package/dist/Components/VerticalTabGroup.svelte +5 -4
  118. package/dist/Contexts/AlertContext.svelte.d.ts +8 -5
  119. package/dist/Contexts/AlertContext.svelte.js +10 -9
  120. package/dist/Helpers/Helpers.svelte.d.ts +23 -2
  121. package/dist/Helpers/Helpers.svelte.js +37 -9
  122. package/dist/Strings/locale.d.ts +19 -0
  123. package/dist/Strings/locale.js +27 -0
  124. package/dist/index.d.ts +1 -0
  125. package/dist/index.js +1 -0
  126. package/dist/scss/_mixins.scss +3406 -3392
  127. package/package.json +14 -7
@@ -1,8 +1,8 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- generics="T extends object, IdType extends Primitive, FilterValueType"
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="T extends object, IdType extends Primitive, FilterValueType"
6
6
  >import { dev } from "$app/environment";
7
7
  import Action from "../../Action.svelte";
8
8
  import Button from "../../Button.svelte";
@@ -15,6 +15,7 @@ import DateModal from "../../Touch/DateModal.svelte";
15
15
  import { hasQuery } from "../TableHelpers.svelte.js";
16
16
  import { devCatch, isDateTuple, isNumericArray } from "../../../Helpers/Helpers.svelte.js";
17
17
  import { Colour, ColourSet } from "../../../scss/colours.js";
18
+ import { m as i18n } from "../../../paraglide/messages.js";
18
19
  import { InputVariant } from "../../../Types/Internal/InputVariant.js";
19
20
  import { Size } from "../../../Types/Internal/Size.js";
20
21
  import { getContext, onDestroy, onMount, untrack } from "svelte";
@@ -64,13 +65,15 @@ let selectedOptions = $state([]);
64
65
  let lastQueryOptions = $state([]);
65
66
  const inputId = $derived(`${tableContext.tableName}-cell-quicksearch-${column.id}`);
66
67
  const filterMode = $derived(tableContext.paginationRepo?.filterModes.get(def.id));
68
+ const numberDateTypes = $derived(numberDateFilterTypes());
69
+ const stringTypes = $derived(stringFilterTypes());
67
70
  const selectedNumberFilterType = $derived.by(() => {
68
71
  const value = filterMode ?? NumberDateFilterMode.In;
69
- return numberDateFilterTypes.find((it) => it.value === value) ?? null;
72
+ return numberDateTypes.find((it) => it.value === value) ?? null;
70
73
  });
71
74
  const selectedStringFilterType = $derived.by(() => {
72
75
  const value = filterMode ?? StringFilterMode.Contains;
73
- return stringFilterTypes.find((it) => it.value === value) ?? null;
76
+ return stringTypes.find((it) => it.value === value) ?? null;
74
77
  });
75
78
  const filteringStateValue = $derived(tableContext.paginationRepo?.filtering.find((it) => it.id === def.id)?.value);
76
79
  $effect(() => {
@@ -268,337 +271,346 @@ onDestroy(() => {
268
271
  debounceTimer = undefined;
269
272
  }
270
273
  });
271
- </script>
272
-
273
- <div class="input-cell {inputId}">
274
- {#if isSearchable}
275
- <div class="input-wrapper-parent">
276
- {#if isDate}
277
- {@const dateValues = tableContext.paginationRepo?.filtering.find((it) => it.id === def.id)
278
- ?.value ?? [null, null]}
279
- {#if isDateTuple(dateValues)}
280
- {@const [fromDate, toDate] = dateValues}
281
- <div class="spaced-around">
282
- <Button
283
- size={Size.FillHeight}
284
- fullWidth
285
- onclick={() => {
286
- showFromDateModal = true;
287
- }}>From {fromDate?.toLocaleDateString() ?? 'Any Date'}</Button
288
- >
289
-
290
- <Button
291
- size={Size.FillHeight}
292
- fullWidth
293
- onclick={() => {
294
- showToDateModal = true;
295
- }}>To {toDate?.toLocaleDateString() ?? 'Any Date'}</Button
296
- >
297
- </div>
298
-
299
- {#if showFromDateModal}
300
- <DateModal
301
- header="Edit Date From"
302
- value={fromDate}
303
- cancelEditing={() => {
304
- showFromDateModal = false;
305
- }}
306
- confirm={(e) => {
307
- tableContext.paginationRepo?.filterBy(def.id, [e, toDate]);
308
- showFromDateModal = false;
309
- }}
310
- />
311
- {/if}
312
-
313
- {#if showToDateModal}
314
- <DateModal
315
- inclusive
316
- header="Edit Date To"
317
- value={toDate}
318
- cancelEditing={() => {
319
- showToDateModal = false;
320
- }}
321
- confirm={(e) => {
322
- tableContext.paginationRepo?.filterBy(def.id, [fromDate, e]);
323
- showToDateModal = false;
324
- }}
325
- />
326
- {/if}
327
- {/if}
328
- {:else if isSelect}
329
- {#if hasQuery(customFilter)}
330
- {#if customFilter.valueAsObject !== true}
331
- {@const label = customFilter.id}
332
-
333
- <!-- TODO: multiselect -->
334
-
335
- <!-- FIXME: Most likely Unsafe -->
336
- <QuerySelect
337
- valueAsObject={false}
338
- clearable
339
- name={customFilter.objectName ?? 'Item'}
340
- valueProp="value"
341
- labelProp="label"
342
- value={value as null}
343
- query={customFilter.query}
344
- bind:options={lastQueryOptions}
345
- onchange={generateOnChangePrimitive(label)}
346
- />
347
- {:else}
348
- {@const label = customFilter.id}
349
-
350
- <!-- TODO: multiselect -->
351
-
352
- <QuerySelect
353
- valueAsObject={true}
354
- clearable
355
- name={customFilter.objectName ?? 'Item'}
356
- valueProp="value"
357
- labelProp="label"
358
- value={value as null}
359
- query={customFilter.query}
360
- bind:options={lastQueryOptions}
361
- onchange={generateOnChangeObject(label)}
362
- />
363
- {/if}
364
- {:else}
365
- {#await options then options}
366
- <MultiSelect
367
- labelProp="label"
368
- valueProp="value"
369
- {options}
370
- valueAsObject
371
- onchange={(e: Array<SelectOption<unknown>>) => {
372
- tableContext.paginationRepo?.filterBy(
373
- def.id,
374
- e.map((it) => it.value)
375
- );
376
- }}
377
- selectedValues={selectedOptions}
378
- collapseSelection
379
- />
380
- {/await}
381
- {/if}
382
- {:else if def instanceof CheckboxDef}
383
- {@const value = (() => {
384
- switch (tableContext.paginationRepo?.filtering.find((it) => it.id === def.id)?.value) {
385
- case true: {
386
- return Ternary.True;
387
- }
388
- case false: {
389
- return Ternary.False;
390
- }
391
- default: {
392
- return Ternary.Neutral;
393
- }
394
- }
395
- })()}
396
- <div class="centered">
397
- <ThreeStateRadio
398
- {value}
399
- yesLabel="Selected"
400
- noLabel="Not Selected"
401
- neutralLabel="Any"
402
- neutralIcon={{ name: 'circle-minus' }}
403
- onchange={(v) => {
404
- switch (v) {
405
- case Ternary.False: {
406
- tableContext.paginationRepo?.filterBy(def.id, false);
407
- return;
408
- }
409
- case Ternary.True: {
410
- tableContext.paginationRepo?.filterBy(def.id, true);
411
- return;
412
- }
413
- case Ternary.Neutral:
414
- default: {
415
- tableContext.paginationRepo?.filterBy(def.id, null);
416
- return;
417
- }
418
- }
419
- }}
420
- />
421
- </div>
422
- {:else if isNumeric}
423
- {#if selectedNumberFilterType?.value === NumberDateFilterMode.Between}
424
- <div class="input-wrapper left">
425
- <NumberInput
426
- data-type="quicksearch"
427
- id={inputId}
428
- bind:value={valueMin}
429
- variant={InputVariant.Table}
430
- placeholder="Min&hellip;"
431
- oninput={() => {
432
- debouncedFilterBy([valueMin, valueMax]);
433
- }}
434
- onkeydown={closeOnCtrlF}
435
- />
436
- </div>
437
- <div class="input-wrapper right">
438
- <NumberInput
439
- data-type="quicksearch"
440
- id={inputId}
441
- bind:value={valueMax}
442
- placeholder="Max&hellip;"
443
- variant={InputVariant.Table}
444
- oninput={() => {
445
- debouncedFilterBy([valueMin, valueMax]);
446
- }}
447
- onkeydown={closeOnCtrlF}
448
- />
449
- </div>
450
- {:else}
451
- <div class="input-wrapper right">
452
- {#await isNullFilter}
453
- loading
454
- {:then isNullFilter}
455
- {#if isNullFilter}
456
- <TextInput
457
- data-type="quicksearch"
458
- id={inputId}
459
- value="is Null"
460
- disabled
461
- variant={InputVariant.Table}
462
- />
463
- {:else}
464
- <!-- NOTE: This is a text input in order to support the __in functionality, which is a comma separated list of numbers -->
465
- <TextInput
466
- data-type="quicksearch"
467
- id={inputId}
468
- bind:value={value as string | null}
469
- placeholder="Filter&hellip;"
470
- variant={InputVariant.Table}
471
- oninput={() => {
472
- debouncedFilterBy([value || null]);
473
- }}
474
- onkeydown={closeOnCtrlF}
475
- />
476
- {/if}
477
- {:catch e}
478
- <!-- eslint-disable-next-line svelte/no-at-debug-tags -->
479
- {@debug e}
480
- {/await}
481
- </div>
482
- {/if}
483
- {:else if value == null || typeof value == 'string'}
484
- <div class="input-wrapper right">
485
- {#if selectedStringFilterType?.value == StringFilterMode.null}
486
- <TextInput
487
- data-type="quicksearch"
488
- id={inputId}
489
- value="is Null"
490
- disabled
491
- variant={InputVariant.Table}
492
- />
493
- {:else if selectedStringFilterType?.value == StringFilterMode.Empty}
494
- <TextInput
495
- data-type="quicksearch"
496
- id={inputId}
497
- value="is Empty"
498
- disabled
499
- variant={InputVariant.Table}
500
- />
501
- {:else}
502
- <TextInput
503
- data-type="quicksearch"
504
- id={inputId}
505
- oninput={() => {
506
- debouncedFilterBy(value);
507
- }}
508
- variant={InputVariant.Table}
509
- bind:value={value as string | null}
510
- placeholder="Filter&hellip;"
511
- />
512
- {/if}
513
- </div>
514
- {/if}
515
-
516
- <!-- TODO button for date, checkbox or select for checkbox -->
517
- </div>
518
-
519
- {#if !isSelect && !isDate && !(def instanceof CheckboxDef)}
520
- <div class="stick-right">
521
- <Action
522
- data-type="quicksearch"
523
- size={Size.FillHeight}
524
- colourSet={ColourSet.Auxiliary}
525
- icon={{
526
- name: 'filter-2',
527
- size: Size.MediumLarge,
528
- colour: Colour['$ui-blue-5'],
529
- }}
530
- onclick={() => {
531
- if (!openedSelect) {
532
- return;
533
- }
534
- if (openedSelect.value === selectSymbol) {
535
- openedSelect.value = null;
536
- } else {
537
- openedSelect.value = selectSymbol;
538
- }
539
- }}
540
- />
541
- </div>
542
- {/if}
543
- {/if}
544
-
545
- {#if isSelectOpen}
546
- <div
547
- class="floating"
548
- transition:fade={{ easing: cubicOut, duration: 100 }}
549
- >
550
- <div class="select-wrapper">
551
- {#if isNumeric}
552
- <SingleSelect
553
- options={numberDateFilterTypes}
554
- labelProp="label"
555
- valueProp="value"
556
- name="Filter Type"
557
- valueAsObject
558
- value={selectedNumberFilterType}
559
- onchange={(newValue: SelectOption<NumberDateFilterMode> | null) => {
560
- const oldFilterType = selectedNumberFilterType;
561
-
562
- const newFilterType = newValue?.value ?? NumberDateFilterMode.In;
563
-
564
- if (newFilterType !== oldFilterType?.value) {
565
- tableContext.paginationRepo?.setFilterMode(def.id, newFilterType);
566
-
567
- if (newFilterType === NumberDateFilterMode.Between) {
568
- tableContext.paginationRepo?.filterBy(def.id, [valueMin, valueMin]);
569
- } else if (newFilterType === NumberDateFilterMode.In) {
570
- tableContext.paginationRepo?.filterBy(def.id, [value]);
571
- } else {
572
- tableContext.paginationRepo?.filterBy(def.id, [valueMin, valueMax]);
573
- }
574
- }
575
- }}
576
- onkeydown={(e: KeyboardEvent) => {
577
- e.stopPropagation();
578
- }}
579
- />
580
- {:else}
581
- <SingleSelect
582
- options={stringFilterTypes}
583
- labelProp="label"
584
- valueProp="value"
585
- name="Filter Type"
586
- valueAsObject
587
- value={selectedStringFilterType}
588
- onchange={(newValue: SelectOption<StringFilterMode> | null) => {
589
- const filterType = newValue?.value ?? StringFilterMode.Contains;
590
- tableContext.paginationRepo?.setFilterMode(def.id, filterType);
591
- }}
592
- onkeydown={(e: KeyboardEvent) => {
593
- e.stopPropagation();
594
- }}
595
- />
596
- {/if}
597
- </div>
598
- </div>
599
- {/if}
600
- </div>
601
-
274
+ </script>
275
+
276
+ <div class="input-cell {inputId}">
277
+ {#if isSearchable}
278
+ <div class="input-wrapper-parent">
279
+ {#if isDate}
280
+ {@const dateValues = tableContext.paginationRepo?.filtering.find((it) => it.id === def.id)
281
+ ?.value ?? [null, null]}
282
+ {#if isDateTuple(dateValues)}
283
+ {@const [fromDate, toDate] = dateValues}
284
+ <div class="spaced-around">
285
+ <Button
286
+ size={Size.FillHeight}
287
+ fullWidth
288
+ onclick={() => {
289
+ showFromDateModal = true;
290
+ }}
291
+ >{i18n['scoria.label.filter_date_from']({
292
+ date: fromDate?.toLocaleDateString() ?? i18n['scoria.label.any_date'](),
293
+ })}</Button
294
+ >
295
+
296
+ <Button
297
+ size={Size.FillHeight}
298
+ fullWidth
299
+ onclick={() => {
300
+ showToDateModal = true;
301
+ }}
302
+ >{i18n['scoria.label.filter_date_to']({
303
+ date: toDate?.toLocaleDateString() ?? i18n['scoria.label.any_date'](),
304
+ })}</Button
305
+ >
306
+ </div>
307
+
308
+ {#if showFromDateModal}
309
+ <DateModal
310
+ header={i18n['scoria.label.edit_date_from']()}
311
+ value={fromDate}
312
+ cancelEditing={() => {
313
+ showFromDateModal = false;
314
+ }}
315
+ confirm={(e) => {
316
+ tableContext.paginationRepo?.filterBy(def.id, [e, toDate]);
317
+ showFromDateModal = false;
318
+ }}
319
+ />
320
+ {/if}
321
+
322
+ {#if showToDateModal}
323
+ <DateModal
324
+ inclusive
325
+ header={i18n['scoria.label.edit_date_to']()}
326
+ value={toDate}
327
+ cancelEditing={() => {
328
+ showToDateModal = false;
329
+ }}
330
+ confirm={(e) => {
331
+ tableContext.paginationRepo?.filterBy(def.id, [fromDate, e]);
332
+ showToDateModal = false;
333
+ }}
334
+ />
335
+ {/if}
336
+ {/if}
337
+ {:else if isSelect}
338
+ {#if hasQuery(customFilter)}
339
+ {#if customFilter.valueAsObject !== true}
340
+ {@const label = customFilter.id}
341
+
342
+ <!-- TODO: multiselect -->
343
+
344
+ <!-- FIXME: Most likely Unsafe -->
345
+ <QuerySelect
346
+ valueAsObject={false}
347
+ clearable
348
+ name={customFilter.objectName ?? 'Item'}
349
+ valueProp="value"
350
+ labelProp="label"
351
+ value={value as null}
352
+ query={customFilter.query}
353
+ bind:options={lastQueryOptions}
354
+ onchange={generateOnChangePrimitive(label)}
355
+ />
356
+ {:else}
357
+ {@const label = customFilter.id}
358
+
359
+ <!-- TODO: multiselect -->
360
+
361
+ <QuerySelect
362
+ valueAsObject={true}
363
+ clearable
364
+ name={customFilter.objectName ?? 'Item'}
365
+ valueProp="value"
366
+ labelProp="label"
367
+ value={value as null}
368
+ query={customFilter.query}
369
+ bind:options={lastQueryOptions}
370
+ onchange={generateOnChangeObject(label)}
371
+ />
372
+ {/if}
373
+ {:else}
374
+ {#await options then options}
375
+ <MultiSelect
376
+ labelProp="label"
377
+ valueProp="value"
378
+ {options}
379
+ valueAsObject
380
+ onchange={(e: Array<SelectOption<unknown>>) => {
381
+ tableContext.paginationRepo?.filterBy(
382
+ def.id,
383
+ e.map((it) => it.value)
384
+ );
385
+ }}
386
+ selectedValues={selectedOptions}
387
+ collapseSelection
388
+ />
389
+ {/await}
390
+ {/if}
391
+ {:else if def instanceof CheckboxDef}
392
+ {@const value = (() => {
393
+ switch (tableContext.paginationRepo?.filtering.find((it) => it.id === def.id)?.value) {
394
+ case true: {
395
+ return Ternary.True;
396
+ }
397
+ case false: {
398
+ return Ternary.False;
399
+ }
400
+ default: {
401
+ return Ternary.Neutral;
402
+ }
403
+ }
404
+ })()}
405
+ <div class="centered">
406
+ <ThreeStateRadio
407
+ {value}
408
+ yesLabel={i18n['scoria.label.selected']()}
409
+ noLabel={i18n['scoria.label.not_selected']()}
410
+ neutralLabel={i18n['scoria.label.any']()}
411
+ noIcon={{ name: 'circle' }}
412
+ neutralIcon={{ name: 'circle-minus' }}
413
+ onchange={(v) => {
414
+ switch (v) {
415
+ case Ternary.False: {
416
+ tableContext.paginationRepo?.filterBy(def.id, false);
417
+ return;
418
+ }
419
+ case Ternary.True: {
420
+ tableContext.paginationRepo?.filterBy(def.id, true);
421
+ return;
422
+ }
423
+ case Ternary.Neutral:
424
+ default: {
425
+ tableContext.paginationRepo?.filterBy(def.id, null);
426
+ return;
427
+ }
428
+ }
429
+ }}
430
+ />
431
+ </div>
432
+ {:else if isNumeric}
433
+ {#if selectedNumberFilterType?.value === NumberDateFilterMode.Between}
434
+ <div class="input-wrapper left">
435
+ <NumberInput
436
+ data-type="quicksearch"
437
+ id={inputId}
438
+ bind:value={valueMin}
439
+ variant={InputVariant.Table}
440
+ placeholder={i18n['scoria.label.min_placeholder']()}
441
+ oninput={() => {
442
+ debouncedFilterBy([valueMin, valueMax]);
443
+ }}
444
+ onkeydown={closeOnCtrlF}
445
+ />
446
+ </div>
447
+ <div class="input-wrapper right">
448
+ <NumberInput
449
+ data-type="quicksearch"
450
+ id={inputId}
451
+ bind:value={valueMax}
452
+ placeholder={i18n['scoria.label.max_placeholder']()}
453
+ variant={InputVariant.Table}
454
+ oninput={() => {
455
+ debouncedFilterBy([valueMin, valueMax]);
456
+ }}
457
+ onkeydown={closeOnCtrlF}
458
+ />
459
+ </div>
460
+ {:else}
461
+ <div class="input-wrapper right">
462
+ {#await isNullFilter}
463
+ loading
464
+ {:then isNullFilter}
465
+ {#if isNullFilter}
466
+ <TextInput
467
+ data-type="quicksearch"
468
+ id={inputId}
469
+ value={i18n['scoria.label.filter_is_null']()}
470
+ disabled
471
+ variant={InputVariant.Table}
472
+ />
473
+ {:else}
474
+ <!-- NOTE: This is a text input in order to support the __in functionality, which is a comma separated list of numbers -->
475
+ <TextInput
476
+ data-type="quicksearch"
477
+ id={inputId}
478
+ bind:value={value as string | null}
479
+ placeholder={i18n['scoria.label.filter_placeholder']()}
480
+ variant={InputVariant.Table}
481
+ oninput={() => {
482
+ debouncedFilterBy([value || null]);
483
+ }}
484
+ onkeydown={closeOnCtrlF}
485
+ />
486
+ {/if}
487
+ {:catch e}
488
+ <!-- eslint-disable-next-line svelte/no-at-debug-tags -->
489
+ {@debug e}
490
+ {/await}
491
+ </div>
492
+ {/if}
493
+ {:else if value == null || typeof value == 'string'}
494
+ <div class="input-wrapper right">
495
+ {#if selectedStringFilterType?.value == StringFilterMode.null}
496
+ <TextInput
497
+ data-type="quicksearch"
498
+ id={inputId}
499
+ value={i18n['scoria.label.filter_is_null']()}
500
+ disabled
501
+ variant={InputVariant.Table}
502
+ />
503
+ {:else if selectedStringFilterType?.value == StringFilterMode.Empty}
504
+ <TextInput
505
+ data-type="quicksearch"
506
+ id={inputId}
507
+ value={i18n['scoria.label.filter_is_empty']()}
508
+ disabled
509
+ variant={InputVariant.Table}
510
+ />
511
+ {:else}
512
+ <TextInput
513
+ data-type="quicksearch"
514
+ id={inputId}
515
+ oninput={() => {
516
+ debouncedFilterBy(value);
517
+ }}
518
+ variant={InputVariant.Table}
519
+ bind:value={value as string | null}
520
+ placeholder={i18n['scoria.label.filter_placeholder']()}
521
+ />
522
+ {/if}
523
+ </div>
524
+ {/if}
525
+
526
+ <!-- TODO button for date, checkbox or select for checkbox -->
527
+ </div>
528
+
529
+ {#if !isSelect && !isDate && !(def instanceof CheckboxDef)}
530
+ <div class="stick-right">
531
+ <Action
532
+ data-type="quicksearch"
533
+ size={Size.FillHeight}
534
+ colourSet={ColourSet.Auxiliary}
535
+ icon={{
536
+ name: 'filter-2',
537
+ size: Size.MediumLarge,
538
+ colour: Colour['$ui-blue-5'],
539
+ }}
540
+ onclick={() => {
541
+ if (!openedSelect) {
542
+ return;
543
+ }
544
+ if (openedSelect.value === selectSymbol) {
545
+ openedSelect.value = null;
546
+ } else {
547
+ openedSelect.value = selectSymbol;
548
+ }
549
+ }}
550
+ />
551
+ </div>
552
+ {/if}
553
+ {/if}
554
+
555
+ {#if isSelectOpen}
556
+ <div
557
+ class="floating"
558
+ transition:fade={{ easing: cubicOut, duration: 100 }}
559
+ >
560
+ <div class="select-wrapper">
561
+ {#if isNumeric}
562
+ <SingleSelect
563
+ options={numberDateTypes}
564
+ labelProp="label"
565
+ valueProp="value"
566
+ name="Filter Type"
567
+ placeholder={i18n['scoria.label.select_filter_type']()}
568
+ valueAsObject
569
+ value={selectedNumberFilterType}
570
+ onchange={(newValue: SelectOption<NumberDateFilterMode> | null) => {
571
+ const oldFilterType = selectedNumberFilterType;
572
+
573
+ const newFilterType = newValue?.value ?? NumberDateFilterMode.In;
574
+
575
+ if (newFilterType !== oldFilterType?.value) {
576
+ tableContext.paginationRepo?.setFilterMode(def.id, newFilterType);
577
+
578
+ if (newFilterType === NumberDateFilterMode.Between) {
579
+ tableContext.paginationRepo?.filterBy(def.id, [valueMin, valueMin]);
580
+ } else if (newFilterType === NumberDateFilterMode.In) {
581
+ tableContext.paginationRepo?.filterBy(def.id, [value]);
582
+ } else {
583
+ tableContext.paginationRepo?.filterBy(def.id, [valueMin, valueMax]);
584
+ }
585
+ }
586
+ }}
587
+ onkeydown={(e: KeyboardEvent) => {
588
+ e.stopPropagation();
589
+ }}
590
+ />
591
+ {:else}
592
+ <SingleSelect
593
+ options={stringTypes}
594
+ labelProp="label"
595
+ valueProp="value"
596
+ name="Filter Type"
597
+ placeholder={i18n['scoria.label.select_filter_type']()}
598
+ valueAsObject
599
+ value={selectedStringFilterType}
600
+ onchange={(newValue: SelectOption<StringFilterMode> | null) => {
601
+ const filterType = newValue?.value ?? StringFilterMode.Contains;
602
+ tableContext.paginationRepo?.setFilterMode(def.id, filterType);
603
+ }}
604
+ onkeydown={(e: KeyboardEvent) => {
605
+ e.stopPropagation();
606
+ }}
607
+ />
608
+ {/if}
609
+ </div>
610
+ </div>
611
+ {/if}
612
+ </div>
613
+
602
614
  <style>.focusable,
603
615
  .checkbox-cell,
604
616
  .input-cell,
@@ -611,9 +623,9 @@ onDestroy(() => {
611
623
  overflow-x: var(--cell-overflow-x, clip);
612
624
  text-overflow: ellipsis;
613
625
  position: relative;
614
- padding-left: 0.75rem;
615
- padding-right: 0.75rem;
616
- border-right: solid 1px #cbd4da;
626
+ padding-inline-start: 0.75rem;
627
+ padding-inline-end: 0.75rem;
628
+ border-inline-end: solid 1px #cbd4da;
617
629
  border-bottom: solid 1px #cbd4da;
618
630
  box-sizing: border-box;
619
631
  width: 100%;
@@ -630,8 +642,8 @@ onDestroy(() => {
630
642
  height: 100%;
631
643
  overflow: hidden;
632
644
  display: flex;
633
- padding-left: 4px;
634
- padding-right: 4px;
645
+ padding-inline-start: 4px;
646
+ padding-inline-end: 4px;
635
647
  gap: 4px;
636
648
  width: 100%;
637
649
  justify-content: space-around;
@@ -641,14 +653,14 @@ div.input-cell {
641
653
  background-color: #f4f7f9;
642
654
  height: var(--height);
643
655
  overflow: visible;
644
- padding-left: 0;
645
- padding-right: 0;
646
- border-right: none;
656
+ padding-inline-start: 0;
657
+ padding-inline-end: 0;
658
+ border-inline-end: none;
647
659
  box-sizing: border-box;
648
660
  }
649
661
  div.input-cell div.stick-right {
650
662
  position: absolute;
651
- right: 0.5rem;
663
+ inset-inline-end: 0.5rem;
652
664
  height: 100%;
653
665
  bottom: 50%;
654
666
  top: 0;
@@ -661,7 +673,7 @@ div.input-cell div.stick-right {
661
673
  div.floating {
662
674
  position: absolute;
663
675
  width: 18rem;
664
- right: -14.5rem;
676
+ inset-inline-end: -14.5rem;
665
677
  top: calc(100% + 0.75rem);
666
678
  z-index: 99999;
667
679
  border: solid 2px #cbd4da;
@@ -675,7 +687,7 @@ div.floating::after {
675
687
  z-index: 5;
676
688
  top: -0.75rem;
677
689
  border-radius: 4px;
678
- left: 1rem;
690
+ inset-inline-start: 1rem;
679
691
  transform: rotate(45deg);
680
692
  background-color: #ffffff;
681
693
  border: solid 2px #cbd4da;
@@ -714,7 +726,7 @@ div.input-wrapper-parent div.input-wrapper.left {
714
726
  div.input-wrapper-parent div.input-wrapper.right {
715
727
  min-width: 100px;
716
728
  flex-grow: 2;
717
- --input-padding-right: 2.6rem;
729
+ --input-padding-inline-end: 2.6rem;
718
730
  }
719
731
  div.input-wrapper-parent > :global(.select-wrapper) {
720
732
  flex: 1 1 auto;
@@ -738,4 +750,4 @@ div.input-wrapper-parent > :global(.select-wrapper) {
738
750
  height: 60px;
739
751
  --input-height: 60px;
740
752
  background-color: #ffffff;
741
- }</style>
753
+ }</style>