252 lines
7.8 KiB
Vue
252 lines
7.8 KiB
Vue
<template>
|
|
<div class="input-wrapper">
|
|
<h2>Input</h2>
|
|
|
|
<div class="form-group-row" :class="{ 'extended': state.selectedFromFunction?.extendedInput }">
|
|
<div class="form-group select-group">
|
|
<label for="functionSelect">Select Function</label>
|
|
<select v-model="state.selectedFromFunction">
|
|
<option v-for="fromFunction of props.fromFunctions" :key="fromFunction.label" :value="fromFunction">{{ fromFunction.label }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group input-group" :class="{ 'extended': state.selectedFromFunction?.extendedInput }">
|
|
<template v-for="(_input, i) of state.selectedFromFunction.inputs" :key="i">
|
|
<label for="field">{{ state.selectedFromFunction.inputs[i] }}</label>
|
|
<div>
|
|
<textarea
|
|
v-if="state.selectedFromFunction?.extendedInput"
|
|
v-model="state.selectedFromFunction.models[i]"
|
|
class="extended-input"
|
|
@input="autoGrow($event.target)"
|
|
></textarea>
|
|
<input
|
|
v-else
|
|
type="text"
|
|
v-model="state.selectedFromFunction.models[i]"
|
|
/>
|
|
<div v-if="state.error" class="text-error">{{ state.error }}</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button type="submit" class="gradient-button" @click="() => setPrimitive(() => state.selectedFromFunction.callback(state.selectedFromFunction.models))">Create Output</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section output-section">
|
|
<h2>Output</h2>
|
|
|
|
<template v-for="(toFunction, i) of toFunctions" :key="i">
|
|
<div>
|
|
<div class="output-box-container">
|
|
<LabelledSection :label="toFunction.label" :content="getPrimitive(() => toFunction.callback(state.primitive))" />
|
|
<CopyButton :content="getPrimitive(() => toFunction.callback(state.primitive))" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-if="state.methods.length && state.primitive">
|
|
<div class="form-group-row" :class="{ 'extended': state.selectedMethod?.extendedInput }">
|
|
<div class="form-group select-group">
|
|
<label for="functionSelect">Method</label>
|
|
<select v-model="state.selectedMethod">
|
|
<option v-for="method of props.methods" :key="method.label" :value="method">{{ method.label }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group input-group" :class="{ 'extended': state.selectedMethod?.extendedInput }">
|
|
<template v-for="(_input, i) of state.selectedMethod.inputs" :key="i">
|
|
<label for="field">{{ state.selectedMethod.inputs[i] }}</label>
|
|
<div>
|
|
<textarea
|
|
v-if="state.selectedMethod?.extendedInput"
|
|
v-model="state.selectedMethod.models[i]"
|
|
class="extended-input"
|
|
@input="autoGrow($event.target)"
|
|
></textarea>
|
|
<input
|
|
v-else
|
|
type="text"
|
|
v-model="state.selectedMethod.models[i]"
|
|
/>
|
|
<div v-if="state.selectedMethod.error" class="text-error">{{ state.selectedMethod.error }}</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button type="submit" class="gradient-button" @click="() => executeMethod(state.selectedMethod.callback(state.primitive, state.selectedMethod.models))">Execute Method</button>
|
|
</div>
|
|
<!-- Result -->
|
|
<div>
|
|
<div class="output-box-container">
|
|
<LabelledSection label="Result" :content="state.selectedMethod.result" />
|
|
<CopyButton :content="state.selectedMethod.result" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup generic="Primitive" lang="ts">
|
|
import { ref } from 'vue';
|
|
import type { Ref } from 'vue';
|
|
|
|
import LabelledSection from './LabelledSection.vue';
|
|
import CopyButton from './CopyButton.vue';
|
|
|
|
export interface FromFunction<Primitive> {
|
|
// The label of the function
|
|
label: string,
|
|
|
|
// Array of inputs that the function takes
|
|
inputs: Array<string>,
|
|
|
|
// Array of models that the input stores its value in
|
|
models: Array<any>,
|
|
|
|
// Function that takes the models and returns the primitive
|
|
callback: (value: Array<any>) => Primitive,
|
|
|
|
// Whether the input is extended onto a new line
|
|
extendedInput?: boolean
|
|
}
|
|
|
|
export interface ToFunction<Primitive> {
|
|
label: string;
|
|
callback: (primitive: Primitive) => string;
|
|
result?: string;
|
|
}
|
|
|
|
export interface Method<Primitive> {
|
|
// The label of the function
|
|
label: string;
|
|
|
|
// Array of inputs that the function takes
|
|
inputs: Array<string>,
|
|
|
|
// Array of models that the input stores its value in
|
|
models: Array<any>,
|
|
|
|
// Result of method execution,
|
|
result?: string;
|
|
|
|
// Error (if one occurred).
|
|
error?: string;
|
|
|
|
// Function that takes the models and returns the primitive
|
|
callback: (primitive: Primitive, value: Array<any>) => string;
|
|
|
|
// Whether the input is extended onto a new line
|
|
extendedInput?: boolean
|
|
}
|
|
|
|
export interface Props<Primitive> {
|
|
fromFunctions: Array<FromFunction<Primitive>>,
|
|
toFunctions: Array<ToFunction<Primitive>>,
|
|
methods?: Array<Method<Primitive>>,
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props<Primitive>>(), {
|
|
fromFunctions: () => [],
|
|
toFunctions: () => [],
|
|
methods: () => [],
|
|
});
|
|
|
|
const state: Ref<{
|
|
fromFunctions: Array<FromFunction<Primitive>>,
|
|
toFunctions: Array<ToFunction<Primitive>>,
|
|
methods: Array<Method<Primitive>>,
|
|
|
|
// Selected In Function
|
|
selectedFromFunction: FromFunction<Primitive>,
|
|
|
|
// Selected Method
|
|
selectedMethod?: Method<Primitive>,
|
|
|
|
// The Primitive.
|
|
primitive?: Primitive,
|
|
|
|
// Error to display if an invalid input was given.
|
|
error?: string;
|
|
}> = ref({
|
|
// From functions, to functions and methods.
|
|
fromFunctions: [ ...props.fromFunctions ],
|
|
toFunctions: [ ...props.toFunctions ],
|
|
methods: [ ...props.methods ],
|
|
|
|
// The selected function.
|
|
selectedFromFunction: props.fromFunctions[0],
|
|
|
|
// The selected method.
|
|
selectedMethod: props.methods[0] || undefined,
|
|
|
|
// The Primitive.
|
|
primitive: undefined,
|
|
})
|
|
|
|
async function setPrimitive(functionToExecute: () => Primitive | Promise<Primitive>): void {
|
|
try {
|
|
state.value.primitive = await functionToExecute();
|
|
state.value.error = undefined;
|
|
|
|
state.value.toFunctions.forEach((wrappedMethod, i) => {
|
|
state.value.toFunctions[i].result = wrappedMethod.callback(state.value.primitive)
|
|
});
|
|
|
|
state.value.methods.forEach((method, i) => {
|
|
state.value.methods[i].models.forEach((model, j) => {
|
|
state.value.methods[i].models[j] = '';
|
|
});
|
|
|
|
state.value.methods[i].result = '';
|
|
});
|
|
} catch(error: any) {
|
|
state.value.error = `${error}`;
|
|
}
|
|
}
|
|
|
|
function getPrimitive(functionToExecute: () => string): string {
|
|
try {
|
|
if(!state.value.primitive) {
|
|
return '';
|
|
}
|
|
|
|
return functionToExecute();
|
|
} catch(error: any) {
|
|
return error.message;
|
|
}
|
|
}
|
|
|
|
async function executeMethod(wrappedMethod: () => string | Promise<string>): string {
|
|
try {
|
|
if(!state.value.primitive) {
|
|
return '';
|
|
}
|
|
|
|
state.value.selectedMethod.result = await wrappedMethod;
|
|
|
|
state.value.selectedMethod.error = undefined;
|
|
} catch(error: any) {
|
|
state.value.selectedMethod.error = error.message;
|
|
|
|
return error.message;
|
|
}
|
|
};
|
|
|
|
// Select the first "from" function.
|
|
state.value.selectedFromFunction = state.value.fromFunctions[0];
|
|
|
|
const autoGrow = (element: HTMLTextAreaElement) => {
|
|
element.style.height = 'auto'
|
|
element.style.height = `${Math.min(element.scrollHeight, 300)}px`
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.text-error {
|
|
color: #f46666;
|
|
overflow-wrap: break-word;
|
|
}
|
|
</style>
|