Merge pull request #16282 from ElectronicBlueberry/workflow-editor-tags

Display Tags in Workflow Editor
This commit is contained in:
Marius van den Beek
2023-06-21 19:41:27 +02:00
committed by GitHub
9 changed files with 117 additions and 30 deletions
@@ -0,0 +1,23 @@
<script setup lang="ts">
import StatelessTags from "@/components/TagsMultiselect/StatelessTags.vue";
import { computed } from "vue";
const props = defineProps<{
value?: string;
placeholder?: string;
}>();
const emit = defineEmits<{
(e: "input", value: string): void;
}>();
const valueArray = computed(() => props.value?.split(",").map((v) => v.trim()) ?? []);
function onInput(tags: string[]) {
emit("input", tags.join(","));
}
</script>
<template>
<StatelessTags :value="valueArray" :placeholder="props.placeholder" @input="onInput"></StatelessTags>
</template>
@@ -12,6 +12,7 @@ import FormOptionalText from "./Elements/FormOptionalText.vue";
import FormRulesEdit from "./Elements/FormRulesEdit.vue";
import FormUpload from "./Elements/FormUpload.vue";
import FormDrilldown from "./Elements/FormDrilldown/FormDrilldown.vue";
import FormTags from "./Elements/FormTags.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { ref, computed, useAttrs } from "vue";
import { library } from "@fortawesome/fontawesome-svg-core";
@@ -285,6 +286,10 @@ const isOptional = computed(() => !isRequired.value && attrs.value["optional"] !
:data-label="props.title"
:type="props.type ?? (attrs.options ? 'select' : 'text')"
:attributes="attrs" />
<FormTags
v-else-if="props.type === 'tags'"
v-model="currentValue"
:placeholder="props.attributes?.placeholder" />
<FormInput v-else :id="props.id" v-model="currentValue" :area="attrs['area']" />
</div>
+2 -1
View File
@@ -27,4 +27,5 @@ export type FormParameterTypes =
| "ftpfile"
| "upload"
| "rules"
| "data_dialog";
| "data_dialog"
| "tags";
@@ -17,6 +17,8 @@ interface StatelessTagsProps {
clickable?: boolean;
useToggleLink?: boolean;
maxVisibleTags?: number;
placeholder?: string;
noPadding?: boolean;
}
const props = withDefaults(defineProps<StatelessTagsProps>(), {
@@ -25,6 +27,7 @@ const props = withDefaults(defineProps<StatelessTagsProps>(), {
clickable: false,
useToggleLink: true,
maxVisibleTags: 5,
placeholder: "Add Tags",
});
const emit = defineEmits<{
@@ -113,12 +116,12 @@ function onTagClicked(tag: string) {
</script>
<template>
<div class="stateless-tags px-1">
<div class="stateless-tags" :class="{ 'px-1': !props.noPadding }">
<Multiselect
v-if="!disabled"
ref="multiselectElement"
placeholder="Add Tags"
open-direction="bottom"
:placeholder="props.placeholder"
:value="tags"
:options="userTags"
:multiple="true"
@@ -145,7 +148,7 @@ function onTagClicked(tag: string) {
<template v-slot:caret>
<b-button v-if="!editing" class="toggle-button" variant="link" tabindex="-1" @click="openMultiselect">
Add Tags
{{ props.placeholder }}
<FontAwesomeIcon icon="fa-tags" />
</b-button>
</template>
@@ -173,7 +176,7 @@ function onTagClicked(tag: string) {
</template>
</Multiselect>
<div v-else class="pl-1 pb-2">
<div v-else :class="{ 'pl-1': !props.noPadding, 'pb-2': !props.noPadding }">
<div class="d-inline">
<Tag
v-for="tag in trimmedTags"
@@ -327,6 +330,7 @@ function onTagClicked(tag: string) {
.multiselect__option--selected {
.multiselect-option {
color: $brand-primary;
background-color: $brand-secondary;
.info:not(.highlighted) {
display: inline-block;
@@ -21,15 +21,17 @@
<FormElement
:id="actionNames.TagDatasetAction__tags"
:value="formData[actionNames.TagDatasetAction__tags]"
:attributes="{ placeholder: 'Enter Tags' }"
title="Add Tags"
type="text"
type="tags"
help="This action will set tags for the dataset."
@input="onInput" />
<FormElement
:id="actionNames.RemoveTagDatasetAction__tags"
:value="formData[actionNames.RemoveTagDatasetAction__tags]"
:attributes="{ placeholder: 'Enter Tags' }"
title="Remove Tags"
type="text"
type="tags"
help="This action will remove tags for the dataset."
@input="onInput" />
<FormCard title="Assign columns" collapsible :expanded.sync="expandedColumn">
@@ -16,9 +16,15 @@ import { assertDefined, ensureDefined } from "@/utils/assertions";
import type { UseElementBoundingReturn, UseScrollReturn } from "@vueuse/core";
import { useRelativePosition } from "./composables/relativePosition";
import { NULL_COLLECTION_TYPE_DESCRIPTION, type CollectionTypeDescriptor } from "./modules/collectionTypeDescription";
import StatelessTags from "@/components/TagsMultiselect/StatelessTags.vue";
import { faPlus, faMinus } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
type ElementBounding = UnwrapRef<UseElementBoundingReturn>;
library.add(faPlus, faMinus);
const props = defineProps<{
output: OutputTerminalSource;
workflowOutputs: NonNullable<Step["workflow_outputs"]>;
@@ -266,28 +272,60 @@ const outputDetails = computed(() => {
onBeforeUnmount(() => {
stateStore.deleteOutputTerminalPosition(props.stepId, props.output.name);
});
const addTagsAction = computed(() => {
return props.postJobActions[`TagDatasetAction${props.output.name}`]?.action_arguments?.tags?.split(",") ?? [];
});
const removeTagsAction = computed(() => {
return props.postJobActions[`RemoveTagDatasetAction${props.output.name}`]?.action_arguments?.tags?.split(",") ?? [];
});
</script>
<template>
<div :class="rowClass" :data-output-name="output.name">
<div
v-if="showCalloutActiveOutput"
v-b-tooltip
class="callout-terminal"
title="Checked outputs will become primary workflow outputs and are available as subworkflow outputs."
@keyup="onToggleActive"
@click="onToggleActive">
<i :class="['mark-terminal', activeClass]" />
<div class="d-flex" :class="rowClass" :data-output-name="output.name">
<div class="d-flex flex-column w-100">
<div class="d-flex flex-row">
<div
v-if="showCalloutActiveOutput"
v-b-tooltip
class="callout-terminal"
title="Checked outputs will become primary workflow outputs and are available as subworkflow outputs."
@keyup="onToggleActive"
@click="onToggleActive">
<i :class="['mark-terminal', activeClass]" />
</div>
<div
v-if="showCalloutVisible"
v-b-tooltip
class="callout-terminal"
:title="visibleHint"
@keyup="onToggleVisible"
@click="onToggleVisible">
<i :class="['mark-terminal', visibleClass]" />
</div>
{{ label }}
</div>
<div
v-if="addTagsAction.length > 0"
v-b-tooltip.left
class="d-flex align-items-center overflow-x-hidden"
title="These tags will be added to the output dataset">
<FontAwesomeIcon icon="fa-plus" class="mr-1" />
<StatelessTags disabled no-padding :value="addTagsAction" />
</div>
<div
v-if="removeTagsAction.length > 0"
v-b-tooltip.left
class="d-flex align-items-center overflow-x-hidden"
title="These tags will be removed from the output dataset">
<FontAwesomeIcon icon="fa-minus" class="mr-1" />
<StatelessTags disabled no-padding :value="removeTagsAction" />
</div>
</div>
<div
v-if="showCalloutVisible"
v-b-tooltip
class="callout-terminal"
:title="visibleHint"
@keyup="onToggleVisible"
@click="onToggleVisible">
<i :class="['mark-terminal', visibleClass]" />
</div>
{{ label }}
<draggable-wrapper
:id="id"
ref="el"
+4
View File
@@ -436,3 +436,7 @@ $ui-margin-horizontal-large: $margin-v * 2;
text-decoration: underline;
}
}
.overflow-x-hidden {
overflow-x: hidden !important;
}
+10 -2
View File
@@ -744,11 +744,19 @@ workflow_editor:
type: xpath
selector: >
//li[@class="multiselect__element"]//span[text()="${datatype}"]
add_tags:
add_tags_button:
type: xpath
selector: >
//div[@data-label='Add Tags']//button
add_tags_input:
type: xpath
selector: >
//div[@data-label='Add Tags']//input
remove_tags:
remove_tags_button:
type: xpath
selector: >
//div[@data-label='Remove Tags']//button
remove_tags_input:
type: xpath
selector: >
//div[@data-label='Remove Tags']//input
@@ -688,8 +688,10 @@ steps:
editor.change_datatype.wait_for_and_click()
editor.select_datatype_text_search.wait_for_and_send_keys("bam")
editor.select_datatype(datatype="bam").wait_for_and_click()
self.set_text_element(editor.add_tags, "#crazynewtag")
self.set_text_element(editor.remove_tags, "#oldboringtag")
editor.add_tags_button.wait_for_and_click()
editor.add_tags_input.wait_for_and_send_keys("#crazynewtag" + Keys.ENTER + Keys.ESCAPE)
editor.remove_tags_button.wait_for_and_click()
editor.remove_tags_input.wait_for_and_send_keys("#oldboringtag" + Keys.ENTER + Keys.ESCAPE)
self.sleep_for(self.wait_types.UX_RENDER)
cat_node.clone.wait_for_and_click()
editor.label_input.wait_for_and_send_keys("cloned label")