Skip to content
Snippets Groups Projects
ParameterGroupForm.vue 6.86 KiB
<script setup lang="ts">
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import { computed, type PropType } from "vue";
import ParameterNumberInput from "@/components/parameter-schema/form-mode/ParameterNumberInput.vue";
import MarkdownRenderer from "@/components/MarkdownRenderer.vue";
import ParameterBooleanInput from "@/components/parameter-schema/form-mode/ParameterBooleanInput.vue";
import ParameterEnumInput from "@/components/parameter-schema/form-mode/ParameterEnumInput.vue";
import ParameterStringInput from "@/components/parameter-schema/form-mode/ParameterStringInput.vue";
import type { WorkflowParameters } from "@/types/WorkflowParameters";

const model = defineModel<WorkflowParameters>({ required: true });

const props = defineProps({
  parameterGroup: {
    type: Object,
    required: true,
    validator(value: Record<string, never>) {
      return "object" === value["type"];
    },
  },
  parameterGroupName: {
    type: String,
    required: true,
  },
  showHidden: {
    type: Boolean,
    default: false,
  },
  showOptional: {
    type: Boolean,
    default: false,
  },
  resourceParameters: {
    type: Array as PropType<string[]>,
    required: false,
  },
});
const title = computed<string>(() => props.parameterGroup["title"]);
const icon = computed<string>(() => props.parameterGroup["fa_icon"]);
const description = computed<string>(() => props.parameterGroup["description"]);
const groupHidden = computed<boolean>(() =>
  Object.keys(parameters.value).reduce(
    (acc: boolean, val: string) => acc && parameters.value[val]["hidden"],
    true,
  ),
);
const groupRequired = computed<boolean>(
  () => (props.parameterGroup["required"] ?? []).length > 0,
);
const parameters = computed<Record<string, never>>(
  () => props.parameterGroup["properties"],
);

function parameterRequired(
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  parameterGroup: Record<string, any>,
  parameterName: string,
): boolean {
  return (
    parameterGroup["required"]?.includes(parameterName) || // parameter is required
    parameterGroup["dependentRequired"]?.[parameterName] // parameter is required when another parameter is set
      ?.map((param: string) => model.value[param])
      ?.reduce((acc: boolean, val: string) => acc || val, false)
  );
}
</script>

<template>
  <div
    class="card mb-3"
    :hidden="(!showHidden && groupHidden) || (!showOptional && !groupRequired)"
  >
    <h3 class="card-header" :id="props.parameterGroupName">
      <font-awesome-icon :icon="icon" class="me-2" v-if="icon" />
      {{ title }}
    </h3>
    <div class="card-body">
      <h5 class="card-title" v-if="description">{{ description }}</h5>
      <template
        v-for="(parameter, parameterName) in parameters"
        :key="parameterName"
      >
        <div
          :hidden="
            (!showHidden && parameter['hidden']) ||
            (!showOptional && !parameterRequired(parameterGroup, parameterName))
          "
        >
          <code
            class="p-2 rounded-top border-bottom-0 border bg-secondary-subtle border-secondary"
            >--{{ parameter["name"] ?? parameterName }}</code
          ><span
            v-if="parameterRequired(parameterGroup, parameterName)"
            class="rounded p-1 bg-warning text-light ms-2"
            >required</span
          >
          <div class="input-group">
            <span
              class="input-group-text border-end-0 border border-secondary"
              v-if="parameter['fa_icon']"
            >
              <font-awesome-icon :icon="parameter['fa_icon']" />
            </span>
            <template
              v-if="
                parameter['type'] === 'number' ||
                parameter['type'] === 'integer'
              "
            >
              <!-- @vue-ignore -->
              <parameter-number-input
                :parameter-name="parameterName"
                :parameter="parameter"
                :help-id="parameterName + '-help'"
                :required="parameterRequired(parameterGroup, parameterName)"
                v-model="model[parameterName]"
              />
            </template>
            <template v-else-if="parameter['type'] === 'boolean'">
              <!-- @vue-ignore -->
              <parameter-boolean-input
                :parameter-name="parameterName"
                :parameter="parameter"
                :help-id="parameterName + '-help'"
                v-model="model[parameterName]"
              />
            </template>
            <template v-else-if="parameter['type'] === 'string'">
              <!-- @vue-ignore -->
              <template v-if="parameter['enum']">
                <!-- @vue-ignore -->
                <parameter-enum-input
                  :parameter-name="parameterName"
                  :parameter="parameter"
                  :required="parameterRequired(parameterGroup, parameterName)"
                  v-model="model[parameterName]"
                />
              </template>
              <!-- @vue-ignore -->
              <parameter-string-input
                v-else
                :parameter-name="parameterName"
                :parameter="parameter"
                :required="parameterRequired(parameterGroup, parameterName)"
                v-model="model[parameterName]"
                :remove-advanced="!showOptional"
                :clowm-resource="resourceParameters?.includes(parameterName)"
              />
            </template>
            <span
              class="input-group-text cursor-pointer px-2 border border-secondary"
              v-if="parameter['help_text']"
              data-bs-toggle="collapse"
              :data-bs-target="
                '#helpCollapse' + parameterName.replace(/\./g, '')
              "
              aria-expanded="false"
              :aria-controls="'helpCollapse' + parameterName.replace(/\./g, '')"
            >
              <font-awesome-icon
                class="cursor-pointer"
                icon="fa-solid fa-circle-question"
              />
            </span>
          </div>
          <label v-if="parameter['description']">
            <markdown-renderer :markdown="parameter['description']" />
          </label>
          <div
            class="collapse"
            :id="'helpCollapse' + parameterName.replace(/\./g, '')"
            v-if="parameter['help_text']"
          >
            <div class="p-2 pb-0 mx-2 mb-3 flex-shrink-1 border rounded">
              <markdown-renderer
                class="helpTextCode"
                :markdown="parameter['help_text']"
              />
              <p v-if="parameter['pattern']">
                Pattern: <code>{{ parameter["pattern"] }}</code>
              </p>
            </div>
          </div>
        </div>
      </template>
    </div>
  </div>
</template>

<style scoped>
div.card-body {
  backdrop-filter: brightness(1.2);
}

span.cursor-pointer:hover {
  color: var(--bs-info);
  background: var(--bs-light);
}
</style>