266 lines
6.9 KiB
Vue
266 lines
6.9 KiB
Vue
<template>
|
|
<div class="box">
|
|
<div
|
|
v-for="(mapping, mapIndex) in localMappings"
|
|
:key="mapIndex"
|
|
class="mb-5 p-4 border"
|
|
>
|
|
<div class="level">
|
|
<div class="level-left">
|
|
<h5 class="title is-5">Mapping {{ mapIndex + 1 }}: {{ mapping.alias }}</h5>
|
|
</div>
|
|
<div class="level-right">
|
|
<button
|
|
class="button is-danger is-small"
|
|
@click="removeMapping(mapIndex)"
|
|
>
|
|
<span class="icon is-small">
|
|
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'white', size: 16 }"></SvgIcon>
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns is-multiline">
|
|
<div class="column is-6">
|
|
<div class="field">
|
|
<label class="label">Alias</label>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="mapping.alias"
|
|
@input="update"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-6">
|
|
<div class="field">
|
|
<label class="label">Model</label>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="mapping.model"
|
|
@input="update"
|
|
placeholder="e.g., app.Transaction"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-6">
|
|
<div class="field">
|
|
<label class="label">Lookup Field</label>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="mapping.lookup_field"
|
|
@input="update"
|
|
placeholder="e.g., id"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-6">
|
|
<div class="field">
|
|
<label class="label">Lookup Value From</label>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="mapping.lookup_value_from"
|
|
@input="update"
|
|
placeholder="e.g., transaction_id or transaction.customer.id"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-6">
|
|
<div class="field">
|
|
<label class="label">Type</label>
|
|
<div class="control">
|
|
<div class="select is-fullwidth">
|
|
<select
|
|
v-model="mapping.type"
|
|
@change="update"
|
|
>
|
|
<option value="object">Object</option>
|
|
<option value="list">List</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-6">
|
|
<div class="field">
|
|
<label class="label">Is Trigger Object?</label>
|
|
<div class="control">
|
|
<label class="checkbox">
|
|
<input
|
|
type="checkbox"
|
|
v-model="mapping.is_trigger_object"
|
|
@change="update"
|
|
/>
|
|
Yes
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr />
|
|
<h6 class="title is-6">Fields</h6>
|
|
<div
|
|
v-for="(field, fieldIndex) in mapping.fields"
|
|
:key="fieldIndex"
|
|
class="field has-addons"
|
|
>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="field.placeholder"
|
|
@input="update"
|
|
placeholder="[placeholder]"
|
|
/>
|
|
</div>
|
|
<div class="control is-expanded">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="field.source"
|
|
@input="update"
|
|
placeholder="source.field.name"
|
|
/>
|
|
</div>
|
|
<div class="control">
|
|
<button
|
|
class="button is-danger is-light"
|
|
@click="removeField(mapIndex, fieldIndex as number)"
|
|
>
|
|
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'primary' }"></SvgIcon>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<button
|
|
class="button is-small is-light"
|
|
@click="addField(mapIndex)"
|
|
>
|
|
<span class="icon is-small">+</span>
|
|
<span>Add Field</span>
|
|
</button>
|
|
</div>
|
|
|
|
<button
|
|
class="button is-primary"
|
|
@click="addMapping"
|
|
>
|
|
<SvgIcon
|
|
class="mr-2"
|
|
v-bind="{ name: 'add4.svg', type: 'white', size: 18 }"
|
|
/>
|
|
Add Mapping
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, watch } from "vue";
|
|
|
|
const props = defineProps({
|
|
mappings: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(["update:mappings"]);
|
|
|
|
// Use a local ref to manage mappings to handle the object-to-array transformation for fields
|
|
const localMappings = ref<any[]>([]);
|
|
|
|
// Helper to transform fields object to array for v-for
|
|
const transformMappings = (sourceMappings: any[]) => {
|
|
return sourceMappings.map((m) => ({
|
|
...m,
|
|
fields: m.fields
|
|
? Object.entries(m.fields).map(([placeholder, source]) => ({
|
|
placeholder,
|
|
source: typeof source === "object" ? JSON.stringify(source) : source,
|
|
}))
|
|
: [],
|
|
}));
|
|
};
|
|
|
|
// Helper to transform fields array back to object for emission
|
|
const reformatMappingsForEmit = () => {
|
|
return localMappings.value.map((m) => {
|
|
const newFields = m.fields.reduce((obj: any, item: any) => {
|
|
try {
|
|
// Attempt to parse if it's a JSON string for format objects
|
|
obj[item.placeholder] = JSON.parse(item.source);
|
|
} catch (e) {
|
|
obj[item.placeholder] = item.source;
|
|
}
|
|
return obj;
|
|
}, {});
|
|
return { ...m, fields: newFields };
|
|
});
|
|
};
|
|
|
|
watch(
|
|
() => props.mappings,
|
|
(newMappings) => {
|
|
localMappings.value = transformMappings(newMappings || []);
|
|
},
|
|
{ immediate: true, deep: true },
|
|
);
|
|
|
|
const addMapping = () => {
|
|
localMappings.value.push({
|
|
alias: "",
|
|
model: "",
|
|
lookup_field: "id",
|
|
lookup_value_from: "",
|
|
type: "object",
|
|
is_trigger_object: false,
|
|
fields: [],
|
|
});
|
|
update();
|
|
};
|
|
|
|
const removeMapping = (index: number) => {
|
|
localMappings.value.splice(index, 1);
|
|
update();
|
|
};
|
|
|
|
const addField = (mapIndex: number) => {
|
|
if (!localMappings.value[mapIndex].fields) {
|
|
localMappings.value[mapIndex].fields = [];
|
|
}
|
|
localMappings.value[mapIndex].fields.push({ placeholder: "", source: "" });
|
|
update();
|
|
};
|
|
|
|
const removeField = (mapIndex: number, fieldIndex: number) => {
|
|
localMappings.value[mapIndex].fields.splice(fieldIndex, 1);
|
|
update();
|
|
};
|
|
|
|
const update = () => {
|
|
emit("update:mappings", reformatMappingsForEmit());
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.box {
|
|
padding: 1.5rem;
|
|
}
|
|
.border {
|
|
border: 1px solid #dbdbdb;
|
|
border-radius: 4px;
|
|
}
|
|
</style>
|