Skip to content

Commit 455da5c

Browse files
authored
Merge pull request galaxyproject#18936 from itisAliRH/workflow-license-creator-keyboard
2 parents 4a7c220 + 37b4fa4 commit 455da5c

5 files changed

Lines changed: 137 additions & 148 deletions

File tree

Lines changed: 107 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,112 @@
1+
<script setup lang="ts">
2+
import { watchImmediate } from "@vueuse/core";
3+
import { BAlert } from "bootstrap-vue";
4+
import { computed, ref } from "vue";
5+
import Multiselect from "vue-multiselect";
6+
7+
import { GalaxyApi } from "@/api";
8+
import { type components } from "@/api/schema";
9+
import { errorMessageAsString } from "@/utils/simple-error";
10+
11+
import License from "@/components/License/License.vue";
12+
import LoadingSpan from "@/components/LoadingSpan.vue";
13+
14+
const defaultLicense: LicenseType = {
15+
licenseId: null,
16+
name: "*Do not specify a license.*",
17+
};
18+
19+
type LicenseMetadataModel = components["schemas"]["LicenseMetadataModel"];
20+
type LicenseType = {
21+
licenseId: string | null;
22+
name: string;
23+
};
24+
25+
interface Props {
26+
inputLicense: string;
27+
}
28+
29+
const props = defineProps<Props>();
30+
31+
const emit = defineEmits<{
32+
(e: "onLicense", license: string | null): void;
33+
}>();
34+
35+
const licensesLoading = ref(false);
36+
const errorMessage = ref<string>("");
37+
const currentLicense = ref<LicenseType>();
38+
const licenses = ref<LicenseMetadataModel[] | undefined>([]);
39+
40+
const licenseOptions = computed(() => {
41+
const options: LicenseType[] = [];
42+
43+
options.push(defaultLicense);
44+
45+
for (const license of licenses.value || []) {
46+
if (license.licenseId == currentLicense.value?.licenseId || license.recommended) {
47+
options.push({
48+
licenseId: license.licenseId,
49+
name: license.name,
50+
});
51+
}
52+
}
53+
54+
return options;
55+
});
56+
57+
function onLicense(license: LicenseType) {
58+
emit("onLicense", license.licenseId);
59+
}
60+
61+
async function fetchLicenses() {
62+
const { error, data } = await GalaxyApi().GET("/api/licenses");
63+
64+
if (error) {
65+
errorMessage.value = errorMessageAsString(error) || "Unable to fetch licenses.";
66+
}
67+
68+
licenses.value = data;
69+
70+
licensesLoading.value = false;
71+
}
72+
73+
async function setCurrentLicense() {
74+
if (!licenses.value?.length && !licensesLoading.value) {
75+
licensesLoading.value = true;
76+
77+
await fetchLicenses();
78+
}
79+
80+
const inputLicense = props.inputLicense;
81+
82+
currentLicense.value = (licenses.value || []).find((l) => l.licenseId == inputLicense) || defaultLicense;
83+
}
84+
85+
watchImmediate(
86+
() => props.inputLicense,
87+
() => {
88+
setCurrentLicense();
89+
}
90+
);
91+
</script>
92+
193
<template>
2-
<div v-if="editLicense">
3-
<LoadingSpan v-if="licensesLoading" message="Loading licenses..." />
4-
<b-form-select
94+
<div>
95+
<BAlert v-if="licensesLoading" variant="info" class="m-0" show>
96+
<LoadingSpan message="Loading licenses" />
97+
</BAlert>
98+
<BAlert v-else-if="errorMessage" variant="danger" class="m-0" show>
99+
{{ errorMessage }}
100+
</BAlert>
101+
<Multiselect
5102
v-else
6-
v-model="license"
103+
v-model="currentLicense"
7104
data-description="license select"
8-
:options="licenseOptions"></b-form-select>
9-
<License v-if="currentLicenseInfo" :license-id="license" :input-license-info="currentLicenseInfo">
10-
<template v-slot:buttons>
11-
<span v-b-tooltip.hover title="Save License"
12-
><FontAwesomeIcon data-description="license save" icon="save" @click="onSave"
13-
/></span>
14-
<span v-b-tooltip.hover title="Cancel Edit"><FontAwesomeIcon icon="times" @click="disableEdit" /></span>
15-
</template>
16-
</License>
17-
<div v-else>
18-
<a href="#" @click.prevent="onSave">Save without license</a> or
19-
<a href="#" @click.prevent="editLicense = false">cancel edit.</a>
20-
</div>
21-
</div>
22-
<div v-else-if="license" data-description="license selector" :data-license="license">
23-
<License :license-id="license">
24-
<template v-slot:buttons>
25-
<span v-b-tooltip.hover title="Edit License"
26-
><FontAwesomeIcon icon="edit" data-description="edit license link" @click="editLicense = true"
27-
/></span>
28-
</template>
29-
</License>
30-
</div>
31-
<div v-else data-description="license selector" data-license="null">
32-
<i
33-
><a href="#" data-description="edit license link" @click.prevent="editLicense = true"
34-
>Specify a license for this workflow.</a
35-
></i
36-
>
105+
track-by="licenseId"
106+
:options="licenseOptions"
107+
label="name"
108+
placeholder="Select a license"
109+
@select="onLicense" />
110+
<License v-if="currentLicense?.licenseId" :license-id="currentLicense.licenseId" />
37111
</div>
38112
</template>
39-
40-
<script>
41-
import { library } from "@fortawesome/fontawesome-svg-core";
42-
import { faEdit, faSave, faTimes } from "@fortawesome/free-solid-svg-icons";
43-
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
44-
import axios from "axios";
45-
import BootstrapVue from "bootstrap-vue";
46-
import LoadingSpan from "components/LoadingSpan";
47-
import { getAppRoot } from "onload/loadConfig";
48-
import Vue from "vue";
49-
50-
import License from "./License";
51-
52-
library.add(faSave);
53-
library.add(faTimes);
54-
library.add(faEdit);
55-
56-
Vue.use(BootstrapVue);
57-
58-
export default {
59-
components: { License, LoadingSpan, FontAwesomeIcon },
60-
props: {
61-
inputLicense: {
62-
type: String,
63-
},
64-
},
65-
data() {
66-
return {
67-
license: this.inputLicense || null,
68-
licensesLoading: false,
69-
licenses: [],
70-
editLicense: false,
71-
};
72-
},
73-
computed: {
74-
currentLicenseInfo() {
75-
for (const license of this.licenses) {
76-
if (license.licenseId == this.license) {
77-
return license;
78-
}
79-
}
80-
return null;
81-
},
82-
licenseOptions() {
83-
const options = [];
84-
options.push({
85-
value: null,
86-
text: "*Do not specify a license.*",
87-
});
88-
for (const license of this.licenses) {
89-
if (license.licenseId == this.license || license.recommended) {
90-
options.push({
91-
value: license.licenseId,
92-
text: license.name,
93-
});
94-
}
95-
}
96-
return options;
97-
},
98-
},
99-
watch: {
100-
inputLicense() {
101-
this.license = this.inputLicense;
102-
},
103-
},
104-
mounted() {
105-
const url = `${getAppRoot()}api/licenses`;
106-
axios
107-
.get(url)
108-
.then((response) => response.data)
109-
.then((data) => {
110-
this.licenses = data;
111-
this.licensesLoading = false;
112-
})
113-
.catch((e) => {
114-
console.error(e);
115-
});
116-
},
117-
methods: {
118-
onSave() {
119-
this.onLicense(this.license);
120-
this.disableEdit();
121-
},
122-
disableEdit() {
123-
this.editLicense = false;
124-
},
125-
onLicense(license) {
126-
this.$emit("onLicense", license);
127-
},
128-
},
129-
};
130-
</script>

client/src/components/SchemaOrg/CreatorEditor.vue

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,24 @@
1010
<div v-for="(creator, index) in creatorsCurrent" :key="index">
1111
<CreatorViewer :creator="creator">
1212
<template v-slot:buttons>
13-
<span v-b-tooltip.hover title="Edit Creator"
14-
><FontAwesomeIcon icon="edit" @click="onEdit(index)"
15-
/></span>
16-
<span v-b-tooltip.hover title="Remove Creator">
17-
<FontAwesomeIcon icon="times" @click="onRemove(index)" />
18-
</span>
13+
<BButton
14+
v-b-tooltip.hover
15+
class="inline-icon-button"
16+
variant="link"
17+
size="sm"
18+
title="Edit Creator"
19+
@click="onEdit(index)">
20+
<FontAwesomeIcon icon="edit" />
21+
</BButton>
22+
<BButton
23+
v-b-tooltip.hover
24+
class="inline-icon-button"
25+
variant="link"
26+
size="sm"
27+
title="Remove Creator"
28+
@click="onRemove(index)">
29+
<FontAwesomeIcon icon="times" />
30+
</BButton>
1931
</template>
2032
</CreatorViewer>
2133
</div>

client/src/utils/navigation/navigation.yml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -747,15 +747,10 @@ workflow_editor:
747747
canvas_body: '#workflow-canvas'
748748
edit_annotation: '#workflow-annotation'
749749
edit_name: '#workflow-name'
750-
license_selector:
751-
selector: 'license selector'
752-
type: data-description
753-
edit_license_link:
754-
selector: 'edit license link'
755-
type: data-description
756-
license_select:
757-
selector: 'license select'
758-
type: data-description
750+
license_selector: '[data-description="license select"]'
751+
license_current_value: '[data-description="license select"] .multiselect__single'
752+
license_selector_input: '[data-description="license select"] input.multiselect__input'
753+
license_selector_option: '[data-description="license select"] .multiselect__element'
759754
license_save:
760755
selector: 'license save'
761756
type: data-description

lib/galaxy/selenium/navigates_galaxy.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,11 +1204,12 @@ def rule_builder_enter_source_text(self, json):
12041204
text_area_elem.send_keys(json)
12051205

12061206
def workflow_editor_set_license(self, license: str) -> None:
1207-
editor = self.components.workflow_editor
1208-
editor.edit_license_link.wait_for_and_click()
1209-
select = editor.license_select.wait_for_select()
1210-
select.select_by_value(license)
1211-
editor.license_save.wait_for_and_click()
1207+
license_selector = self.components.workflow_editor.license_selector
1208+
license_selector.wait_for_and_click()
1209+
license_selector.wait_for_and_send_keys(license)
1210+
1211+
license_selector_option = self.components.workflow_editor.license_selector_option
1212+
license_selector_option.wait_for_and_click()
12121213

12131214
def workflow_editor_click_option(self, option_label):
12141215
self.workflow_editor_click_options()

lib/galaxy_test/selenium/test_workflow_editor.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,14 @@ def test_edit_license(self):
100100
name = self.workflow_create_new()
101101
editor.canvas_body.wait_for_visible()
102102
editor.license_selector.wait_for_visible()
103-
editor.license_selector.assert_no_axe_violations_with_impact_of_at_least("serious")
104-
editor.license_selector.assert_data_value("license", "null")
103+
assert "Do not specify" in editor.license_current_value.wait_for_text()
105104

106105
self.workflow_editor_set_license("MIT")
107106
self.workflow_editor_click_save()
108107

109108
self.workflow_index_open_with_name(name)
110109
editor.license_selector.wait_for_visible()
111-
editor.license_selector.assert_data_value("license", "MIT")
110+
assert "MIT" in editor.license_current_value.wait_for_text()
112111

113112
@selenium_test
114113
def test_optional_select_data_field(self):

0 commit comments

Comments
 (0)