Skip to content
Snippets Groups Projects
Verified Commit 6dce4e95 authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Add page and element to add instance default parameters

parent 75415fc1
No related branches found
No related tags found
1 merge request!102Resolve "Add UI for parameter translation layer"
......@@ -6553,9 +6553,9 @@
}
},
"node_modules/vite": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz",
"integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==",
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
"integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
......
......@@ -325,6 +325,24 @@ onMounted(() => {
>Update icon</a
>
</li>
<li>
<router-link
class="dropdown-item"
:to="{
name: 'workflow-parameter-translation',
params: {
workflowId: props.workflow.workflow_id,
versionId: version.workflow_version_id,
},
}"
>
<template v-if="version.parameter_extension"
>Update</template
>
<template v-else>Add</template>
Parameter Translation
</router-link>
</li>
</ul>
</td>
</tr>
......
......@@ -97,4 +97,14 @@ export const workflowRoutes: RouteRecordRaw[] = [
},
],
},
{
path: "workflows/:workflowId/version/:versionId/parameters",
name: "workflow-parameter-translation",
component: () =>
import("../views/workflows/CreateParameterTranslationView.vue"),
props: (route) => ({
versionId: route.params.versionId,
workflowId: route.params.workflowId,
}),
},
];
......@@ -63,6 +63,15 @@ export const useWorkflowStore = defineStore({
}
return mapping;
},
ownVersionMapping(): Record<string, WorkflowVersion> {
const mapping: Record<string, WorkflowVersion> = {};
for (const workflow of this.ownWorkflows) {
for (const version of workflow.versions) {
mapping[version.workflow_version_id] = version;
}
}
return mapping;
},
getArbitraryWorkflow(): (wid: string) => Promise<WorkflowIn | undefined> {
return (wid: string) => get(wid);
},
......@@ -71,6 +80,15 @@ export const useWorkflowStore = defineStore({
__addNameToMapping(key: string, value: string) {
useNameStore().addNameToMapping(key, value);
},
fetchWorkflowVersion(wid: string, vid: string): Promise<WorkflowVersion> {
return WorkflowVersionService.workflowVersionGetWorkflowVersion(
vid,
wid,
).then((version) => {
this.__addNameToMapping(version.workflow_version_id, version.version);
return version;
});
},
fetchWorkflows(onFinally?: () => void): Promise<WorkflowOut[]> {
if (Object.keys(this.workflowMapping).length > 0) {
onFinally?.();
......
<script setup lang="ts">
import { useNameStore } from "@/stores/names";
import { useWorkflowStore } from "@/stores/workflows";
import { computed, onMounted, reactive, watch } from "vue";
import {
DocumentationEnum,
type ParameterExtension_Input,
} from "@/client/workflow";
const props = defineProps<{
versionId: string;
workflowId: string;
}>();
const parameterState = reactive<{
extension: ParameterExtension_Input;
resourceParameters: Set<string>;
}>({
extension: {},
resourceParameters: new Set(),
});
const parameterPools = reactive<{
defaults: string[];
mapping: string[];
}>({
defaults: [],
mapping: [],
});
const nameRepository = useNameStore();
const workflowRepository = useWorkflowStore();
watch(
() => workflowRepository.documentationFiles[props.versionId ?? ""],
(newVal, old) => {
if (newVal != old && newVal?.parameter_schema != undefined) {
updateParameterPools(newVal);
}
},
{
deep: true,
},
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function updateParameterPools(newVal?: Record<DocumentationEnum, any>) {
if (newVal?.parameter_schema) {
const parameters = extractParameterList(newVal.parameter_schema);
parameterPools.defaults = parameters.slice();
parameterPools.mapping = parameters.slice();
}
if (
workflowRepository.ownVersionMapping[props.versionId]?.parameter_extension
) {
parameterPools.defaults = parameterPools.defaults.filter(
(param) =>
workflowRepository.ownVersionMapping[props.versionId]
?.parameter_extension?.defaults?.[param] == undefined,
);
parameterPools.mapping = parameterPools.mapping.filter(
(param) =>
workflowRepository.ownVersionMapping[props.versionId]
?.parameter_extension?.defaults?.[param] == undefined,
);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function extractParameterList(schema: Record<string, any>): string[] {
const groupedParameters = Object.keys(schema["definitions"] ?? {}).reduce(
(acc: string[], val) => [
...acc,
...Object.keys(schema["definitions"][val]["properties"]),
],
[],
);
const singleParameters = Object.keys(schema["properties"] ?? {});
return [...groupedParameters, ...singleParameters];
}
function getParameterType(param: string): string | undefined {
return parameterSchema.value[param]?.["type"];
}
function addDefaultParameter(param: string, index: number) {
if (parameterState.extension.defaults == undefined) {
parameterState.extension.defaults = {};
}
parameterPools.defaults.splice(index, 1);
switch (getParameterType(param)) {
case "integer": {
parameterState.extension.defaults[param] = 0;
break;
}
case "number": {
parameterState.extension.defaults[param] = 0;
break;
}
case "boolean": {
parameterState.extension.defaults[param] = true;
break;
}
case "string": {
parameterState.extension.defaults[param] =
parameterSchema.value[param]?.["enum"]?.[0] ?? "";
break;
}
default: {
parameterState.extension.defaults[param] = "";
break;
}
}
}
function deleteDefaultParameter(param: string) {
delete parameterState.extension.defaults?.[param];
parameterPools.defaults.push(param);
if (Object.keys(parameterState.extension.defaults ?? {}).length === 0) {
parameterState.extension.defaults = undefined;
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parameterSchema = computed<Record<string, Record<string, any>>>(() => {
const schema =
workflowRepository.documentationFiles[props.versionId ?? ""]
?.parameter_schema;
const a = schema?.["properties"] ?? {};
for (const group in schema?.["definitions"] ?? {}) {
for (const param in schema?.["definitions"]?.[group]?.["properties"] ??
{}) {
a[param] = schema["definitions"][group]["properties"][param];
}
}
return a;
});
onMounted(() => {
workflowRepository.fetchWorkflow(props.workflowId, true, () => {
parameterState.extension =
workflowRepository.ownVersionMapping[props.versionId]
?.parameter_extension ?? {};
workflowRepository
.fetchWorkflowDocumentation(
props.workflowId,
props.versionId,
DocumentationEnum.PARAMETER_SCHEMA,
workflowRepository.ownVersionMapping[props.versionId]?.modes?.[0],
)
.finally(() => {
updateParameterPools(
workflowRepository.documentationFiles[props.versionId],
);
});
});
});
</script>
<template>
<div class="row border-bottom mb-4">
<h2 class="mb-2">
Add parameter metadata to
{{ nameRepository.getName(props.workflowId) }}@{{
nameRepository.getName(props.versionId)
}}
</h2>
</div>
<div
class="d-flex flex-wrap overflow-y-auto p-1 border rounded border-dashed mb-2"
style="max-height: 30vh"
v-if="parameterPools.defaults.length > 0"
>
<b class="ms-1 w-100">Workflow parameters:</b>
<div
class="w-fit border px-2 rounded cursor-pointer m-1 parameter-container"
v-for="(param, index) in parameterPools.defaults"
:key="param"
@click="addDefaultParameter(param, index)"
>
{{ param }}
</div>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col"><b>Parameter</b></th>
<th scope="col"><b>Value</b></th>
</tr>
</thead>
<tbody v-if="parameterState.extension.defaults">
<tr
v-for="param in Object.keys(parameterState.extension.defaults)"
:key="param"
>
<td style="width: 10%">{{ param }}</td>
<td class="d-flex justify-content-between align-items-center">
<input
v-if="
getParameterType(param) === 'number' ||
getParameterType(param) === 'integer'
"
type="number"
class="form-control form-control-sm flex-grow"
v-model="parameterState.extension.defaults[param]"
:step="getParameterType(param) === 'integer' ? 1 : 0.0001"
:min="parameterSchema[param]['minimum']"
:max="parameterSchema[param]['maximum']"
/>
<div
v-else-if="getParameterType(param) === 'boolean'"
class="flex-grow"
>
<div class="form-check form-check-inline">
<label
class="form-check-label"
:for="'trueOption' + param.replace(/\./g, '')"
>True</label
>
<input
class="form-check-input"
type="radio"
:name="'inlineRadioOptions' + param.replace(/\./g, '')"
:id="'trueOption' + param.replace(/\./g, '')"
:value="true"
v-model="parameterState.extension.defaults[param]"
/>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
:name="'inlineRadioOptions' + param.replace(/\./g, '')"
:id="'falseOption' + param.replace(/\./g, '')"
:value="false"
v-model="parameterState.extension.defaults[param]"
/>
<label
class="form-check-label"
:for="'falseOption' + param.replace(/\./g, '')"
>False</label
>
</div>
</div>
<select
v-else-if="parameterSchema[param]?.['enum']"
class="form-select form-select-sm flex-grow"
v-model="parameterState.extension.defaults[param]"
>
<option
v-for="option in parameterSchema[param]?.['enum']"
:key="option"
:value="option"
>
{{ option }}
</option>
</select>
<div v-else>
<input
type="text"
class="form-control form-control-sm flex-grow"
v-model="parameterState.extension.defaults[param]"
:pattern="parameterSchema[param]?.['pattern']"
/>
</div>
<button
type="button"
class="btn btn-outline-danger btn-sm ms-2"
@click="deleteDefaultParameter(param)"
>
Remove
</button>
</td>
</tr>
</tbody>
</table>
<pre><code>{{
parameterState.extension
}}</code></pre>
<pre><code>{{ parameterPools }}</code></pre>
</template>
<style scoped>
.parameter-container:hover {
background: var(--bs-secondary-bg-subtle);
}
</style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment