diff --git a/src/components/parameter-schema/form-mode/ParameterFileInput.vue b/src/components/parameter-schema/form-mode/ParameterFileInput.vue index 260ff12d0926ade0a1e43c7c802b8319522a2b0e..26f9508487b060e0b6f06abedd6ce81ebea4e8fa 100644 --- a/src/components/parameter-schema/form-mode/ParameterFileInput.vue +++ b/src/components/parameter-schema/form-mode/ParameterFileInput.vue @@ -5,7 +5,7 @@ import { useBucketStore } from "@/stores/buckets"; import type { SizeModifierType } from "@/types/PropTypes"; const model = defineModel<string | undefined>({ required: true }); -const s3Regex = /s3:\/\/(\S*)\/(\S*)/g; +const s3Regex = /s3:\/\/([^\s/]*)(\/\S*)?/g; const props = defineProps({ parameter: { @@ -23,8 +23,13 @@ const props = defineProps({ type: String as PropType<SizeModifierType>, }, border: Boolean, + allowRaw: Boolean, }); +const emit = defineEmits<{ + (e: "switch-to-raw"): void; +}>(); + const s3ObjectRepository = useS3ObjectStore(); const bucketRepository = useBucketStore(); const randomIDSuffix = Math.random().toString(16).substring(2, 8); @@ -45,7 +50,7 @@ const inputDynamicClass = computed<string[]>(() => { if (props.sizeModifier) { cssClasses.push(`form-control-${props.sizeModifier}`); } - if (!helpTextPresent.value) { + if (!helpTextPresent.value && !props.allowRaw) { cssClasses.push("rounded-end"); } return cssClasses; @@ -61,7 +66,7 @@ watch(model, (newVal, oldVal) => { }); function parseModel(val?: string) { - if (val == undefined) { + if (val == undefined || val.length === 0) { s3Path.bucket = ""; s3Path.key = undefined; return; @@ -69,12 +74,14 @@ function parseModel(val?: string) { const match = s3Regex.exec(val ?? ""); if (match) { s3Path.bucket = match[1]; - s3Path.key = match[2]; + s3Path.key = match[2]?.slice(1); if (bucketRepository.bucketMapping[s3Path.bucket] == undefined) { - console.log("Missing bucket"); + // Missing bucket + emit("switch-to-raw"); } } else { - console.log("Not S3 Path"); + // Not S3 Path + emit("switch-to-raw"); } } @@ -186,6 +193,14 @@ onMounted(() => { <datalist :id="'keys-options-' + randomIDSuffix"> <option v-for="obj in keyDataList" :value="obj" :key="obj" /> </datalist> + <button + v-if="allowRaw" + type="button" + class="btn btn-outline-secondary" + @click="emit('switch-to-raw')" + > + Advanced + </button> </template> <style scoped></style> diff --git a/src/components/parameter-schema/form-mode/ParameterGroupForm.vue b/src/components/parameter-schema/form-mode/ParameterGroupForm.vue index aba2788b3920d70e2b92da8e4b7a64c92332c209..346aceda55bf78290be4c2c591ff5af44930490c 100644 --- a/src/components/parameter-schema/form-mode/ParameterGroupForm.vue +++ b/src/components/parameter-schema/form-mode/ParameterGroupForm.vue @@ -108,6 +108,7 @@ function parameterId(parameterName: string): string { :required="parameterRequired(parameterGroup, parameterName)" border :resource-parameter="resourceParameters?.includes(parameterName)" + :allow-raw="showOptional" /> <span class="input-group-text cursor-pointer px-2 border border-secondary" diff --git a/src/components/parameter-schema/form-mode/ParameterInput.vue b/src/components/parameter-schema/form-mode/ParameterInput.vue index ca67de093b6fc7906b53971b925458583e2b672b..0f6d1105369575909d9e7ca407b9663627b181de 100644 --- a/src/components/parameter-schema/form-mode/ParameterInput.vue +++ b/src/components/parameter-schema/form-mode/ParameterInput.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import { computed } from "vue"; +import { computed, ref } from "vue"; import ParameterResourceInput from "@/components/parameter-schema/form-mode/ParameterResourceInput.vue"; import ParameterNumberInput from "@/components/parameter-schema/form-mode/ParameterNumberInput.vue"; import ParameterBooleanInput from "@/components/parameter-schema/form-mode/ParameterBooleanInput.vue"; @@ -15,15 +15,17 @@ const model = defineModel< required: true, }); +const rawInput = ref<boolean>(false); + const props = defineProps<{ // eslint-disable-next-line @typescript-eslint/no-explicit-any parameter: Record<string, any>; required?: boolean; resourceParameter?: boolean; - advanced?: boolean; rawModel?: boolean; sizeModifier?: SizeModifierType; border?: boolean; + allowRaw?: boolean; }>(); const parameterType = computed<string>( @@ -56,22 +58,25 @@ const parameterType = computed<string>( /> <template v-else> <parameter-resource-input - v-if="resourceParameter && !advanced" + v-if="resourceParameter && !rawInput" :parameter="parameter" :required="required" v-model="model as ResourcePath_Input" :rawModel="rawModel" :size-modifier="sizeModifier" :border="border" + @switch-to-raw="rawInput = true" + :allow-raw="allowRaw" /> <parameter-file-input - v-else-if="parameter['format'] && !advanced" - class="border border-secondary" + v-else-if="parameter['format'] && !rawInput" :required="required" :parameter="parameter" v-model="model as string" :size-modifier="sizeModifier" :border="border" + @switch-to-raw="rawInput = true" + :allow-raw="allowRaw" /> <parameter-string-input v-else @@ -80,6 +85,9 @@ const parameterType = computed<string>( v-model="model as string" :size-modifier="sizeModifier" :border="border" + :resource-parameter="resourceParameter" + :allow-switch="allowRaw" + @disable-raw="rawInput = false" /> </template> </template> diff --git a/src/components/parameter-schema/form-mode/ParameterResourceInput.vue b/src/components/parameter-schema/form-mode/ParameterResourceInput.vue index 8e4a5ca288bc179d93f8f321632b0c65c0b55064..8166de0d2a0b391add980d9f820cac4c5f2a4a46 100644 --- a/src/components/parameter-schema/form-mode/ParameterResourceInput.vue +++ b/src/components/parameter-schema/form-mode/ParameterResourceInput.vue @@ -18,6 +18,11 @@ const props = defineProps<{ rawModel?: boolean; sizeModifier?: SizeModifierType; border?: boolean; + allowRaw?: boolean; +}>(); + +const emit = defineEmits<{ + (e: "switch-to-raw"): void; }>(); const resourceRepository = useResourceStore(); @@ -29,6 +34,8 @@ const resource = reactive<ResourcePath_Input>({ suffix: undefined, }); +const helpTextPresent = computed<boolean>(() => props.parameter["help_text"]); + const baseDynamicClass = computed<string[]>(() => props.border ? ["border", "border-secondary"] : [], ); @@ -45,6 +52,9 @@ const inputDynamicClass = computed<string[]>(() => { if (props.sizeModifier) { cssClasses.push(`form-control-${props.sizeModifier}`); } + if (!helpTextPresent.value && !props.allowRaw) { + cssClasses.push("rounded-end"); + } return cssClasses; }); @@ -67,7 +77,7 @@ watch(model, (newVal, oldVal) => { }); function parseModel(val?: string | ResourcePath_Input) { - if (val == undefined) { + if (val == undefined || (typeof val === "string" && val.length === 0)) { Object.assign(resource, { resource_id: "", resource_version_id: "", @@ -76,9 +86,13 @@ function parseModel(val?: string | ResourcePath_Input) { } else if (typeof val === "string") { const match = resourceRegex.exec(val); if (match) { - resource.resource_id = hexToUUID(match[1]); - resource.suffix = match[3]; - resource.resource_version_id = + const tempResource: ResourcePath_Input = { + resource_id: "", + resource_version_id: "", + }; + tempResource.resource_id = hexToUUID(match[1]); + tempResource.suffix = match[3]; + tempResource.resource_version_id = match[2].length === 32 ? hexToUUID(match[2]) : resourceRepository.getLatestVersion(resource.resource_id); @@ -87,12 +101,26 @@ function parseModel(val?: string | ResourcePath_Input) { resourceRepository.versionMapping[resource.resource_version_id] == undefined ) { - console.log("Missing resource"); + // Missing resource + emit("switch-to-raw"); + return; } + Object.assign(resource, tempResource); } else { - console.log("Not resource Path"); + // Not resource path + emit("switch-to-raw"); } } else { + if ( + (val.resource_id.length > 0 && + resourceRepository.resourceMapping[val.resource_id] == undefined) || + (val.resource_version_id.length > 0 && + resourceRepository.versionMapping[val.resource_version_id] == undefined) + ) { + // Missing resource + emit("switch-to-raw"); + return; + } Object.assign(resource, JSON.parse(JSON.stringify(val))); } } @@ -178,7 +206,7 @@ onMounted(() => { </select> <input type="text" - class="form-control rounded-end" + class="form-control" :class="inputDynamicClass" placeholder="/optional/path/in/resource/..." minlength="2" @@ -196,6 +224,14 @@ onMounted(() => { :key="file" /> </datalist> + <button + v-if="allowRaw" + type="button" + class="btn btn-outline-secondary" + @click="emit('switch-to-raw')" + > + Advanced + </button> </template> <style scoped></style> diff --git a/src/components/parameter-schema/form-mode/ParameterStringInput.vue b/src/components/parameter-schema/form-mode/ParameterStringInput.vue index 85e6eee21e2c23f2c53a6f58bbb5b2cb855e520d..3871923d73b387bdda31ab5d26dd0fffaa50a57a 100644 --- a/src/components/parameter-schema/form-mode/ParameterStringInput.vue +++ b/src/components/parameter-schema/form-mode/ParameterStringInput.vue @@ -8,7 +8,7 @@ const props = defineProps({ type: Object, required: true, validator(value: Record<string, never>) { - return "string" === value["type"] && value["enum"]; + return "string" === value["type"]; }, }, required: Boolean, @@ -19,6 +19,18 @@ const props = defineProps({ type: String as PropType<SizeModifierType>, }, border: Boolean, + resourceParameter: Boolean, + allowSwitch: Boolean, +}); + +const emit = defineEmits<{ + (e: "disable-raw"): void; +}>(); + +const fileOrResource = computed<boolean>(() => { + return ( + (props.resourceParameter || props.parameter["format"]) && props.allowSwitch + ); }); const dynamicCssClass = computed<string[]>(() => { @@ -26,7 +38,7 @@ const dynamicCssClass = computed<string[]>(() => { if (props.sizeModifier) { cssClasses.push(`form-control-${props.sizeModifier}`); } - if (!helpTextPresent.value) { + if (!helpTextPresent.value && !fileOrResource.value) { cssClasses.push("rounded-end"); } if (props.border) { @@ -51,6 +63,14 @@ const helpTextPresent = computed<boolean>(() => props.parameter["help_text"]); :aria-describedby="props.helpId" :pattern="pattern" /> + <button + v-if="fileOrResource" + type="button" + class="btn btn-secondary" + @click="emit('disable-raw')" + > + Advanced + </button> </template> <style scoped></style> diff --git a/src/components/workflows/WorkflowWithVersionsCard.vue b/src/components/workflows/WorkflowWithVersionsCard.vue index 1e8e19e97ca32699d60c8bafb8c678db477f525b..d69290f4af2202deca6798ce34d38e7ccf2932c6 100644 --- a/src/components/workflows/WorkflowWithVersionsCard.vue +++ b/src/components/workflows/WorkflowWithVersionsCard.vue @@ -128,7 +128,7 @@ onMounted(() => { <div class="btn-group"> <button type="button" - class="btn btn-success" + class="btn btn-outline-success" :class="{ disabled: props.loading }" @click="emit('workflow-update-click', props.workflow)" data-bs-toggle="modal" @@ -138,8 +138,7 @@ onMounted(() => { </button> <button type="button" - class="btn btn-success dropdown-toggle dropdown-toggle-split" - style="filter: brightness(85%)" + class="btn btn-outline-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false" > diff --git a/src/views/workflows/StartWorkflowView.vue b/src/views/workflows/StartWorkflowView.vue index e6fde26d083723352bb271517dadc2c2b077585f..99f1f6d861f1087766087be749ca716bf475185b 100644 --- a/src/views/workflows/StartWorkflowView.vue +++ b/src/views/workflows/StartWorkflowView.vue @@ -128,7 +128,6 @@ onMounted(() => { </template> </bootstrap-toast> <parameter-schema-form-component - :workflow-version-id="versionId" :schema="versionState.parameterSchema" :loading="versionState.loading" allow-notes