Initial commit
This commit is contained in:
192
app/components/marketing/email/MappingConfigurator.vue
Normal file
192
app/components/marketing/email/MappingConfigurator.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user