mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #15180 from ElectronicBlueberry/typeathon
Day 1 Typeathon
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useDetailedDatatypes } from "composables/datatypes";
|
||||
import { useDetailedDatatypes, type DetailedDatatypes } from "composables/datatypes";
|
||||
import { useFilterObjectArray } from "composables/utils/filter";
|
||||
import DelayedInput from "components/Common/DelayedInput.vue";
|
||||
|
||||
const filter = ref("");
|
||||
const filterFields = ["extension"];
|
||||
const filterFields: Array<keyof DetailedDatatypes> = ["extension"];
|
||||
|
||||
const { datatypes } = useDetailedDatatypes();
|
||||
const filteredDatatypes = useFilterObjectArray(datatypes, filter, filterFields);
|
||||
|
||||
@@ -1,95 +1,67 @@
|
||||
<script setup>
|
||||
import FormBoolean from "./Elements/FormBoolean";
|
||||
import FormHidden from "./Elements/FormHidden";
|
||||
import FormInput from "./Elements/FormInput";
|
||||
import FormParameter from "./Elements/FormParameter";
|
||||
import FormSelection from "./Elements/FormSelection";
|
||||
import FormColor from "./Elements/FormColor";
|
||||
import FormDirectory from "./Elements/FormDirectory";
|
||||
import FormNumber from "./Elements/FormNumber";
|
||||
import FormRulesEdit from "./Elements/FormRulesEdit";
|
||||
<script setup lang="ts">
|
||||
import FormBoolean from "./Elements/FormBoolean.vue";
|
||||
import FormHidden from "./Elements/FormHidden.vue";
|
||||
import FormInput from "./Elements/FormInput.vue";
|
||||
import FormParameter from "./Elements/FormParameter.vue";
|
||||
import FormSelection from "./Elements/FormSelection.vue";
|
||||
import FormColor from "./Elements/FormColor.vue";
|
||||
import FormDirectory from "./Elements/FormDirectory.vue";
|
||||
import FormNumber from "./Elements/FormNumber.vue";
|
||||
import FormRulesEdit from "./Elements/FormRulesEdit.vue";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { ref, computed, useAttrs } from "vue";
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
import { faExclamation, faTimes, faArrowsAltH } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCaretSquareDown, faCaretSquareUp } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: "identifier",
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
value: {
|
||||
default: null,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
refreshOnChange: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
error: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
backbonejs: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
attributes: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
collapsedEnableText: {
|
||||
type: String,
|
||||
default: "Enable",
|
||||
},
|
||||
collapsedDisableText: {
|
||||
type: String,
|
||||
default: "Disable",
|
||||
},
|
||||
collapsedEnableIcon: {
|
||||
type: String,
|
||||
default: "far fa-caret-square-down",
|
||||
},
|
||||
collapsedDisableIcon: {
|
||||
type: String,
|
||||
default: "far fa-caret-square-up",
|
||||
},
|
||||
connectedEnableText: {
|
||||
type: String,
|
||||
default: "Remove connection from module.",
|
||||
},
|
||||
connectedDisableText: {
|
||||
type: String,
|
||||
default: "Add connection to module.",
|
||||
},
|
||||
connectedEnableIcon: {
|
||||
type: String,
|
||||
default: "fa fa-times",
|
||||
},
|
||||
connectedDisableIcon: {
|
||||
type: String,
|
||||
default: "fa fa-arrows-alt-h",
|
||||
},
|
||||
workflowBuildingMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
import type { ComputedRef } from "vue";
|
||||
import type { FormParameterTypes, FormParameterAttributes, FormParameterValue } from "./parameterTypes";
|
||||
|
||||
export interface FormElementProps {
|
||||
id?: string;
|
||||
type?: FormParameterTypes;
|
||||
value?: FormParameterValue;
|
||||
title?: string;
|
||||
refreshOnChange?: boolean;
|
||||
help?: string;
|
||||
error?: string;
|
||||
backbonejs?: boolean;
|
||||
disabled?: boolean;
|
||||
attributes?: FormParameterAttributes;
|
||||
collapsedEnableText?: string;
|
||||
collapsedDisableText?: string;
|
||||
collapsedEnableIcon?: string;
|
||||
collapsedDisableIcon?: string;
|
||||
connectedEnableText?: string;
|
||||
connectedDisableText?: string;
|
||||
connectedEnableIcon?: string;
|
||||
connectedDisableIcon?: string;
|
||||
workflowBuildingMode?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<FormElementProps>(), {
|
||||
id: "identifier",
|
||||
refreshOnChange: false,
|
||||
backbonejs: false,
|
||||
disabled: false,
|
||||
collapsedEnableText: "Enable",
|
||||
collapsedDisableText: "Disable",
|
||||
collapsedEnableIcon: "far fa-caret-square-down",
|
||||
collapsedDisableIcon: "far fa-caret-square-up",
|
||||
connectedEnableText: "Remove connection from module.",
|
||||
connectedDisableText: "Add connection to module.",
|
||||
connectedEnableIcon: "fa fa-times",
|
||||
connectedDisableIcon: "fa fa-arrows-alt-h",
|
||||
workflowBuildingMode: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["input", "change"]);
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: FormParameterValue, id: string): void;
|
||||
(e: "change", shouldRefresh: boolean): void;
|
||||
}>();
|
||||
|
||||
//@ts-ignore bad library types
|
||||
library.add(faExclamation, faTimes, faArrowsAltH, faCaretSquareDown, faCaretSquareUp);
|
||||
|
||||
/** TODO: remove attrs computed.
|
||||
useAttrs is *not* reactive, and does not play nice with type safety.
|
||||
@@ -97,15 +69,15 @@ const emit = defineEmits(["input", "change"]);
|
||||
but should be removed as soon as that component is removed.
|
||||
*/
|
||||
const attrs = computed(() => props.attributes || useAttrs());
|
||||
const collapsibleValue = computed(() => attrs.value["collapsible_value"]);
|
||||
const defaultValue = computed(() => attrs.value["default_value"]);
|
||||
const connectedValue = { __class__: "ConnectedValue" };
|
||||
const collapsibleValue: ComputedRef<FormParameterValue> = computed(() => attrs.value["collapsible_value"]);
|
||||
const defaultValue: ComputedRef<FormParameterValue> = computed(() => attrs.value["default_value"]);
|
||||
const connectedValue: FormParameterValue = { __class__: "ConnectedValue" };
|
||||
|
||||
const connected = ref(false);
|
||||
const collapsed = ref(false);
|
||||
|
||||
const collapsible = computed(() => !props.disabled && collapsibleValue.value !== undefined);
|
||||
const connectable = computed(() => collapsible.value && attrs.value["connectable"]);
|
||||
const connectable = computed(() => collapsible.value && Boolean(attrs.value["connectable"]));
|
||||
|
||||
// Determines to wether expand or collapse the input
|
||||
{
|
||||
@@ -118,7 +90,7 @@ const connectable = computed(() => collapsible.value && attrs.value["connectable
|
||||
}
|
||||
|
||||
/** Submits a changed value. */
|
||||
function setValue(value) {
|
||||
function setValue(value: FormParameterValue) {
|
||||
emit("input", value, props.id);
|
||||
emit("change", props.refreshOnChange);
|
||||
}
|
||||
@@ -154,7 +126,7 @@ const showField = computed(() => !collapsed.value && !props.disabled);
|
||||
const previewText = computed(() => attrs.value["text_value"]);
|
||||
const helpText = computed(() => {
|
||||
const helpArgument = attrs.value["argument"];
|
||||
if (helpArgument && !props.help.includes(`(${helpArgument})`)) {
|
||||
if (helpArgument && !props.help?.includes(`(${helpArgument})`)) {
|
||||
return `${props.help} (${helpArgument})`;
|
||||
} else {
|
||||
return props.help;
|
||||
@@ -171,7 +143,9 @@ const currentValue = computed({
|
||||
});
|
||||
|
||||
const isHiddenType = computed(
|
||||
() => ["hidden", "hidden_data", "baseurl"].includes(props.type) || (props.attributes && props.attributes.titleonly)
|
||||
() =>
|
||||
["hidden", "hidden_data", "baseurl"].includes(props.type ?? "") ||
|
||||
(props.attributes && props.attributes.titleonly)
|
||||
);
|
||||
|
||||
const collapseText = computed(() => (collapsed.value ? props.collapsedEnableText : props.collapsedDisableText));
|
||||
@@ -182,7 +156,7 @@ const isEmpty = computed(() => {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (["text", "integer", "float", "password"].includes(props.type) && currentValue.value === "") {
|
||||
if (["text", "integer", "float", "password"].includes(props.type ?? "") && currentValue.value === "") {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -194,14 +168,6 @@ const isRequiredType = computed(() => props.type !== "boolean");
|
||||
const isOptional = computed(() => !isRequired.value && attrs.value["optional"] !== undefined);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
import { faExclamation, faTimes, faArrowsAltH } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCaretSquareDown, faCaretSquareUp } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
library.add(faExclamation, faTimes, faArrowsAltH, faCaretSquareDown, faCaretSquareUp);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-show="!isHidden"
|
||||
@@ -258,7 +224,7 @@ library.add(faExclamation, faTimes, faArrowsAltH, faCaretSquareDown, faCaretSqua
|
||||
v-model="currentValue"
|
||||
:max="attrs.max"
|
||||
:min="attrs.min"
|
||||
:type="type"
|
||||
:type="props.type ?? 'float'"
|
||||
:workflow-building-mode="workflowBuildingMode" />
|
||||
<FormSelection
|
||||
v-else-if="props.type == 'select' && attrs.display == 'radio'"
|
||||
@@ -277,7 +243,7 @@ library.add(faExclamation, faTimes, faArrowsAltH, faCaretSquareDown, faCaretSqua
|
||||
:id="props.id"
|
||||
v-model="currentValue"
|
||||
:data-label="props.title"
|
||||
:type="props.type"
|
||||
:type="props.type ?? 'text'"
|
||||
:attributes="attrs" />
|
||||
<FormInput v-else :id="props.id" v-model="currentValue" :area="attrs['area']" />
|
||||
</div>
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// TODO: stricter types
|
||||
export type FormParameterValue = any;
|
||||
export type FormParameterAttributes = {
|
||||
[attribute: string]: any;
|
||||
};
|
||||
|
||||
export type FormParameterTypes =
|
||||
| "boolean"
|
||||
| "hidden"
|
||||
| "hidden_data"
|
||||
| "baseurl"
|
||||
| "integer"
|
||||
| "float"
|
||||
| "radio"
|
||||
| "color"
|
||||
| "directory_uri"
|
||||
| "text"
|
||||
| "password"
|
||||
| "select"
|
||||
| "data_column"
|
||||
| "genomebuild"
|
||||
| "data"
|
||||
| "data_collection"
|
||||
| "drill_down"
|
||||
| "group_tag"
|
||||
| "library_data"
|
||||
| "ftpfile"
|
||||
| "upload"
|
||||
| "rules"
|
||||
| "data_dialog";
|
||||
@@ -1,51 +0,0 @@
|
||||
import { ref } from "vue";
|
||||
import axios from "axios";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
|
||||
/**
|
||||
* Fetches a detailed array of datatypes available on this galaxy instance.
|
||||
* Does not cache the result or use a store.
|
||||
*/
|
||||
export function useDetailedDatatypes() {
|
||||
const datatypesLoading = ref(true);
|
||||
const datatypes = ref([]);
|
||||
|
||||
async function getDatatypes() {
|
||||
try {
|
||||
const datatypesPromise = axios.get(`${getAppRoot()}api/datatypes?extension_only=false`);
|
||||
const datatypeEDAMFormatsPromise = axios.get(`${getAppRoot()}api/datatypes/edam_formats/detailed`);
|
||||
const datatypeEDAMDataPromise = axios.get(`${getAppRoot()}api/datatypes/edam_data/detailed`);
|
||||
|
||||
const [baseTypes, datatypeEDAMFormats, datatypeEDAMData] = await Promise.all([
|
||||
datatypesPromise,
|
||||
datatypeEDAMFormatsPromise,
|
||||
datatypeEDAMDataPromise,
|
||||
]);
|
||||
|
||||
datatypes.value = baseTypes.data.map((type, i) => {
|
||||
const typeEDAMFormat = datatypeEDAMFormats.data[type.extension] ?? null;
|
||||
const typeEDAMData = datatypeEDAMData.data[type.extension] ?? null;
|
||||
|
||||
return {
|
||||
extension: type.extension,
|
||||
description: type.description,
|
||||
descriptionUrl: type.description_url,
|
||||
edamFormat: typeEDAMFormat.prefix_IRI,
|
||||
edamFormatLabel: typeEDAMFormat.label,
|
||||
edamFormatDefinition: typeEDAMFormat.definition,
|
||||
edamData: typeEDAMData.prefix_IRI,
|
||||
edamDataLabel: typeEDAMData.label,
|
||||
edamDataDefinition: typeEDAMData.definition,
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("unable to fetch available datatypes\n", e);
|
||||
} finally {
|
||||
datatypesLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
getDatatypes();
|
||||
|
||||
return { datatypes, datatypesLoading };
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { ref } from "vue";
|
||||
import { fetcher } from "schema";
|
||||
|
||||
import type { Ref } from "vue";
|
||||
|
||||
const datatypesFetcher = fetcher.path("/api/datatypes").method("get").create();
|
||||
const edamFormatsFetcher = fetcher.path("/api/datatypes/edam_formats/detailed").method("get").create();
|
||||
const edamDataFetcher = fetcher.path("/api/datatypes/edam_data/detailed").method("get").create();
|
||||
|
||||
export interface DetailedDatatypes {
|
||||
extension: string;
|
||||
description?: string;
|
||||
descriptionUrl?: string;
|
||||
edamFormat?: string;
|
||||
edamFormatLabel?: string;
|
||||
edamFormatDefinition?: string;
|
||||
edamData?: string;
|
||||
edamDataLabel?: string;
|
||||
edamDataDefinition?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a detailed array of datatypes available on this galaxy instance.
|
||||
* Does not cache the result or use a store.
|
||||
*/
|
||||
export function useDetailedDatatypes() {
|
||||
const datatypesLoading = ref(true);
|
||||
const datatypes: Ref<DetailedDatatypes[]> = ref([]);
|
||||
|
||||
async function getDatatypes() {
|
||||
try {
|
||||
const datatypesPromise = datatypesFetcher({ extension_only: true });
|
||||
const datatypeEDAMFormatsPromise = edamFormatsFetcher({});
|
||||
const datatypeEDAMDataPromise = edamDataFetcher({});
|
||||
|
||||
const [baseTypes, datatypeEDAMFormats, datatypeEDAMData] = await Promise.all([
|
||||
datatypesPromise,
|
||||
datatypeEDAMFormatsPromise,
|
||||
datatypeEDAMDataPromise,
|
||||
]);
|
||||
|
||||
type BaseTypes = Exclude<typeof baseTypes.data, string[]>;
|
||||
|
||||
datatypes.value = (baseTypes.data as BaseTypes).map((type) => {
|
||||
const typeEDAMFormat = datatypeEDAMFormats.data[type.extension] ?? null;
|
||||
const typeEDAMData = datatypeEDAMData.data[type.extension] ?? null;
|
||||
|
||||
return {
|
||||
extension: type.extension,
|
||||
description: type.description,
|
||||
descriptionUrl: type.description_url,
|
||||
edamFormat: typeEDAMFormat?.prefix_IRI,
|
||||
edamFormatLabel: typeEDAMFormat?.label,
|
||||
edamFormatDefinition: typeEDAMFormat?.definition,
|
||||
edamData: typeEDAMData?.prefix_IRI,
|
||||
edamDataLabel: typeEDAMData?.label,
|
||||
edamDataDefinition: typeEDAMData?.definition,
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("unable to fetch available datatypes\n", e);
|
||||
} finally {
|
||||
datatypesLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
getDatatypes();
|
||||
|
||||
return { datatypes, datatypesLoading };
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { ref } from "vue";
|
||||
|
||||
let toastRef = ref(null);
|
||||
|
||||
export const setToastComponentRef = (newRef) => {
|
||||
// eslint-disable-next-line vue/no-ref-as-operand
|
||||
toastRef = newRef;
|
||||
};
|
||||
|
||||
/**
|
||||
* Direct export to simplify usage in Options Api component.
|
||||
* Use 'useToast' for the Composition Api instead.
|
||||
*/
|
||||
export const Toast = {
|
||||
success(message, title = "Success") {
|
||||
toastRef.value.showToast(message, title, "success");
|
||||
},
|
||||
|
||||
info(message, title = "Info") {
|
||||
toastRef.value.showToast(message, title, "info");
|
||||
},
|
||||
|
||||
warning(message, title = "Warning") {
|
||||
toastRef.value.showToast(message, title, "warning");
|
||||
},
|
||||
|
||||
error(message, title = "Error") {
|
||||
toastRef.value.showToast(message, title, "error");
|
||||
},
|
||||
};
|
||||
|
||||
export function useToast() {
|
||||
return { ...Toast };
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ref, type Ref } from "vue";
|
||||
|
||||
import type Vue from "vue";
|
||||
import type ToastComponentFile from "components/Toast";
|
||||
|
||||
export type ToastComponent = Vue & typeof ToastComponentFile.methods;
|
||||
|
||||
let toastRef: Ref<ToastComponent | null> = ref(null);
|
||||
|
||||
export const setToastComponentRef = (newRef: typeof toastRef) => {
|
||||
// eslint-disable-next-line vue/no-ref-as-operand
|
||||
toastRef = newRef;
|
||||
};
|
||||
|
||||
/**
|
||||
* Direct export to simplify usage in Options Api component.
|
||||
* Use 'useToast' for the Composition Api instead.
|
||||
*/
|
||||
export const Toast = {
|
||||
success(message: string, title = "Success") {
|
||||
toastRef.value?.showToast(message, title, "success");
|
||||
},
|
||||
|
||||
info(message: string, title = "Info") {
|
||||
toastRef.value?.showToast(message, title, "info");
|
||||
},
|
||||
|
||||
warning(message: string, title = "Warning") {
|
||||
toastRef.value?.showToast(message, title, "warning");
|
||||
},
|
||||
|
||||
error(message: string, title = "Error") {
|
||||
toastRef.value?.showToast(message, title, "error");
|
||||
},
|
||||
};
|
||||
|
||||
export function useToast() {
|
||||
return { ...Toast };
|
||||
}
|
||||
Reference in New Issue
Block a user