besper-frontend-site-dev-main
Version:
Professional B-esper Frontend Site - Site-wide integration toolkit for full website bot deployment
812 lines (719 loc) • 27.8 kB
JavaScript
/**
* Configuration Tab Component
* Handles the configuration tab in the bot management interface
*/
export class ConfigurationTab {
constructor(widget, state, i18n = null) {
this.widget = widget;
this.state = state;
this.i18n = i18n;
}
/**
* Update language
* @param {string} _language - New language code
*/
updateLanguage(_language) {
// Re-render the tab content with new language
const tabContent = this.widget.querySelector('#bm-tab-configuration');
if (tabContent && this.i18n) {
const updatedHTML = this.getHTML();
const match = updatedHTML.match(
/<div class="bm-tab-content"[^>]*>([\s\S]*)<\/div>\s*$/
);
if (match) {
tabContent.innerHTML = match[1];
// Re-setup event listeners after content update
this.setupEventListeners(this.currentCallbacks || {});
}
}
}
/**
* Get translated text
* @param {string} key - Translation key
* @param {Object} variables - Variables for substitution
* @returns {string} Translated text
*/
t(key, variables = {}) {
return this.i18n ? this.i18n.t(`configuration.${key}`, variables) : key;
}
/**
* Generate the HTML for the configuration tab
* @returns {string} Configuration tab HTML string
*/
getHTML() {
return `
<div class="bm-tab-content" id="bm-tab-configuration">
<h2 style="font-size: 24px; font-weight: 500; color: #022d54; margin: 0 0 8px 0;">${this.t('title')}</h2>
<p style="font-size: 14px; color: #6b7684; margin: 0 0 32px 0;">${this.t('subtitle')}</p>
<div class="bm-grid">
<!-- Basic Information -->
${this.getBasicInformationCard()}
<!-- Bot Credentials -->
${this.getBotCredentialsCard()}
<!-- Welcome Message -->
${this.getWelcomeMessageCard()}
<!-- Logo Upload -->
${this.getLogoUploadCard()}
<!-- CORS Configuration -->
${this.getCorsConfigurationCard()}
<!-- Welcome Messages -->
${this.getWelcomeMessagesCard()}
</div>
<div class="bm-actions">
<button class="bm-btn bm-btn-primary" id="bm-saveBtn">${this.t('actions.save')}</button>
<button class="bm-btn bm-btn-secondary" id="bm-refreshBtn">${this.t('actions.refresh')}</button>
</div>
</div>
`;
}
/**
* Get Basic Information card HTML
*/
getBasicInformationCard() {
return `
<div class="bm-card">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2L2 7L12 12L22 7L12 2Z"/>
<path d="M2 17L12 22L22 17"/>
<path d="M2 12L12 17L22 12"/>
</svg>
${this.t('basicInfo.title')}
</h2>
<p class="bm-card-subtitle">${this.t('basicInfo.subtitle')}</p>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('basicInfo.botName')} *</label>
<input type="text" class="bm-form-input" id="bm-nameInput" placeholder="${this.t('basicInfo.botName')}">
<p class="bm-form-hint">${this.t('basicInfo.internalIdentifier')}</p>
</div>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('basicInfo.botTitle')} *</label>
<input type="text" class="bm-form-input" id="bm-botTitleInput" placeholder="Customer Support">
<p class="bm-form-hint">${this.t('basicInfo.shownInHeader')}</p>
</div>
<div class="bm-form-group">
<label class="bm-form-label">
${this.t('basicInfo.dataPolicyUrl')}
<button type="button" class="bm-info-btn" title="Information">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<path d="M12 16v-4"/>
<path d="M12 8h.01"/>
</svg>
</button>
</label>
<input type="text" class="bm-form-input" id="bm-dataPolicyInput" placeholder="https://example.com/privacy">
<div class="bm-info-tooltip">
<p>${this.t('basicInfo.dataPolicyHint')}</p>
</div>
</div>
</div>
`;
}
/**
* Get Bot Credentials card HTML
*/
getBotCredentialsCard() {
return `
<div class="bm-card">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
<circle cx="12" cy="16" r="1"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>
${this.t('credentials.title')}
</h2>
<p class="bm-card-subtitle">${this.t('credentials.subtitle')}</p>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('credentials.botId')}</label>
<div class="bm-credential-field">
<input type="text" class="bm-form-input" id="bm-botIdInput" readonly>
<button class="bm-copy-btn" data-copy-target="bm-botIdInput">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
</button>
</div>
</div>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('credentials.managementId')}</label>
<div class="bm-credential-field">
<input type="text" class="bm-form-input" id="bm-managementIdInput" readonly>
<button class="bm-copy-btn" data-copy-target="bm-managementIdInput">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
</button>
</div>
</div>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('credentials.managementSecret')}</label>
<div class="bm-credential-field">
<input type="password" class="bm-form-input" id="bm-managementSecretInput" readonly>
<button class="bm-toggle-btn" id="bm-toggleSecretBtn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
<circle cx="12" cy="12" r="3"/>
</svg>
</button>
<button class="bm-copy-btn" data-copy-target="bm-managementSecretInput">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2 2v1"/>
</svg>
</button>
</div>
</div>
</div>
`;
}
/**
* Get Instructions card HTML
*/
getInstructionsCard() {
return `
<div class="bm-card">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6A2 2 0 0 0 4 4V20A2 2 0 0 0 6 22H18A2 2 0 0 0 20 20V8Z"/>
<path d="M14 2V8H20"/>
</svg>
Instructions
</h2>
<div class="bm-form-group">
<textarea class="bm-form-textarea" id="bm-instructionsInput" placeholder="${this.i18n ? this.i18n.t('placeholders.botInstructions') : 'Enter bot instructions...'}" rows="6"></textarea>
</div>
</div>
`;
}
/**
* Get Welcome Message card HTML
*/
getWelcomeMessageCard() {
return `
<div class="bm-card">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
${this.t('welcomeMessage.title')}
</h2>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('welcomeMessage.defaultMessage')}</label>
<textarea class="bm-form-textarea" id="bm-welcomeMessageInput" placeholder="${this.t('welcomeMessage.placeholder')}" rows="3"></textarea>
<p class="bm-form-hint">${this.t('welcomeMessage.hint')}</p>
</div>
</div>
`;
}
/**
* Get Logo Upload card HTML
*/
getLogoUploadCard() {
return `
<div class="bm-card">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<path d="M21 15l-5-5L5 21"/>
</svg>
${this.t('logo.title')}
</h2>
<div class="bm-logo-section">
<div class="bm-logo-preview" id="bm-logoPreview">
<div class="bm-logo-placeholder">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<path d="M21 15l-5-5L5 21"/>
</svg>
<span>${this.t('logo.noLogo')}</span>
</div>
</div>
<div class="bm-logo-actions">
<button class="bm-btn bm-btn-primary" id="bm-selectLogoBtn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>
${this.t('logo.upload')}
</button>
<button class="bm-btn bm-btn-secondary" id="bm-removeLogoBtn" style="display: none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
${this.t('logo.remove')}
</button>
<input type="file" id="bm-logoFileInput" style="display: none;" accept="image/*">
</div>
<p class="bm-form-hint">${this.t('logo.hint')}</p>
</div>
</div>
`;
}
/**
* Get CORS Configuration card HTML
*/
getCorsConfigurationCard() {
return `
<div class="bm-card bm-card-full">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"/>
<path d="M12 1v6M12 17v6M4.22 4.22l4.24 4.24M15.54 15.54l4.24 4.24M1 12h6M17 12h6M4.22 19.78l4.24-4.24M15.54 8.46l4.24-4.24"/>
</svg>
${this.t('cors.title')}
</h2>
<p class="bm-form-description">
${this.t('cors.subtitle')}
</p>
<div class="bm-form-group">
<label class="bm-form-label">${this.t('cors.allowedOrigins')}</label>
<div class="bm-cors-origins-container">
<div id="bm-corsOriginsList" class="bm-cors-origins-list">
<!-- Origins will be populated here -->
</div>
<div class="bm-cors-add-container">
<input type="text" class="bm-form-input" id="bm-corsOriginInput" placeholder="https://example.com" style="flex: 1;">
<button class="bm-btn bm-btn-secondary bm-btn-sm" id="bm-addCorsOriginBtn">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="16"/>
<line x1="8" y1="12" x2="16" y2="12"/>
</svg>
${this.t('cors.addOrigin')}
</button>
</div>
</div>
</div>
</div>
`;
}
/**
* Get Welcome Messages card HTML
*/
getWelcomeMessagesCard() {
return `
<div class="bm-card bm-card-full">
<h2 class="bm-card-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>
</svg>
Welcome Messages
</h2>
<div class="bm-welcome-section">
<div class="bm-welcome-actions">
<button class="bm-btn bm-btn-primary" id="bm-addLanguageBtn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"/>
<line x1="5" y1="12" x2="19" y2="12"/>
</svg>
${this.t('welcomeMessages.addLanguage')}
</button>
<button class="bm-btn bm-btn-secondary" id="bm-translateAllBtn" disabled>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M5 8l6 6M4 14l6-6 2-3 3 3 6 6"/>
<path d="M2 5h12M7 2v3"/>
<path d="M22 22l-5-10-5 10"/>
<path d="M14 18h6"/>
</svg>
${this.t('welcomeMessages.translateAll')}
</button>
</div>
<div class="bm-welcome-messages" id="bm-welcomeMessages">
<!-- Dynamic welcome message fields will be added here -->
</div>
</div>
</div>
`;
}
/**
* Setup event listeners for configuration tab
* @param {Object} callbacks - Callback functions for events
*/
setupEventListeners(callbacks = {}) {
// Store callbacks for later use
this.currentCallbacks = callbacks;
// Copy buttons
const copyButtons = this.widget.querySelectorAll(
'.bm-copy-btn[data-copy-target]'
);
copyButtons.forEach(btn => {
btn.addEventListener('click', () => {
const targetId = btn.getAttribute('data-copy-target');
this.copyToClipboard(targetId);
});
});
// Toggle secret visibility
const toggleSecretBtn = this.widget.querySelector('#bm-toggleSecretBtn');
if (toggleSecretBtn) {
toggleSecretBtn.addEventListener('click', () =>
this.toggleSecretVisibility()
);
}
// Logo upload
const selectLogoBtn = this.widget.querySelector('#bm-selectLogoBtn');
const logoFileInput = this.widget.querySelector('#bm-logoFileInput');
const removeLogoBtn = this.widget.querySelector('#bm-removeLogoBtn');
if (selectLogoBtn && logoFileInput) {
selectLogoBtn.addEventListener('click', () => logoFileInput.click());
logoFileInput.addEventListener('change', e => this.handleLogoUpload(e));
}
if (removeLogoBtn) {
removeLogoBtn.addEventListener('click', () => this.removeLogo());
}
// CORS origins
const addCorsOriginBtn = this.widget.querySelector('#bm-addCorsOriginBtn');
const corsOriginInput = this.widget.querySelector('#bm-corsOriginInput');
if (addCorsOriginBtn) {
addCorsOriginBtn.addEventListener('click', () => this.addCorsOrigin());
}
if (corsOriginInput) {
corsOriginInput.addEventListener('keypress', e => {
if (e.key === 'Enter') {
e.preventDefault();
this.addCorsOrigin();
}
});
}
// Welcome messages
const addLanguageBtn = this.widget.querySelector('#bm-addLanguageBtn');
const translateAllBtn = this.widget.querySelector('#bm-translateAllBtn');
if (addLanguageBtn && callbacks.onAddLanguage) {
addLanguageBtn.addEventListener('click', callbacks.onAddLanguage);
}
if (translateAllBtn && callbacks.onTranslateAll) {
translateAllBtn.addEventListener('click', callbacks.onTranslateAll);
}
// Info tooltip for data policy URL
const infoBtn = this.widget.querySelector('.bm-info-btn');
const infoTooltip = this.widget.querySelector('.bm-info-tooltip');
if (infoBtn && infoTooltip) {
let isTooltipVisible = false;
const isMobile = window.innerWidth <= 768;
const showTooltip = () => {
infoTooltip.style.display = 'block';
isTooltipVisible = true;
// On mobile, add backdrop to prevent scrolling
if (isMobile) {
document.body.style.overflow = 'hidden';
}
};
const hideTooltip = () => {
infoTooltip.style.display = 'none';
isTooltipVisible = false;
// Restore scrolling on mobile
if (isMobile) {
document.body.style.overflow = '';
}
};
// Toggle on click (primary interaction for mobile)
infoBtn.addEventListener('click', e => {
e.preventDefault();
e.stopPropagation();
if (isTooltipVisible) {
hideTooltip();
} else {
showTooltip();
}
});
// Hide when clicking outside
document.addEventListener('click', e => {
if (
isTooltipVisible &&
!infoBtn.contains(e.target) &&
!infoTooltip.contains(e.target)
) {
hideTooltip();
}
});
// Mobile-specific: Close button in tooltip
if (isMobile) {
infoTooltip.addEventListener('click', e => {
// Check if clicked on the close button (×)
if (
e.target === infoTooltip &&
e.offsetX > infoTooltip.offsetWidth - 30
) {
hideTooltip();
}
});
// Escape key to close
document.addEventListener('keydown', e => {
if (e.key === 'Escape' && isTooltipVisible) {
hideTooltip();
}
});
} else {
// Desktop: Show on hover
infoBtn.addEventListener('mouseenter', showTooltip);
infoBtn.addEventListener('mouseleave', () => {
// Small delay to allow moving to tooltip
setTimeout(() => {
if (!infoTooltip.matches(':hover') && !infoBtn.matches(':hover')) {
hideTooltip();
}
}, 100);
});
// Keep visible when hovering tooltip
infoTooltip.addEventListener('mouseenter', () => {
showTooltip();
});
infoTooltip.addEventListener('mouseleave', hideTooltip);
}
}
// Save and refresh buttons
const saveBtn = this.widget.querySelector('#bm-saveBtn');
const refreshBtn = this.widget.querySelector('#bm-refreshBtn');
if (saveBtn && callbacks.onSave) {
saveBtn.addEventListener('click', callbacks.onSave);
}
if (refreshBtn && callbacks.onRefresh) {
refreshBtn.addEventListener('click', callbacks.onRefresh);
}
}
/**
* Copy text to clipboard
* @param {string} targetId - ID of the input element to copy from
*/
copyToClipboard(targetId) {
const input = this.widget.querySelector(`#${targetId}`);
if (input) {
input.select();
input.setSelectionRange(0, 99999); // For mobile devices
document.execCommand('copy');
// Show feedback
this.showCopyFeedback(input);
}
}
/**
* Show copy feedback
* @param {HTMLElement} element - Element to show feedback for
*/
showCopyFeedback(element) {
const originalBorder = element.style.border;
element.style.border = '2px solid #10b981';
setTimeout(() => {
element.style.border = originalBorder;
}, 500);
}
/**
* Toggle secret visibility
*/
toggleSecretVisibility() {
const secretInput = this.widget.querySelector('#bm-managementSecretInput');
const toggleBtn = this.widget.querySelector('#bm-toggleSecretBtn');
if (secretInput && toggleBtn) {
const isPassword = secretInput.type === 'password';
secretInput.type = isPassword ? 'text' : 'password';
const svg = toggleBtn.querySelector('svg');
if (svg) {
svg.innerHTML = isPassword
? '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>'
: '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>';
}
}
}
/**
* Handle logo upload
* @param {Event} event - File input change event
*/
handleLogoUpload(event) {
const file = event.target.files[0];
if (file) {
// Validate file
if (!this.validateLogoFile(file)) {
return;
}
// Create preview
const reader = new FileReader();
reader.onload = e => {
this.updateLogoPreview(e.target.result);
};
reader.readAsDataURL(file);
}
}
/**
* Validate logo file
* @param {File} file - File to validate
* @returns {boolean} Whether file is valid
*/
validateLogoFile(file) {
const maxSize = 2 * 1024 * 1024; // 2MB
const allowedTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/svg+xml',
'image/webp',
];
if (file.size > maxSize) {
console.error('File size must be less than 2MB');
return false;
}
if (!allowedTypes.includes(file.type)) {
console.error(
'File type not supported. Please use JPG, PNG, GIF, SVG, or WebP'
);
return false;
}
return true;
}
/**
* Update logo preview
* @param {string} imageUrl - Image URL to display
*/
updateLogoPreview(imageUrl) {
const logoPreview = this.widget.querySelector('#bm-logoPreview');
const removeLogoBtn = this.widget.querySelector('#bm-removeLogoBtn');
if (logoPreview) {
logoPreview.innerHTML = `<img src="${imageUrl}" alt="Bot Logo" style="max-width: 100%; max-height: 100%; border-radius: 8px;">`;
}
if (removeLogoBtn) {
removeLogoBtn.style.display = 'inline-flex';
}
}
/**
* Remove logo
*/
removeLogo() {
const logoPreview = this.widget.querySelector('#bm-logoPreview');
const logoFileInput = this.widget.querySelector('#bm-logoFileInput');
const removeLogoBtn = this.widget.querySelector('#bm-removeLogoBtn');
if (logoPreview) {
logoPreview.innerHTML = `
<div class="bm-logo-placeholder">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<path d="M21 15l-5-5L5 21"/>
</svg>
<span>No logo uploaded</span>
</div>
`;
}
if (logoFileInput) {
logoFileInput.value = '';
}
if (removeLogoBtn) {
removeLogoBtn.style.display = 'none';
}
}
/**
* Add CORS origin
*/
addCorsOrigin() {
const input = this.widget.querySelector('#bm-corsOriginInput');
const originsList = this.widget.querySelector('#bm-corsOriginsList');
if (input && originsList) {
const origin = input.value.trim();
if (origin) {
this.addCorsOriginToList(origin, originsList);
input.value = '';
}
}
}
/**
* Add CORS origin to list
* @param {string} origin - Origin to add
* @param {HTMLElement} container - Container to add origin to
*/
addCorsOriginToList(origin, container) {
const originElement = document.createElement('div');
originElement.className = 'bm-cors-origin-item';
originElement.innerHTML = `
<span class="bm-cors-origin-text">${origin}</span>
<button class="bm-cors-remove-btn" type="button">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
`;
const removeBtn = originElement.querySelector('.bm-cors-remove-btn');
removeBtn.addEventListener('click', () => {
originElement.remove();
});
container.appendChild(originElement);
}
/**
* Populate configuration data
* @param {Object} config - Configuration data
*/
populateData(config) {
if (!config) return;
// Basic information
this.setInputValue('bm-nameInput', config.name);
this.setInputValue('bm-botTitleInput', config.botTitle);
this.setInputValue('bm-dataPolicyInput', config.dataPolicyUrl);
// Credentials
this.setInputValue('bm-botIdInput', config.botId);
this.setInputValue('bm-managementIdInput', config.managementId);
this.setInputValue('bm-managementSecretInput', config.managementSecret);
// Instructions and welcome message
this.setInputValue('bm-instructionsInput', config.instructions);
this.setInputValue('bm-welcomeMessageInput', config.welcomeMessage);
// Logo
if (config.logoUrl) {
this.updateLogoPreview(config.logoUrl);
}
// CORS origins
if (config.corsOrigins && Array.isArray(config.corsOrigins)) {
const originsList = this.widget.querySelector('#bm-corsOriginsList');
if (originsList) {
originsList.innerHTML = '';
config.corsOrigins.forEach(origin => {
this.addCorsOriginToList(origin, originsList);
});
}
}
}
/**
* Set input value safely
* @param {string} id - Input ID
* @param {any} value - Value to set
*/
setInputValue(id, value) {
const input = this.widget.querySelector(`#${id}`);
if (input && value !== undefined && value !== null) {
input.value = value;
}
}
/**
* Get configuration data from form
* @returns {Object} Configuration data
*/
getConfigurationData() {
return {
name: this.getInputValue('bm-nameInput'),
botTitle: this.getInputValue('bm-botTitleInput'),
dataPolicyUrl: this.getInputValue('bm-dataPolicyInput'),
instructions: this.getInputValue('bm-instructionsInput'),
welcomeMessage: this.getInputValue('bm-welcomeMessageInput'),
corsOrigins: this.getCorsOrigins(),
};
}
/**
* Get input value safely
* @param {string} id - Input ID
* @returns {string} Input value
*/
getInputValue(id) {
const input = this.widget.querySelector(`#${id}`);
return input ? input.value.trim() : '';
}
/**
* Get CORS origins from the list
* @returns {Array} Array of CORS origins
*/
getCorsOrigins() {
const originItems = this.widget.querySelectorAll('.bm-cors-origin-text');
return Array.from(originItems).map(item => item.textContent.trim());
}
}