unclean SPARC
This commit is contained in:
@@ -0,0 +1,349 @@
|
||||
class MailingFetchDialog extends EICDialogContent {
|
||||
|
||||
actions = [
|
||||
{
|
||||
label: 'Cancel',
|
||||
onclick: this.cancel.bind(this),
|
||||
severity: 'secondary',
|
||||
role: 'cancel'
|
||||
},
|
||||
{
|
||||
label: 'Use these recipients',
|
||||
onclick: this.add.bind(this),
|
||||
severity: 'primary',
|
||||
role: 'add',
|
||||
disabled: true
|
||||
}
|
||||
]
|
||||
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
Object.assign(this, app.helpers.activeAttributes)
|
||||
this.currentFilters = []
|
||||
this.currentQCId = null
|
||||
this.currentNbResults = 0
|
||||
this.baseColors = ['success','primary','danger','warning','accent','secondary']
|
||||
}
|
||||
|
||||
DOMContentLoaded(options) {
|
||||
this.contactsModel = options.models.contacts
|
||||
this.mailingsModel = options.models.mailings
|
||||
this.mid = options.mid
|
||||
const components = ui.eicfy(this.el)
|
||||
this.setupTriggers(components)
|
||||
this.setupRefs(components)
|
||||
this.components.searchType.disabled = true
|
||||
this.setAsyncLoading(true, ['searchType'])
|
||||
this.contactsModel.list().then(this.fillQCSelector.bind(this))
|
||||
}
|
||||
|
||||
fillQCSelector(qcList){
|
||||
for(let query of qcList){
|
||||
this.components.searchType.el.append(ui.create(
|
||||
`<option value="${query.id}">${query.title}</option>`
|
||||
))
|
||||
}
|
||||
this.components.searchType.disabled = false
|
||||
this.setAsyncLoading(false, ['searchType'])
|
||||
}
|
||||
|
||||
onsearchType(component, event){
|
||||
this.setAsyncLoading(true, ['searchCriteria'])
|
||||
this.components.searchBtn.disabled = true
|
||||
this.contactsModel.get(component.value).then(this.buildForm.bind(this))
|
||||
}
|
||||
|
||||
onSourceName(component, event){ this.changeAddBtnState() }
|
||||
|
||||
buildForm(query){
|
||||
this.fieldNames = {}
|
||||
this.fieldColors = {}
|
||||
this.output('searchCriteria','')
|
||||
|
||||
const tabsMenu = ui.create(`
|
||||
<menu eictab vertical class="searchCriteriaGroups" xsmall>
|
||||
${query.group.map(queryGroup => `
|
||||
<li>
|
||||
${queryGroup.title}
|
||||
</li>
|
||||
`).join('\n')}
|
||||
</menu>
|
||||
`)
|
||||
const tabsDiv = ui.create(`<div class="cols-2 left"></div>`)
|
||||
this.outputs.searchCriteria.append(tabsDiv)
|
||||
|
||||
for(let queryGroup of query.group){
|
||||
const groupEl = ui.create(`
|
||||
<article eiccard="" class="tab-content searchCriteriaGroups">
|
||||
<header>
|
||||
<h1>${queryGroup.title}
|
||||
${queryGroup.description ? `<span info="" class="icon-info" title="${queryGroup.description.replace('"','"').replace(/\n/g, ' ')}"></span>`: ''}
|
||||
</h1>
|
||||
</header>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
`)
|
||||
const sectionEl = groupEl.querySelector('section')
|
||||
let colIdx = 0
|
||||
for(let field of queryGroup.field){
|
||||
this.fieldNames[field.id] = field.title
|
||||
this.fieldColors[field.id] = {
|
||||
severity: this.baseColors[colIdx % this.baseColors.length],
|
||||
brightness: 100+(20*Math.floor(colIdx/this.baseColors.length))
|
||||
}
|
||||
colIdx++
|
||||
const el = ui.create(`
|
||||
<div class="cols-2 field">
|
||||
<div class="cols-2 field-label">
|
||||
<label title="${field.description ? field.description.replace('"','"'):''}">${field.title}</label>
|
||||
${field.description ? `<span info="" class="icon-info" title="${field.description.replace('"','"').replace(/\n/g, ' ')}"></span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
if(!field.type) field.type='text'
|
||||
switch(field.type){
|
||||
case 'list':
|
||||
const selector = ui.create(`<select eicselect multiple name="${field.id}" lookup></select>`)
|
||||
for(let value of field.value){
|
||||
selector.append(ui.create(
|
||||
`<option value="${value}">${value}</option>`
|
||||
))
|
||||
}
|
||||
el.append(selector)
|
||||
break
|
||||
case 'date':
|
||||
el.append(ui.create(`<input eicinput type="date" name="${field.id}">`))
|
||||
break
|
||||
default:
|
||||
el.append(ui.create(`<select eicselect name="${field.id}" editable data-type="array" placeholder="One or several search values (hit enter after each)">`))
|
||||
|
||||
}
|
||||
sectionEl.append(el)
|
||||
}
|
||||
tabsDiv.append(groupEl)
|
||||
}
|
||||
|
||||
tabsDiv.prepend(tabsMenu)
|
||||
const groupsMenu = new Tab(tabsMenu)
|
||||
groupsMenu.addTabs(tabsDiv.querySelectorAll('menu.searchCriteriaGroups li'), tabsDiv.querySelectorAll('article.searchCriteriaGroups')); //Array.from(this.findAll('menu.searchCriteriaGroups li')).reverse()
|
||||
|
||||
const components = ui.eicfy(this.outputs.searchCriteria)
|
||||
this.setAsyncLoading(false, ['searchCriteria'])
|
||||
this.filtersForm = new Form(this.outputs.searchCriteria)
|
||||
this.setupTriggers(components)
|
||||
this.components.searchBtn.disabled = false
|
||||
}
|
||||
|
||||
onFiltersChange(component, event){
|
||||
this.currentQCId = this.components.searchType.value
|
||||
const formValues = this.filtersForm.value
|
||||
let fieldValues = Object.keys(formValues).map(k => ({id: k, value: formValues[k]}))
|
||||
this.currentFilters = fieldValues.filter(item => item.value.length>0)
|
||||
//this.setAsyncLoading(true, ['searchOutput'])
|
||||
this.components.searchBtn.loading = true
|
||||
this.contactsModel.getSample(this.currentQCId, this.currentFilters).then(
|
||||
this.fillSearchOutput.bind(this),
|
||||
() => this.components.searchBtn.loading = false
|
||||
//this.setAsyncLoading(false, ['searchOutput'])
|
||||
)
|
||||
}
|
||||
|
||||
fillSearchOutput(results){
|
||||
this.components.searchBtn.loading = false
|
||||
// this.setAsyncLoading(false, ['searchOutput'])
|
||||
this.output('searchOutput', `
|
||||
<alert eicalert small muted info>Total recipients: <b>${results.nbRows}</b></alert>
|
||||
<article eiccard collapsable>
|
||||
<header eicalert small muted info><h1>Quick Probe</h1></header>
|
||||
<section>
|
||||
Email (or part of it)
|
||||
<input eicinput="" type="search" name="emailProbe" data-ref="probeSearch"/>
|
||||
<article eiccard class="probe-results"></article>
|
||||
</section>
|
||||
</article>
|
||||
<article eiccard collapsable>
|
||||
<header eicalert small muted info><h1>Results statistics</h1></header>
|
||||
<section>
|
||||
<ul data-output="countersList"></ul>
|
||||
</section>
|
||||
</article>
|
||||
`)
|
||||
this.outputs.searchOutput.querySelectorAll('[eiccard]').forEach(el => { new Card(el) })
|
||||
this.outputs.searchOutput.querySelectorAll('[eicbutton]').forEach(el => { new Button(el) })
|
||||
const probeSearch = new InputSearch(this.outputs.searchOutput.querySelector('[eicinput][type="search"]'))
|
||||
probeSearch.onQuery = this.onProbe.bind(this,probeSearch)
|
||||
this.fillCountersLegend(results.counters)
|
||||
this.currentNbResults = results.nbRows
|
||||
this.changeAddBtnState()
|
||||
}
|
||||
|
||||
changeAddBtnState(){
|
||||
if((this.currentNbResults>0) && (this.components.sourceName.value.length>3)) this.actions.find(o => o.role == 'add').button.disabled = false
|
||||
else this.actions.find(o => o.role == 'add').button.disabled = true
|
||||
}
|
||||
|
||||
onRefreshSample(component){
|
||||
this.components.sampleRefreshBtn.loading = true
|
||||
this.contactsModel.getSample(this.currentQCId, this.currentFilters).then(
|
||||
(results) => {
|
||||
const el = this.outputs.searchOutput.querySelector('.sample-list')
|
||||
el.innerHTML = results.rows.map(row => ('<li>'+row.email+'</li>')).join('')
|
||||
this.components.sampleRefreshBtn.loading = false
|
||||
},
|
||||
() => this.components.sampleRefreshBtn.loading = false
|
||||
)
|
||||
}
|
||||
|
||||
onProbe(component){
|
||||
component.loading = true
|
||||
this.setAsyncLoading(false, ['quickprobe'])
|
||||
this.outputs.searchOutput.querySelector('article.probe-results').innerHTML = ''
|
||||
this.contactsModel.probe(this.currentQCId, this.currentFilters, component.value).then((payload) =>{
|
||||
this.fillProbeResults(payload)
|
||||
component.loading = false
|
||||
},
|
||||
() => { component.loading = false }
|
||||
)
|
||||
}
|
||||
|
||||
fillProbeResults(results){
|
||||
this.lastProbeResults = results
|
||||
this.lastProbeIndex = 0
|
||||
if(results.probeMatchesNumber==0){
|
||||
this.outputs.searchOutput.querySelector('article.probe-results').innerHTML = `<header>No email found containing that text.</header>`
|
||||
return
|
||||
}
|
||||
this.showProbeResult()
|
||||
}
|
||||
|
||||
showProbeResult(){
|
||||
this.outputs.searchOutput.querySelector('article.probe-results').innerHTML = ''
|
||||
this.outputs.searchOutput.querySelector('article.probe-results').append(ui.create(`
|
||||
<header>
|
||||
<div>
|
||||
<span>Found ${this.lastProbeResults.probeMatchesNumber} matching</span>
|
||||
<span xsmall data-output="probeIndex"></span>
|
||||
</div>
|
||||
<span class="next-prev"></span>
|
||||
</header>
|
||||
`))
|
||||
this.outputs.searchOutput.querySelector('article.probe-results').append(ui.create(`<section></section>`))
|
||||
this.probeMaxIndex = this.lastProbeResults.probeMatchesNumber<20 ? this.lastProbeResults.probeMatchesNumber-1 : 19
|
||||
this.components.prevProbeShow = new Button(null, {
|
||||
label:'<',
|
||||
size: 'xxsmall',
|
||||
onclick: () => {
|
||||
this.lastProbeIndex = (this.lastProbeIndex>0) ? this.lastProbeIndex-1 : this.probeMaxIndex
|
||||
this.showOneProbeMatch()
|
||||
}
|
||||
});
|
||||
this.outputs.searchOutput.querySelector('.next-prev').append(this.components.prevProbeShow.el)
|
||||
this.components.nextProbeShow = new Button(null, {
|
||||
label:'>',
|
||||
size: 'xxsmall',
|
||||
onclick: () => {
|
||||
this.lastProbeIndex = (this.lastProbeIndex<(this.probeMaxIndex)) ? this.lastProbeIndex+1 : 0
|
||||
this.showOneProbeMatch()
|
||||
}
|
||||
});
|
||||
this.outputs.searchOutput.querySelector('.next-prev').append(this.components.nextProbeShow.el)
|
||||
|
||||
this.showOneProbeMatch()
|
||||
}
|
||||
|
||||
showOneProbeMatch(){
|
||||
const row = this.lastProbeResults.probeMatches[this.lastProbeIndex]
|
||||
let html='<ul>'
|
||||
for(const key of Object.keys(row)){
|
||||
html += `<li><div class='cols-2'>
|
||||
<b>${row[key].title}</b>
|
||||
<i>${Array.isArray(row[key].value) ? row[key].value.join(', ') : row[key].value}</i>
|
||||
</div></li>`
|
||||
}
|
||||
html += '</ul>'
|
||||
this.outputs.searchOutput.querySelector('article.probe-results section').innerHTML = ''
|
||||
this.outputs.searchOutput.querySelector('article.probe-results section').append(ui.create(html))
|
||||
|
||||
this.outputs.searchOutput.querySelector('[data-output="probeIndex"]').innerHTML = ` (Showing ${this.lastProbeIndex+1}/${this.probeMaxIndex+1})`
|
||||
}
|
||||
|
||||
fillCountersLegend(counters){
|
||||
const el = this.outputs.searchOutput.querySelector('[data-output="countersList"]')
|
||||
el.innerHTML = ''
|
||||
for(let counterName in counters) {
|
||||
const liel = ui.create(`
|
||||
<li>
|
||||
<article eiccard collapsable collapsed>
|
||||
<header><div>${counterName} <span eicchip xxsmall>${counters[counterName].nbUnique} unique</span></div></header>
|
||||
<section>
|
||||
<div class="cols-2 resultCounter">
|
||||
<ul data-output="resultLegend"></ul>
|
||||
<div data-output="resultPie"></div>
|
||||
</div>
|
||||
</section>
|
||||
</alert>
|
||||
</li>
|
||||
`)
|
||||
el.append(liel)
|
||||
const ulel = liel.querySelector('[data-output="resultLegend"]')
|
||||
let colIdx = 0
|
||||
const pieData = []
|
||||
for(let value in counters[counterName].counters) {
|
||||
const severity = this.baseColors[colIdx % this.baseColors.length]
|
||||
const brightness = 100-(20*Math.floor(colIdx/this.baseColors.length))
|
||||
ulel.append(ui.create(`
|
||||
<li><div class="cols-2">
|
||||
<div class="color-dot" style="background: var(--eicui-base-color-${(severity!='secondary') ? severity : 'grey'}-100);filter:brightness(${brightness}%");></div>
|
||||
<div>
|
||||
<b>${value}:</b>
|
||||
<i>${ (100*counters[counterName].counters[value]/counters[counterName].total).toFixed(1) }% (${counters[counterName].counters[value]})</i>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
`))
|
||||
|
||||
pieData.push({
|
||||
value: counters[counterName].counters[value],
|
||||
severity: severity,
|
||||
brightness: `${brightness}%`,
|
||||
})
|
||||
colIdx++
|
||||
}
|
||||
new PieTreeChart(liel.querySelector('[data-output="resultPie"]'), {
|
||||
title: '',
|
||||
height: 200,
|
||||
data: pieData,
|
||||
angularGap: 1,
|
||||
innerRadius: 0,
|
||||
outerRadius: 50
|
||||
})
|
||||
|
||||
}
|
||||
el.querySelectorAll('[eiccard]').forEach(el => { new Card(el) })
|
||||
}
|
||||
|
||||
async add() {
|
||||
this.actions.find(o => o.role == 'add').button.loading = true
|
||||
this.currentQCId = this.components.searchType.value
|
||||
const formValues = this.filtersForm.value
|
||||
let fieldValues = Object.keys(formValues).map(k => ({id: k, value: formValues[k]}))
|
||||
this.currentFilters = fieldValues.filter(item => item.value.length>0)
|
||||
await this.mailingsModel.saveImport(this.mid, {
|
||||
sourceName: this.components.sourceName.value,
|
||||
sourceType: 'Marklogic',
|
||||
data: null,
|
||||
availableColumns: null,
|
||||
query_id: this.currentQCId,
|
||||
query_params: this.currentFilters,
|
||||
})
|
||||
this.commit(true)
|
||||
}
|
||||
|
||||
onFailed() {
|
||||
this.abort()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app.registerClass('MailingFetchDialog',MailingFetchDialog);
|
||||
Reference in New Issue
Block a user