Add 'tags' to event model. Add a dataimport system - currently for MaxMind zip files
This commit is contained in:
145
app/javascript/controllers/country_selector_controller.js
Normal file
145
app/javascript/controllers/country_selector_controller.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "select" ]
|
||||
static values = {
|
||||
options: Array,
|
||||
placeholder: String
|
||||
}
|
||||
|
||||
connect() {
|
||||
// Check if the element is visible, if not, wait for it to become visible
|
||||
if (this.isHidden()) {
|
||||
// Element is hidden, set up a MutationObserver to watch for visibility changes
|
||||
this.observer = new MutationObserver(() => {
|
||||
if (!this.isHidden()) {
|
||||
this.initializeTomSelect()
|
||||
this.observer.disconnect()
|
||||
}
|
||||
})
|
||||
|
||||
this.observer.observe(this.element, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
})
|
||||
|
||||
// Also check periodically as a fallback
|
||||
this.checkInterval = setInterval(() => {
|
||||
if (!this.isHidden()) {
|
||||
this.initializeTomSelect()
|
||||
this.cleanup()
|
||||
}
|
||||
}, 500)
|
||||
} else {
|
||||
// Element is already visible, initialize immediately
|
||||
this.initializeTomSelect()
|
||||
}
|
||||
}
|
||||
|
||||
isHidden() {
|
||||
return this.element.offsetParent === null || this.element.classList.contains('hidden')
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if (this.observer) {
|
||||
this.observer.disconnect()
|
||||
this.observer = null
|
||||
}
|
||||
if (this.checkInterval) {
|
||||
clearInterval(this.checkInterval)
|
||||
this.checkInterval = null
|
||||
}
|
||||
}
|
||||
|
||||
initializeTomSelect() {
|
||||
if (!this.hasSelectTarget) {
|
||||
console.log('No select target found')
|
||||
return
|
||||
}
|
||||
|
||||
// Check if Tom Select is available
|
||||
if (typeof TomSelect === 'undefined') {
|
||||
console.log('Tom Select is not loaded')
|
||||
return
|
||||
}
|
||||
|
||||
// If TomSelect is already initialized, destroy it first
|
||||
if (this.tomSelect) {
|
||||
this.tomSelect.destroy()
|
||||
}
|
||||
|
||||
console.log('Initializing Tom Select with options:', this.optionsValue.length, 'countries')
|
||||
console.log('First few country options:', this.optionsValue.slice(0, 3))
|
||||
|
||||
// Prepare options for Tom Select
|
||||
const options = this.optionsValue.map(([display, value]) => ({
|
||||
value: value,
|
||||
text: display,
|
||||
// Add searchable fields for better search
|
||||
search: display + ' ' + value
|
||||
}))
|
||||
|
||||
// Get currently selected values from the hidden select
|
||||
const selectedValues = Array.from(this.selectTarget.selectedOptions).map(option => option.value)
|
||||
|
||||
try {
|
||||
// Initialize Tom Select
|
||||
this.tomSelect = new TomSelect(this.selectTarget, {
|
||||
options: options,
|
||||
items: selectedValues,
|
||||
plugins: ['remove_button'],
|
||||
maxItems: null,
|
||||
maxOptions: 1000,
|
||||
create: false,
|
||||
placeholder: this.placeholderValue || "Search and select countries...",
|
||||
searchField: ['text', 'search'],
|
||||
searchConjunction: 'or',
|
||||
onItemAdd: function() {
|
||||
// Clear the search input after selecting an item
|
||||
this.setTextboxValue('');
|
||||
this.refreshOptions();
|
||||
},
|
||||
render: {
|
||||
option: function(data, escape) {
|
||||
return `<div class="flex items-center p-2">
|
||||
<span>${escape(data.text)}</span>
|
||||
</div>`
|
||||
},
|
||||
item: function(data, escape) {
|
||||
return `<div class="flex items-center text-sm">
|
||||
<span>${escape(data.text)}</span>
|
||||
</div>`
|
||||
}
|
||||
},
|
||||
dropdownParent: 'body',
|
||||
copyClassesToDropdown: false
|
||||
})
|
||||
|
||||
console.log('Tom Select successfully initialized for country selector')
|
||||
|
||||
// Make sure the wrapper is visible
|
||||
setTimeout(() => {
|
||||
if (this.tomSelect && this.tomSelect.wrapper) {
|
||||
this.tomSelect.wrapper.style.visibility = 'visible'
|
||||
this.tomSelect.wrapper.style.display = 'block'
|
||||
console.log('Tom Select wrapper made visible')
|
||||
}
|
||||
}, 100)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error initializing Tom Select:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Public method to reinitialize if needed
|
||||
reinitialize() {
|
||||
this.initializeTomSelect()
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.cleanup()
|
||||
if (this.tomSelect) {
|
||||
this.tomSelect.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["progressBar", "totalRecords", "processedRecords", "failedRecords", "recordsPerSecond"]
|
||||
static values = {
|
||||
importId: Number,
|
||||
refreshInterval: { type: Number, default: 2000 }
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (this.hasImportIdValue) {
|
||||
this.startUpdating()
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.stopUpdating()
|
||||
}
|
||||
|
||||
startUpdating() {
|
||||
this.updateProgress()
|
||||
this.interval = setInterval(() => {
|
||||
this.updateProgress()
|
||||
}, this.refreshIntervalValue)
|
||||
}
|
||||
|
||||
stopUpdating() {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
}
|
||||
|
||||
async updateProgress() {
|
||||
try {
|
||||
const response = await fetch(`/data_imports/${this.importIdValue}/progress`)
|
||||
const data = await response.json()
|
||||
|
||||
this.updateProgressBar(data.progress_percentage)
|
||||
this.updateStats(data)
|
||||
|
||||
// If completed or failed, reload the page
|
||||
if (data.status === 'completed' || data.status === 'failed') {
|
||||
setTimeout(() => {
|
||||
window.location.reload()
|
||||
}, 2000)
|
||||
this.stopUpdating()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating progress:', error)
|
||||
}
|
||||
}
|
||||
|
||||
updateProgressBar(percentage) {
|
||||
if (this.hasProgressBarTarget) {
|
||||
this.progressBarTarget.style.width = `${percentage}%`
|
||||
}
|
||||
}
|
||||
|
||||
updateStats(data) {
|
||||
if (this.hasTotalRecordsTarget) {
|
||||
this.totalRecordsTarget.textContent = data.total_records.toLocaleString()
|
||||
}
|
||||
|
||||
if (this.hasProcessedRecordsTarget) {
|
||||
this.processedRecordsTarget.textContent = data.processed_records.toLocaleString()
|
||||
}
|
||||
|
||||
if (this.hasFailedRecordsTarget) {
|
||||
this.failedRecordsTarget.textContent = data.failed_records.toLocaleString()
|
||||
}
|
||||
|
||||
if (this.hasRecordsPerSecondTarget) {
|
||||
this.recordsPerSecondTarget.textContent = data.records_per_second.toLocaleString()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user