Loading client/src/components/Collections/ListCollectionCreator.vue +99 −12 Original line number Diff line number Diff line <script setup lang="ts"> import "ui/hoverhighlight"; import { faSquare } from "@fortawesome/free-regular-svg-icons"; import { faMinus, faSortAlphaDown, faTimes, faUndo } from "@fortawesome/free-solid-svg-icons"; import { faEdit, faSquare } from "@fortawesome/free-regular-svg-icons"; import { faGripLines, faMinus, faSortAlphaDown, faTimes, faUndo } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { BAlert } from "bootstrap-vue"; import { computed, ref, watch } from "vue"; Loading @@ -18,6 +18,7 @@ import { type Mode, useCollectionCreator } from "./common/useCollectionCreator"; import GButton from "../BaseComponents/GButton.vue"; import GButtonGroup from "../BaseComponents/GButtonGroup.vue"; import GModal from "../BaseComponents/GModal.vue"; import FormSelectMany from "../Form/Elements/FormSelectMany/FormSelectMany.vue"; import HelpText from "../Help/HelpText.vue"; import CollectionCreator from "@/components/Collections/common/CollectionCreator.vue"; Loading Loading @@ -343,12 +344,39 @@ function addUploadedFiles(files: HDASummary[]) { }); } /** If we are creating a collection from a history (not a pre-selection of elements), * once we have some selected elements, we provide an option to rename them in a modal. */ const canRenameElements = computed(() => { return !props.fromSelection && inListElements.value.length > 0; }); /** A toggle for the modal that allows renaming elements in the selected list */ const renamingElements = ref(false); /** find the element in the workingElements array and update its name */ function renameElement(element: any, name: string) { // We do this whole process of removing and readding because inListElements // might be reacting to changes in workingElements, and we want to // prevent that from causing issues with producing duplicate elements in either list: // first check at what index of inlistElements the element is const index = inListElements.value.findIndex((e) => e.id === element.id); if (index < 0) { return; } // remove from inListElements inListElements.value = inListElements.value.filter((e) => e.id !== element.id); // then find the element in workingElements, and rename it element = workingElements.value.find((e) => e.id === element.id); if (element) { element.name = name; } // now add again to inListElements at same index if (index >= 0) { inListElements.value.splice(index, 0, element); } } function selectionAsHdaSummary(value: any): HDASummary { Loading Loading @@ -413,11 +441,13 @@ function selectionAsHdaSummary(value: any): HDASummary { :show-buttons="showButtonsForModal" :collection-name="collectionName" :mode="mode" :can-rename-elements="canRenameElements" @on-update-collection-name="onUpdateCollectionName" @add-uploaded-files="addUploadedFiles" @on-update-datatype-toggle="changeDatatypeFilter" @onUpdateHideSourceItems="onUpdateHideSourceItems" @remove-extensions-toggle="removeExtensionsToggle" @clicked-rename="renamingElements = true" @clicked-create="attemptCreate"> <template v-slot:help-content> <p> Loading @@ -443,7 +473,7 @@ function selectionAsHdaSummary(value: any): HDASummary { <li v-if="!fromSelection"> The filter textbox can be used to rapidly find the datasets of interest by name. </li> <li> <li v-if="fromSelection"> {{ localize("Change the identifier of elements in the list by clicking on") }} <i data-target=".collection-element .name"> {{ localize("the existing name") }} Loading Loading @@ -520,6 +550,24 @@ function selectionAsHdaSummary(value: any): HDASummary { </i> {{ localize(".") }} </p> <p v-if="!fromSelection"> <strong> {{ localize("Optional:") }} </strong> {{ localize( [ "Once you have made your selection, if you wish to rename identifiers for elements in the list", " or change/set the order in which they exist in the final list, you can click on ", ].join("") ) }} <i data-target=".rename-elements"> {{ localize("Rename/Reorder list elements") }} </i> {{ localize(". This opens a modal where you can perform these actions.") }} </p> </template> <template v-slot:middle-content> Loading Loading @@ -646,6 +694,7 @@ function selectionAsHdaSummary(value: any): HDASummary { <draggable v-model="workingElements" class="collection-elements scroll-container flex-row drop-zone" style="max-height: 400px" chosen-class="bg-secondary"> <DatasetCollectionElementView v-for="element in workingElements" Loading @@ -669,14 +718,49 @@ function selectionAsHdaSummary(value: any): HDASummary { :options="workingElements.map((e) => ({ label: e.name || '', value: e }))"> <template v-slot:label-area="{ value }"> <DatasetCollectionElementView class="w-100" text-only not-editable :element="selectionAsHdaSummary(value)" :hide-extension="!showElementExtension" @onRename="(name) => renameElement(value, name)" /> :hide-extension="!showElementExtension" /> </template> </FormSelectMany> </template> </CollectionCreator> <GModal class="rename-elements-modal" :show.sync="renamingElements" fixed-height size="small" title="Rename and Reorder List Elements"> <div> <FontAwesomeIcon :icon="faEdit" fixed-width /> {{ localize("Here, you can change the identifiers of the elements in the list.") }} {{ localize( "The final list will then have these identifiers, and this does not modify the original datasets." ) }} </div> <div> <FontAwesomeIcon :icon="faGripLines" fixed-width /> {{ localize("Also, you can click and drag to reorder the elements in the list.") }} </div> <hr class="w-100 my-2" /> <draggable v-model="inListElements" class="collection-elements scroll-container flex-row" chosen-class="bg-secondary" @wheel.stop> <DatasetCollectionElementView v-for="value in inListElements" :key="value.id" class="w-100" :element="selectionAsHdaSummary(value)" :hide-extension="!showElementExtension" @onRename="(name) => renameElement(value, name)" /> </draggable> </GModal> </div> </div> </template> Loading @@ -686,6 +770,15 @@ function selectionAsHdaSummary(value: any): HDASummary { @import "theme/blue.scss"; .list-collection-creator { .rename-elements-modal { .collection-element { cursor: grab; &:focus { cursor: grabbing; } } } .footer { margin-top: 8px; } Loading @@ -709,7 +802,6 @@ function selectionAsHdaSummary(value: any): HDASummary { } .collection-elements { max-height: 400px; border: 0px solid lightgrey; overflow-y: auto; overflow-x: hidden; Loading @@ -732,11 +824,6 @@ function selectionAsHdaSummary(value: any): HDASummary { border-color: black; } } &:not(.with-actions) { &:hover { border: none; } } &:last-of-type { margin-bottom: 2px; Loading client/src/components/Collections/ListDatasetCollectionElementView.vue +6 −4 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ interface Props { hasActions?: boolean; notEditable?: boolean; hideExtension?: boolean; showHid?: boolean; hideHid?: boolean; textOnly?: boolean; } const props = defineProps<Props>(); Loading Loading @@ -45,15 +46,16 @@ watch( <template> <div class="collection-element d-flex justify-content-between" class="d-flex justify-content-between" :data-hid="element.hid" :class="{ 'with-actions': hasActions }" :class="{ 'collection-element': !textOnly, 'with-actions': hasActions }" role="button" data-description="list dataset collection element" tabindex="0" @keyup.enter="emit('element-is-selected', element)" @click="emit('element-is-selected', element)"> <span class="d-flex flex-gapx-1"> <span v-if="element.hid ?? true">{{ element.hid }}:</span> <span v-if="!hideHid && (element.hid ?? true)">{{ element.hid }}:</span> <strong> <ClickToEdit v-if="!notEditable" v-model="elementName" :title="localize('Click to rename')" /> <span v-else>{{ elementName }}</span> Loading client/src/components/Collections/common/CollectionCreator.vue +6 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ interface Props { showButtons?: boolean; collectionName: string; mode: "wizard" | "modal"; canRenameElements?: boolean; } const props = withDefaults(defineProps<Props>(), { Loading @@ -46,12 +47,14 @@ const props = withDefaults(defineProps<Props>(), { collectionType: undefined, showButtons: true, mode: "modal", canRenameElements: false, }); const emit = defineEmits<{ (e: "on-update-collection-name", name: string): void; (e: "remove-extensions-toggle"): void; (e: "clicked-create", value: string): void; (e: "clicked-rename"): void; (e: "onUpdateHideSourceItems", value: boolean): void; (e: "on-update-datatype-toggle", value: "all" | "datatype" | "ext"): void; (e: "add-uploaded-files", value: HDASummary[]): void; Loading Loading @@ -196,9 +199,11 @@ watch( <CollectionCreatorFooterButtons v-if="showButtons" :short-what-is-being-created="shortWhatIsBeingCreated" :can-rename-elements="props.canRenameElements" :valid-input="validInput" @clicked-cancel="cancelCreate" @clicked-create="emit('clicked-create', collectionName)" /> @clicked-create="emit('clicked-create', collectionName)" @clicked-rename="emit('clicked-rename')" /> </div> </div> </BTab> Loading client/src/components/Collections/common/CollectionCreatorFooterButtons.vue +15 −3 Original line number Diff line number Diff line Loading @@ -6,12 +6,14 @@ import GButton from "@/components/BaseComponents/GButton.vue"; interface Props { validInput: boolean; shortWhatIsBeingCreated: string; canRenameElements?: boolean; } defineProps<Props>(); const emit = defineEmits<{ (e: "clicked-create"): void; (e: "clicked-rename"): void; (e: "clicked-cancel"): void; }>(); </script> Loading @@ -22,8 +24,18 @@ const emit = defineEmits<{ {{ localize("Cancel") }} </GButton> <span> <GButton v-if="canRenameElements" class="rename-elements" size="small" :disabled="!validInput" @click="emit('clicked-rename')"> {{ localize("Rename/Reorder " + shortWhatIsBeingCreated) + " elements" }} </GButton> <GButton class="create-collection" color="blue" :disabled="!validInput" @click="emit('clicked-create')"> {{ localize("Create " + shortWhatIsBeingCreated) }} </GButton> </span> </div> </template> client/src/components/Form/Elements/FormSelectMany/FormSelectMany.vue +1 −0 Original line number Diff line number Diff line Loading @@ -472,6 +472,7 @@ const selectedCount = computed(() => { } .toggle-button { display: block; padding-left: 0; padding-right: 0; } Loading Loading
client/src/components/Collections/ListCollectionCreator.vue +99 −12 Original line number Diff line number Diff line <script setup lang="ts"> import "ui/hoverhighlight"; import { faSquare } from "@fortawesome/free-regular-svg-icons"; import { faMinus, faSortAlphaDown, faTimes, faUndo } from "@fortawesome/free-solid-svg-icons"; import { faEdit, faSquare } from "@fortawesome/free-regular-svg-icons"; import { faGripLines, faMinus, faSortAlphaDown, faTimes, faUndo } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { BAlert } from "bootstrap-vue"; import { computed, ref, watch } from "vue"; Loading @@ -18,6 +18,7 @@ import { type Mode, useCollectionCreator } from "./common/useCollectionCreator"; import GButton from "../BaseComponents/GButton.vue"; import GButtonGroup from "../BaseComponents/GButtonGroup.vue"; import GModal from "../BaseComponents/GModal.vue"; import FormSelectMany from "../Form/Elements/FormSelectMany/FormSelectMany.vue"; import HelpText from "../Help/HelpText.vue"; import CollectionCreator from "@/components/Collections/common/CollectionCreator.vue"; Loading Loading @@ -343,12 +344,39 @@ function addUploadedFiles(files: HDASummary[]) { }); } /** If we are creating a collection from a history (not a pre-selection of elements), * once we have some selected elements, we provide an option to rename them in a modal. */ const canRenameElements = computed(() => { return !props.fromSelection && inListElements.value.length > 0; }); /** A toggle for the modal that allows renaming elements in the selected list */ const renamingElements = ref(false); /** find the element in the workingElements array and update its name */ function renameElement(element: any, name: string) { // We do this whole process of removing and readding because inListElements // might be reacting to changes in workingElements, and we want to // prevent that from causing issues with producing duplicate elements in either list: // first check at what index of inlistElements the element is const index = inListElements.value.findIndex((e) => e.id === element.id); if (index < 0) { return; } // remove from inListElements inListElements.value = inListElements.value.filter((e) => e.id !== element.id); // then find the element in workingElements, and rename it element = workingElements.value.find((e) => e.id === element.id); if (element) { element.name = name; } // now add again to inListElements at same index if (index >= 0) { inListElements.value.splice(index, 0, element); } } function selectionAsHdaSummary(value: any): HDASummary { Loading Loading @@ -413,11 +441,13 @@ function selectionAsHdaSummary(value: any): HDASummary { :show-buttons="showButtonsForModal" :collection-name="collectionName" :mode="mode" :can-rename-elements="canRenameElements" @on-update-collection-name="onUpdateCollectionName" @add-uploaded-files="addUploadedFiles" @on-update-datatype-toggle="changeDatatypeFilter" @onUpdateHideSourceItems="onUpdateHideSourceItems" @remove-extensions-toggle="removeExtensionsToggle" @clicked-rename="renamingElements = true" @clicked-create="attemptCreate"> <template v-slot:help-content> <p> Loading @@ -443,7 +473,7 @@ function selectionAsHdaSummary(value: any): HDASummary { <li v-if="!fromSelection"> The filter textbox can be used to rapidly find the datasets of interest by name. </li> <li> <li v-if="fromSelection"> {{ localize("Change the identifier of elements in the list by clicking on") }} <i data-target=".collection-element .name"> {{ localize("the existing name") }} Loading Loading @@ -520,6 +550,24 @@ function selectionAsHdaSummary(value: any): HDASummary { </i> {{ localize(".") }} </p> <p v-if="!fromSelection"> <strong> {{ localize("Optional:") }} </strong> {{ localize( [ "Once you have made your selection, if you wish to rename identifiers for elements in the list", " or change/set the order in which they exist in the final list, you can click on ", ].join("") ) }} <i data-target=".rename-elements"> {{ localize("Rename/Reorder list elements") }} </i> {{ localize(". This opens a modal where you can perform these actions.") }} </p> </template> <template v-slot:middle-content> Loading Loading @@ -646,6 +694,7 @@ function selectionAsHdaSummary(value: any): HDASummary { <draggable v-model="workingElements" class="collection-elements scroll-container flex-row drop-zone" style="max-height: 400px" chosen-class="bg-secondary"> <DatasetCollectionElementView v-for="element in workingElements" Loading @@ -669,14 +718,49 @@ function selectionAsHdaSummary(value: any): HDASummary { :options="workingElements.map((e) => ({ label: e.name || '', value: e }))"> <template v-slot:label-area="{ value }"> <DatasetCollectionElementView class="w-100" text-only not-editable :element="selectionAsHdaSummary(value)" :hide-extension="!showElementExtension" @onRename="(name) => renameElement(value, name)" /> :hide-extension="!showElementExtension" /> </template> </FormSelectMany> </template> </CollectionCreator> <GModal class="rename-elements-modal" :show.sync="renamingElements" fixed-height size="small" title="Rename and Reorder List Elements"> <div> <FontAwesomeIcon :icon="faEdit" fixed-width /> {{ localize("Here, you can change the identifiers of the elements in the list.") }} {{ localize( "The final list will then have these identifiers, and this does not modify the original datasets." ) }} </div> <div> <FontAwesomeIcon :icon="faGripLines" fixed-width /> {{ localize("Also, you can click and drag to reorder the elements in the list.") }} </div> <hr class="w-100 my-2" /> <draggable v-model="inListElements" class="collection-elements scroll-container flex-row" chosen-class="bg-secondary" @wheel.stop> <DatasetCollectionElementView v-for="value in inListElements" :key="value.id" class="w-100" :element="selectionAsHdaSummary(value)" :hide-extension="!showElementExtension" @onRename="(name) => renameElement(value, name)" /> </draggable> </GModal> </div> </div> </template> Loading @@ -686,6 +770,15 @@ function selectionAsHdaSummary(value: any): HDASummary { @import "theme/blue.scss"; .list-collection-creator { .rename-elements-modal { .collection-element { cursor: grab; &:focus { cursor: grabbing; } } } .footer { margin-top: 8px; } Loading @@ -709,7 +802,6 @@ function selectionAsHdaSummary(value: any): HDASummary { } .collection-elements { max-height: 400px; border: 0px solid lightgrey; overflow-y: auto; overflow-x: hidden; Loading @@ -732,11 +824,6 @@ function selectionAsHdaSummary(value: any): HDASummary { border-color: black; } } &:not(.with-actions) { &:hover { border: none; } } &:last-of-type { margin-bottom: 2px; Loading
client/src/components/Collections/ListDatasetCollectionElementView.vue +6 −4 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ interface Props { hasActions?: boolean; notEditable?: boolean; hideExtension?: boolean; showHid?: boolean; hideHid?: boolean; textOnly?: boolean; } const props = defineProps<Props>(); Loading Loading @@ -45,15 +46,16 @@ watch( <template> <div class="collection-element d-flex justify-content-between" class="d-flex justify-content-between" :data-hid="element.hid" :class="{ 'with-actions': hasActions }" :class="{ 'collection-element': !textOnly, 'with-actions': hasActions }" role="button" data-description="list dataset collection element" tabindex="0" @keyup.enter="emit('element-is-selected', element)" @click="emit('element-is-selected', element)"> <span class="d-flex flex-gapx-1"> <span v-if="element.hid ?? true">{{ element.hid }}:</span> <span v-if="!hideHid && (element.hid ?? true)">{{ element.hid }}:</span> <strong> <ClickToEdit v-if="!notEditable" v-model="elementName" :title="localize('Click to rename')" /> <span v-else>{{ elementName }}</span> Loading
client/src/components/Collections/common/CollectionCreator.vue +6 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ interface Props { showButtons?: boolean; collectionName: string; mode: "wizard" | "modal"; canRenameElements?: boolean; } const props = withDefaults(defineProps<Props>(), { Loading @@ -46,12 +47,14 @@ const props = withDefaults(defineProps<Props>(), { collectionType: undefined, showButtons: true, mode: "modal", canRenameElements: false, }); const emit = defineEmits<{ (e: "on-update-collection-name", name: string): void; (e: "remove-extensions-toggle"): void; (e: "clicked-create", value: string): void; (e: "clicked-rename"): void; (e: "onUpdateHideSourceItems", value: boolean): void; (e: "on-update-datatype-toggle", value: "all" | "datatype" | "ext"): void; (e: "add-uploaded-files", value: HDASummary[]): void; Loading Loading @@ -196,9 +199,11 @@ watch( <CollectionCreatorFooterButtons v-if="showButtons" :short-what-is-being-created="shortWhatIsBeingCreated" :can-rename-elements="props.canRenameElements" :valid-input="validInput" @clicked-cancel="cancelCreate" @clicked-create="emit('clicked-create', collectionName)" /> @clicked-create="emit('clicked-create', collectionName)" @clicked-rename="emit('clicked-rename')" /> </div> </div> </BTab> Loading
client/src/components/Collections/common/CollectionCreatorFooterButtons.vue +15 −3 Original line number Diff line number Diff line Loading @@ -6,12 +6,14 @@ import GButton from "@/components/BaseComponents/GButton.vue"; interface Props { validInput: boolean; shortWhatIsBeingCreated: string; canRenameElements?: boolean; } defineProps<Props>(); const emit = defineEmits<{ (e: "clicked-create"): void; (e: "clicked-rename"): void; (e: "clicked-cancel"): void; }>(); </script> Loading @@ -22,8 +24,18 @@ const emit = defineEmits<{ {{ localize("Cancel") }} </GButton> <span> <GButton v-if="canRenameElements" class="rename-elements" size="small" :disabled="!validInput" @click="emit('clicked-rename')"> {{ localize("Rename/Reorder " + shortWhatIsBeingCreated) + " elements" }} </GButton> <GButton class="create-collection" color="blue" :disabled="!validInput" @click="emit('clicked-create')"> {{ localize("Create " + shortWhatIsBeingCreated) }} </GButton> </span> </div> </template>
client/src/components/Form/Elements/FormSelectMany/FormSelectMany.vue +1 −0 Original line number Diff line number Diff line Loading @@ -472,6 +472,7 @@ const selectedCount = computed(() => { } .toggle-button { display: block; padding-left: 0; padding-right: 0; } Loading