|
2 | 2 | import { displayStandardErrorAlert, getAlertErrorFromResponse } from '$lib/common/errors'; |
3 | 3 | import ConfirmActionButton from '$lib/components/common/ConfirmActionButton.svelte'; |
4 | 4 | import CreateUpdateImageModal from '$lib/components/v2/projects/datasets/CreateUpdateImageModal.svelte'; |
5 | | - import Paginator from '$lib/components/common/Paginator.svelte'; |
6 | 5 | import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte'; |
7 | | - import { deepCopy, objectChanged } from '$lib/common/component_utilities'; |
| 6 | + import { objectChanged } from '$lib/common/component_utilities'; |
8 | 7 | import SlimSelect from 'slim-select'; |
9 | 8 | import { onDestroy, tick } from 'svelte'; |
10 | | - import Tooltip from '$lib/components/common/Tooltip.svelte'; |
11 | 9 |
|
12 | 10 | /** @type {import('fractal-components/types/api').DatasetV2} */ |
13 | 11 | export let dataset; |
14 | 12 | /** @type {import('fractal-components/types/api').ImagePage} */ |
15 | 13 | export let imagePage; |
16 | 14 | /** @type {string|null} */ |
17 | 15 | export let vizarrViewerUrl; |
18 | | - /** @type {boolean} */ |
19 | | - export let useDatasetFilters; |
20 | 16 | /** |
21 | 17 | * Set to true if the table is displayed inside the "Run workflow" modal. |
22 | 18 | * Used to disable some buttons. |
23 | 19 | * @type {boolean} |
24 | 20 | */ |
25 | 21 | export let runWorkflowModal; |
26 | | - export let attributeFiltersEnabled = true; |
| 22 | + export let filtersEnabled = true; |
27 | 23 | /** @type {{ attribute_filters: { [key: string]: Array<string | number | boolean> | null }, type_filters: { [key: string]: boolean | null }} | null} */ |
28 | 24 | export let initialFilterValues = null; |
29 | 25 |
|
30 | | - let datasetFiltersChanged = false; |
31 | 26 | /** @type {(dataset: import('fractal-components/types/api').DatasetV2) => void} */ |
32 | 27 | export let onDatasetsUpdated = () => {}; |
33 | 28 |
|
34 | 29 | let showTable = false; |
35 | 30 | let firstLoad = true; |
36 | 31 |
|
37 | | - /** @type {Tooltip|undefined} */ |
38 | | - let currentSelectionTooltip; |
39 | | -
|
40 | 32 | /** @type {CreateUpdateImageModal|undefined} */ |
41 | 33 | let imageModal = undefined; |
42 | 34 |
|
43 | 35 | let searching = false; |
44 | 36 | let resetting = false; |
45 | 37 | let savingDatasetFilters = false; |
46 | 38 |
|
47 | | - let loading = false; |
48 | 39 | /** @type {{ [key: string]: Array<string | number | boolean> | null}} */ |
49 | 40 | let attributeFilters = {}; |
50 | 41 |
|
|
132 | 123 |
|
133 | 124 | export async function applySearchFields() { |
134 | 125 | searching = true; |
135 | | - await searchImages(); |
| 126 | + const params = await searchImages(); |
136 | 127 | resetBtnActive = |
137 | 128 | Object.values(attributeFilters).filter((a) => a !== null).length > 0 || |
138 | 129 | Object.values(typeFilters).filter((t) => t !== null).length > 0; |
139 | 130 | searching = false; |
| 131 | + return params; |
140 | 132 | } |
141 | 133 |
|
142 | 134 | async function resetSearchFields() { |
143 | 135 | resetBtnActive = false; |
144 | 136 | resetting = true; |
145 | | - if (useDatasetFilters) { |
146 | | - attributeFilters = deepCopy(dataset.attribute_filters); |
147 | | - typeFilters = deepCopy(dataset.type_filters); |
148 | | - } else { |
149 | | - attributeFilters = getAttributeFilterBaseValues(imagePage); |
150 | | - typeFilters = getTypeFilterBaseValues(imagePage); |
151 | | - } |
| 137 | + attributeFilters = getAttributeFilterBaseValues(imagePage); |
| 138 | + typeFilters = getTypeFilterBaseValues(imagePage); |
152 | 139 | await tick(); |
153 | 140 | await searchImages(); |
154 | 141 | resetting = false; |
155 | 142 | } |
156 | 143 |
|
157 | 144 | export async function load() { |
158 | | - loading = true; |
159 | | - currentSelectionTooltip?.setEnabled(!useDatasetFilters); |
160 | | - if (useDatasetFilters) { |
161 | | - attributeFilters = deepCopy(dataset.attribute_filters); |
162 | | - typeFilters = deepCopy(dataset.type_filters); |
163 | | - } else { |
164 | | - attributeFilters = getAttributeFilterBaseValues(imagePage); |
165 | | - typeFilters = getTypeFilterBaseValues(imagePage); |
166 | | - } |
| 145 | + attributeFilters = getAttributeFilterBaseValues(imagePage); |
| 146 | + typeFilters = getTypeFilterBaseValues(imagePage); |
167 | 147 | await tick(); |
168 | 148 | await searchImages(); |
169 | | - loading = false; |
170 | 149 | } |
171 | 150 |
|
172 | 151 | onDestroy(() => { |
|
233 | 212 | ]) |
234 | 213 | ); |
235 | 214 |
|
236 | | - if (runWorkflowModal) { |
237 | | - if (!attributeFiltersEnabled) { |
238 | | - // disable attribute filters selection |
239 | | - for (const attributeSelector of Object.values(attributesSelectors)) { |
240 | | - attributeSelector.disable(); |
241 | | - } |
| 215 | + if (runWorkflowModal && !filtersEnabled) { |
| 216 | + // disable attribute filters selection |
| 217 | + for (const attributeSelector of Object.values(attributesSelectors)) { |
| 218 | + attributeSelector.disable(); |
242 | 219 | } |
243 | 220 | // disable type filters selection |
244 | 221 | for (const typeSelector of Object.values(typesSelectors)) { |
|
351 | 328 | /** |
352 | 329 | * @param {number|null} currentPage |
353 | 330 | * @param {number|null} pageSize |
| 331 | + * @returns {Promise<{ attribute_filters: any, type_filters: any }>} |
354 | 332 | */ |
355 | 333 | async function searchImages(currentPage = null, pageSize = null) { |
356 | 334 | if (currentPage === null) { |
|
417 | 395 | 'datasetImagesError' |
418 | 396 | ); |
419 | 397 | } |
| 398 | + return params; |
420 | 399 | } |
421 | 400 |
|
422 | 401 | /** |
|
502 | 481 | } |
503 | 482 | } |
504 | 483 |
|
505 | | - $: if (attributeFilters && typeFilters) { |
506 | | - datasetFiltersChanged = |
507 | | - !applyBtnActive && |
508 | | - (attributesChanged(dataset.attribute_filters, removeNullValues(attributeFilters)) || |
509 | | - objectChanged(dataset.type_filters, removeNullValues(typeFilters))); |
510 | | - } |
511 | | -
|
512 | 484 | $: if (dataset) { |
513 | 485 | resetBtnActive = false; |
514 | 486 | } |
|
678 | 650 | {/if} |
679 | 651 | Reset |
680 | 652 | </button> |
681 | | - {#if !runWorkflowModal && useDatasetFilters} |
| 653 | + {#if !runWorkflowModal} |
682 | 654 | <ConfirmActionButton |
683 | 655 | modalId="confirmSaveDatasetFilters" |
684 | 656 | label="Save" |
685 | 657 | message="Save dataset filters" |
686 | | - disabled={!datasetFiltersChanged || savingDatasetFilters} |
| 658 | + disabled={savingDatasetFilters} |
687 | 659 | callbackAction={async () => { |
688 | 660 | await saveDatasetFilters(); |
689 | 661 | }} |
|
753 | 725 | </tbody> |
754 | 726 | </table> |
755 | 727 | </div> |
756 | | - <div class="pb-2" id="dataset-filters-wrapper" class:sticky-bottom={!runWorkflowModal}> |
757 | | - <div class="row"> |
758 | | - <div class="col-lg-3 mb-3"> |
759 | | - {#if !runWorkflowModal} |
760 | | - <input |
761 | | - type="radio" |
762 | | - class="btn-check" |
763 | | - name="filters-switch" |
764 | | - id="all-images" |
765 | | - autocomplete="off" |
766 | | - value={false} |
767 | | - bind:group={useDatasetFilters} |
768 | | - on:change={load} |
769 | | - disabled={loading || searching || resetting} |
770 | | - /> |
771 | | - <label class="btn btn-white btn-outline-primary" for="all-images">All images</label> |
772 | | - <Tooltip |
773 | | - id="current-selection-label" |
774 | | - title="These are default selection for images on which a workflow will be run" |
775 | | - placement="bottom" |
776 | | - bind:this={currentSelectionTooltip} |
777 | | - > |
778 | | - <input |
779 | | - type="radio" |
780 | | - class="btn-check" |
781 | | - name="filters-switch" |
782 | | - id="current-selection" |
783 | | - autocomplete="off" |
784 | | - value={true} |
785 | | - bind:group={useDatasetFilters} |
786 | | - on:change={load} |
787 | | - disabled={loading || searching || resetting} |
788 | | - /> |
789 | | - <label class="btn btn-white btn-outline-primary" for="current-selection"> |
790 | | - Current selection |
791 | | - </label> |
792 | | - </Tooltip> |
793 | | - {#if loading} |
794 | | - <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" /> |
795 | | - {/if} |
796 | | - {/if} |
797 | | - </div> |
798 | | - <div class="col-lg-6"> |
799 | | - <Paginator |
800 | | - currentPage={imagePage.current_page} |
801 | | - pageSize={imagePage.page_size} |
802 | | - totalCount={imagePage.total_count} |
803 | | - onPageChange={searchImages} |
804 | | - /> |
805 | | - </div> |
806 | | - {#if !runWorkflowModal} |
807 | | - <div class="col-lg-3"> |
808 | | - <button |
809 | | - class="btn btn-outline-secondary float-end" |
810 | | - on:click={() => imageModal?.openForCreate()} |
811 | | - > |
812 | | - <i class="bi bi-plus-circle" /> |
813 | | - Add an image list entry |
814 | | - </button> |
815 | | - </div> |
816 | | - {/if} |
817 | | - </div> |
818 | | - </div> |
819 | 728 | </div> |
820 | 729 | {/if} |
821 | 730 |
|
822 | | -<CreateUpdateImageModal {dataset} onImageSave={searchImages} bind:this={imageModal} /> |
| 731 | +<CreateUpdateImageModal |
| 732 | + {dataset} |
| 733 | + onImageSave={async () => { |
| 734 | + await searchImages(); |
| 735 | + }} |
| 736 | + bind:this={imageModal} |
| 737 | +/> |
823 | 738 |
|
824 | 739 | <style> |
825 | 740 | #dataset-images-table td:last-child, |
|
831 | 746 | word-break: break-all; |
832 | 747 | } |
833 | 748 |
|
834 | | - #dataset-filters-wrapper { |
835 | | - background-color: #fff; |
836 | | - } |
837 | | -
|
838 | | - .btn-check:not(:checked) + .btn-white { |
839 | | - color: #0d6efd; |
840 | | - background-color: #fff; |
841 | | - } |
842 | | -
|
843 | 749 | .wrap { |
844 | 750 | white-space: normal; |
845 | 751 | } |
|
0 commit comments