iatoolkit 0.3.9__py3-none-any.whl → 0.107.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iatoolkit might be problematic. Click here for more details.
- iatoolkit/__init__.py +27 -35
- iatoolkit/base_company.py +3 -35
- iatoolkit/cli_commands.py +18 -47
- iatoolkit/common/__init__.py +0 -0
- iatoolkit/common/exceptions.py +48 -0
- iatoolkit/common/interfaces/__init__.py +0 -0
- iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit/common/interfaces/database_provider.py +39 -0
- iatoolkit/common/model_registry.py +159 -0
- iatoolkit/common/routes.py +138 -0
- iatoolkit/common/session_manager.py +26 -0
- iatoolkit/common/util.py +353 -0
- iatoolkit/company_registry.py +66 -29
- iatoolkit/core.py +514 -0
- iatoolkit/infra/__init__.py +5 -0
- iatoolkit/infra/brevo_mail_app.py +123 -0
- iatoolkit/infra/call_service.py +140 -0
- iatoolkit/infra/connectors/__init__.py +5 -0
- iatoolkit/infra/connectors/file_connector.py +17 -0
- iatoolkit/infra/connectors/file_connector_factory.py +57 -0
- iatoolkit/infra/connectors/google_cloud_storage_connector.py +53 -0
- iatoolkit/infra/connectors/google_drive_connector.py +68 -0
- iatoolkit/infra/connectors/local_file_connector.py +46 -0
- iatoolkit/infra/connectors/s3_connector.py +33 -0
- iatoolkit/infra/google_chat_app.py +57 -0
- iatoolkit/infra/llm_providers/__init__.py +0 -0
- iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
- iatoolkit/infra/llm_providers/gemini_adapter.py +350 -0
- iatoolkit/infra/llm_providers/openai_adapter.py +124 -0
- iatoolkit/infra/llm_proxy.py +268 -0
- iatoolkit/infra/llm_response.py +45 -0
- iatoolkit/infra/redis_session_manager.py +122 -0
- iatoolkit/locales/en.yaml +222 -0
- iatoolkit/locales/es.yaml +225 -0
- iatoolkit/repositories/__init__.py +5 -0
- iatoolkit/repositories/database_manager.py +187 -0
- iatoolkit/repositories/document_repo.py +33 -0
- iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- iatoolkit/repositories/llm_query_repo.py +105 -0
- iatoolkit/repositories/models.py +279 -0
- iatoolkit/repositories/profile_repo.py +171 -0
- iatoolkit/repositories/vs_repo.py +150 -0
- iatoolkit/services/__init__.py +5 -0
- iatoolkit/services/auth_service.py +193 -0
- {services → iatoolkit/services}/benchmark_service.py +7 -7
- iatoolkit/services/branding_service.py +153 -0
- iatoolkit/services/company_context_service.py +214 -0
- iatoolkit/services/configuration_service.py +375 -0
- iatoolkit/services/dispatcher_service.py +134 -0
- {services → iatoolkit/services}/document_service.py +20 -8
- iatoolkit/services/embedding_service.py +148 -0
- iatoolkit/services/excel_service.py +156 -0
- {services → iatoolkit/services}/file_processor_service.py +36 -21
- iatoolkit/services/history_manager_service.py +208 -0
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +80 -0
- iatoolkit/services/language_service.py +89 -0
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/services/llm_client_service.py +438 -0
- iatoolkit/services/load_documents_service.py +174 -0
- iatoolkit/services/mail_service.py +213 -0
- {services → iatoolkit/services}/profile_service.py +200 -101
- iatoolkit/services/prompt_service.py +303 -0
- iatoolkit/services/query_service.py +467 -0
- iatoolkit/services/search_service.py +55 -0
- iatoolkit/services/sql_service.py +169 -0
- iatoolkit/services/tool_service.py +246 -0
- iatoolkit/services/user_feedback_service.py +117 -0
- iatoolkit/services/user_session_context_service.py +213 -0
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +0 -0
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_filepond.js +85 -0
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +110 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +401 -0
- iatoolkit/static/js/chat_model_selector.js +227 -0
- iatoolkit/static/js/chat_onboarding_button.js +103 -0
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +38 -0
- iatoolkit/static/styles/chat_iatoolkit.css +559 -0
- iatoolkit/static/styles/chat_modal.css +133 -0
- iatoolkit/static/styles/chat_public.css +135 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +398 -0
- iatoolkit/static/styles/llm_output.css +148 -0
- iatoolkit/static/styles/onboarding.css +176 -0
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +30 -23
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +45 -0
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/base.html +78 -0
- iatoolkit/templates/change_password.html +66 -0
- iatoolkit/templates/chat.html +337 -0
- iatoolkit/templates/chat_modals.html +185 -0
- iatoolkit/templates/error.html +51 -0
- iatoolkit/templates/forgot_password.html +51 -0
- iatoolkit/templates/onboarding_shell.html +106 -0
- iatoolkit/templates/signup.html +79 -0
- iatoolkit/views/__init__.py +5 -0
- iatoolkit/views/base_login_view.py +96 -0
- iatoolkit/views/change_password_view.py +116 -0
- iatoolkit/views/chat_view.py +76 -0
- iatoolkit/views/embedding_api_view.py +65 -0
- iatoolkit/views/forgot_password_view.py +75 -0
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +56 -0
- iatoolkit/views/home_view.py +63 -0
- iatoolkit/views/init_context_api_view.py +74 -0
- iatoolkit/views/llmquery_api_view.py +59 -0
- iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit/views/load_document_api_view.py +65 -0
- iatoolkit/views/login_view.py +170 -0
- iatoolkit/views/logout_api_view.py +57 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +37 -0
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +100 -0
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/user_feedback_api_view.py +60 -0
- iatoolkit/views/users_api_view.py +33 -0
- iatoolkit/views/verify_user_view.py +60 -0
- iatoolkit-0.107.4.dist-info/METADATA +268 -0
- iatoolkit-0.107.4.dist-info/RECORD +132 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE +21 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/top_level.txt +0 -1
- iatoolkit/iatoolkit.py +0 -413
- iatoolkit/system_prompts/arquitectura.prompt +0 -32
- iatoolkit-0.3.9.dist-info/METADATA +0 -252
- iatoolkit-0.3.9.dist-info/RECORD +0 -32
- services/__init__.py +0 -5
- services/api_service.py +0 -75
- services/dispatcher_service.py +0 -351
- services/excel_service.py +0 -98
- services/history_service.py +0 -45
- services/jwt_service.py +0 -91
- services/load_documents_service.py +0 -212
- services/mail_service.py +0 -62
- services/prompt_manager_service.py +0 -172
- services/query_service.py +0 -334
- services/search_service.py +0 -32
- services/sql_service.py +0 -42
- services/tasks_service.py +0 -188
- services/user_feedback_service.py +0 -67
- services/user_session_context_service.py +0 -85
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
$(document).ready(function () {
|
|
2
|
+
const paperclipButton = $('#paperclip-button');
|
|
3
|
+
const viewFilesButtonContainer = $('#view-files-button-container');
|
|
4
|
+
const viewFilesButton = $('#view-files-button');
|
|
5
|
+
const uploadedFilesModalElement = $('#uploadedFilesModal');
|
|
6
|
+
const uploadedFilesModal = uploadedFilesModalElement; // En Bootstrap 3, el elemento jQuery es el modal
|
|
7
|
+
const uploadedFilesList = $('#uploaded-files-list');
|
|
8
|
+
|
|
9
|
+
// Initialize FilePond
|
|
10
|
+
window.filePond = FilePond.create(
|
|
11
|
+
document.querySelector('#file-upload'), {
|
|
12
|
+
allowMultiple: true,
|
|
13
|
+
labelIdle: '',
|
|
14
|
+
credits: false,
|
|
15
|
+
allowFileSizeValidation: true,
|
|
16
|
+
maxFileSize: '10MB',
|
|
17
|
+
stylePanelLayout: null,
|
|
18
|
+
itemInsertLocation: 'after',
|
|
19
|
+
instantUpload: false,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
$('.filepond--root').hide(); // Ocultar la UI de FilePond
|
|
23
|
+
|
|
24
|
+
// Función para actualizar la visibilidad del icono "ver archivos"
|
|
25
|
+
function updateFileIconsVisibility() {
|
|
26
|
+
const files = filePond.getFiles();
|
|
27
|
+
if (files.length > 0) {
|
|
28
|
+
viewFilesButtonContainer.show();
|
|
29
|
+
} else {
|
|
30
|
+
viewFilesButtonContainer.hide();
|
|
31
|
+
if (uploadedFilesModalElement.hasClass('in')) { // Si el modal está abierto y no hay archivos, ciérralo
|
|
32
|
+
uploadedFilesModal.modal('hide');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Función para poblar el modal con los archivos y botones de eliminar
|
|
38
|
+
function populateFilesModal() {
|
|
39
|
+
uploadedFilesList.empty(); // Limpiar lista anterior
|
|
40
|
+
const files = filePond.getFiles();
|
|
41
|
+
|
|
42
|
+
if (files.length === 0) {
|
|
43
|
+
uploadedFilesList.append('<li class="list-group-item">No hay archivos adjuntos.</li>');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
files.forEach(file => {
|
|
48
|
+
const listItem = $(`
|
|
49
|
+
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
50
|
+
<span class="file-name-modal">${file.filename}</span>
|
|
51
|
+
<button type="button" class="btn btn-sm btn-outline-danger remove-file-btn" data-file-id="${file.id}" title="Eliminar archivo">
|
|
52
|
+
<i class="bi bi-trash-fill"></i>
|
|
53
|
+
</button>
|
|
54
|
+
</li>
|
|
55
|
+
`);
|
|
56
|
+
uploadedFilesList.append(listItem);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Event listeners de FilePond
|
|
61
|
+
window.filePond.on('addfile', () => updateFileIconsVisibility());
|
|
62
|
+
window.filePond.on('removefile', () => {
|
|
63
|
+
updateFileIconsVisibility();
|
|
64
|
+
if (uploadedFilesModalElement.hasClass('in')) {
|
|
65
|
+
populateFilesModal();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Event listeners de los botones de la UI
|
|
70
|
+
paperclipButton.on('click', () => window.filePond.browse());
|
|
71
|
+
viewFilesButton.on('click', () => {
|
|
72
|
+
populateFilesModal();
|
|
73
|
+
uploadedFilesModal.modal('show');
|
|
74
|
+
});
|
|
75
|
+
uploadedFilesList.on('click', '.remove-file-btn', function () {
|
|
76
|
+
const fileIdToRemove = $(this).data('file-id');
|
|
77
|
+
if (fileIdToRemove) {
|
|
78
|
+
window.filePond.removeFile(fileIdToRemove);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Inicializar visibilidad al cargar
|
|
83
|
+
updateFileIconsVisibility();
|
|
84
|
+
});
|
|
85
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
$(document).ready(function () {
|
|
2
|
+
|
|
3
|
+
let helpContent = null; // Variable para cachear el contenido de ayuda
|
|
4
|
+
|
|
5
|
+
// Evento de clic en el botón de ayuda
|
|
6
|
+
$('#open-help-button').on('click', async function () {
|
|
7
|
+
const helpModal = new bootstrap.Modal(document.getElementById('helpModal'));
|
|
8
|
+
const accordionContainer = $('#help-accordion-container');
|
|
9
|
+
const spinner = $('#help-spinner');
|
|
10
|
+
|
|
11
|
+
// Si el contenido no se ha cargado, hacer la llamada a la API
|
|
12
|
+
if (helpContent) {
|
|
13
|
+
// Si el contenido ya está cacheado, solo muestra el modal
|
|
14
|
+
helpModal.show();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
spinner.show();
|
|
19
|
+
accordionContainer.hide();
|
|
20
|
+
helpModal.show();
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const helpContent = await callToolkit('/api/help-content', {}, "POST");
|
|
24
|
+
|
|
25
|
+
if (!helpContent) {
|
|
26
|
+
toastr.error('No se pudo cargar la guía de uso. Por favor, intente más tarde.');
|
|
27
|
+
spinner.hide();
|
|
28
|
+
helpModal.hide();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Construir el HTML del acordeón y mostrarlo
|
|
33
|
+
buildHelpAccordion(helpContent);
|
|
34
|
+
spinner.hide();
|
|
35
|
+
accordionContainer.show();
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error("Error al cargar el contenido de ayuda:", error);
|
|
39
|
+
toastr.error('Ocurrió un error de red al cargar la guía.');
|
|
40
|
+
spinner.hide();
|
|
41
|
+
helpModal.hide();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Construye dinámicamente el HTML para el acordeón de ayuda a partir de los datos.
|
|
47
|
+
* @param {object} data El objeto JSON con el contenido de ayuda.
|
|
48
|
+
*/
|
|
49
|
+
function buildHelpAccordion(data) {
|
|
50
|
+
const container = $('#help-accordion-container');
|
|
51
|
+
container.empty(); // Limpiar cualquier contenido previo
|
|
52
|
+
|
|
53
|
+
let accordionHtml = '';
|
|
54
|
+
|
|
55
|
+
if (data.example_questions) {
|
|
56
|
+
let contentHtml = '';
|
|
57
|
+
data.example_questions.forEach(cat => {
|
|
58
|
+
contentHtml += `<h6 class="fw-bold">${cat.category}</h6><ul>`;
|
|
59
|
+
cat.questions.forEach(q => contentHtml += `<li>${q}</li>`);
|
|
60
|
+
contentHtml += `</ul>`;
|
|
61
|
+
});
|
|
62
|
+
accordionHtml += createAccordionItem('examples', 'Sample questions', contentHtml, true);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (data.data_sources) {
|
|
66
|
+
let contentHtml = '<dl>';
|
|
67
|
+
data.data_sources.forEach(p => {
|
|
68
|
+
contentHtml += `<dt>${p.source}</dt><dd>${p.description}</dd>`;
|
|
69
|
+
});
|
|
70
|
+
contentHtml += `</dl>`;
|
|
71
|
+
accordionHtml += createAccordionItem('sources', 'Data available', contentHtml );
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (data.best_practices) {
|
|
75
|
+
let contentHtml = '<dl>';
|
|
76
|
+
data.best_practices.forEach(p => {
|
|
77
|
+
contentHtml += `<dt>${p.title}</dt><dd>${p.description}`;
|
|
78
|
+
if (p.example) {
|
|
79
|
+
contentHtml += `<br><small class="text-muted"><em>Ej: "${p.example}"</em></small>`;
|
|
80
|
+
}
|
|
81
|
+
contentHtml += `</dd>`;
|
|
82
|
+
});
|
|
83
|
+
contentHtml += `</dl>`;
|
|
84
|
+
accordionHtml += createAccordionItem('practices', 'Best practices', contentHtml);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (data.capabilities) {
|
|
88
|
+
let contentHtml = `<div class="row">`;
|
|
89
|
+
contentHtml += `<div class="col-md-6"><h6 class="fw-bold">Puede hacer:</h6><ul>${data.capabilities.can_do.map(item => `<li>${item}</li>`).join('')}</ul></div>`;
|
|
90
|
+
contentHtml += `<div class="col-md-6"><h6 class="fw-bold">No puede hacer:</h6><ul>${data.capabilities.cannot_do.map(item => `<li>${item}</li>`).join('')}</ul></div>`;
|
|
91
|
+
contentHtml += `</div>`;
|
|
92
|
+
accordionHtml += createAccordionItem('capabilities', 'Capabilities and limits', contentHtml);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
container.html(accordionHtml);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Helper para crear un item del acordeón de Bootstrap.
|
|
100
|
+
* @param {string} id El ID base para los elementos.
|
|
101
|
+
* @param {string} title El título que se muestra en el botón del acordeón.
|
|
102
|
+
* @param {string} contentHtml El HTML que va dentro del cuerpo colapsable.
|
|
103
|
+
* @param {boolean} isOpen Si el item debe estar abierto por defecto.
|
|
104
|
+
* @returns {string} El string HTML del item del acordeón.
|
|
105
|
+
*/
|
|
106
|
+
function createAccordionItem(id, title, contentHtml, isOpen = false) {
|
|
107
|
+
const showClass = isOpen ? 'show' : '';
|
|
108
|
+
const collapsedClass = isOpen ? '' : 'collapsed';
|
|
109
|
+
|
|
110
|
+
return `
|
|
111
|
+
<div class="accordion-item">
|
|
112
|
+
<h2 class="accordion-header" id="heading-${id}">
|
|
113
|
+
<button class="accordion-button ${collapsedClass}" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-${id}" aria-expanded="${isOpen}" aria-controls="collapse-${id}">
|
|
114
|
+
${title}
|
|
115
|
+
</button>
|
|
116
|
+
</h2>
|
|
117
|
+
<div id="collapse-${id}" class="accordion-collapse collapse ${showClass}" aria-labelledby="heading-${id}" data-bs-parent="#help-accordion-container">
|
|
118
|
+
<div class="accordion-body">
|
|
119
|
+
${contentHtml}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>`;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
$(document).ready(function () {
|
|
2
|
+
// Evento para abrir el modal de historial
|
|
3
|
+
const historyModal = $('#historyModal');
|
|
4
|
+
|
|
5
|
+
$('#history-button').on('click', function() {
|
|
6
|
+
historyModal.modal('show');
|
|
7
|
+
loadHistory();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// Función para cargar el historial
|
|
12
|
+
async function loadHistory() {
|
|
13
|
+
const historyLoading = $('#history-loading');
|
|
14
|
+
const historyContent = $('#history-content');
|
|
15
|
+
const historyTable = historyContent.find('table');
|
|
16
|
+
const noHistoryMessage = $('#no-history-message');
|
|
17
|
+
|
|
18
|
+
// prepare UI for loading
|
|
19
|
+
historyLoading.show();
|
|
20
|
+
historyContent.hide();
|
|
21
|
+
historyTable.show();
|
|
22
|
+
noHistoryMessage.hide();
|
|
23
|
+
|
|
24
|
+
// cal the toolkit, handle the response and errors
|
|
25
|
+
const data = await callToolkit("/api/history", {}, "POST");
|
|
26
|
+
|
|
27
|
+
if (!data || !data.history) {
|
|
28
|
+
historyLoading.hide();
|
|
29
|
+
toastr.error(t_js('error_loading_history'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (data.history.length === 0) {
|
|
34
|
+
historyTable.hide();
|
|
35
|
+
noHistoryMessage.show();
|
|
36
|
+
} else
|
|
37
|
+
displayAllHistory(data.history);
|
|
38
|
+
|
|
39
|
+
historyLoading.hide();
|
|
40
|
+
historyContent.show();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Función para mostrar todo el historial
|
|
44
|
+
function displayAllHistory(historyData) {
|
|
45
|
+
const historyTableBody = $('#history-table-body');
|
|
46
|
+
|
|
47
|
+
historyTableBody.empty();
|
|
48
|
+
|
|
49
|
+
// Filtrar solo consultas que son strings simples
|
|
50
|
+
const filteredHistory = historyData.filter(item => {
|
|
51
|
+
try {
|
|
52
|
+
JSON.parse(item.query);
|
|
53
|
+
return false;
|
|
54
|
+
} catch (e) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Poblar la tabla
|
|
60
|
+
filteredHistory.forEach((item, index) => {
|
|
61
|
+
const icon = $('<i>').addClass('bi bi-pencil-fill');
|
|
62
|
+
|
|
63
|
+
const edit_link = $('<a>')
|
|
64
|
+
.attr('href', 'javascript:void(0);')
|
|
65
|
+
.addClass('edit-pencil')
|
|
66
|
+
.attr('title', t_js('edit_query'))
|
|
67
|
+
.data('query', item.query)
|
|
68
|
+
.append(icon);
|
|
69
|
+
|
|
70
|
+
const row = $('<tr>').append(
|
|
71
|
+
$('<td>').addClass('text-nowrap').text(formatDate(item.created_at)),
|
|
72
|
+
$('<td>').text(item.query),
|
|
73
|
+
$('<td>').append(edit_link),
|
|
74
|
+
);
|
|
75
|
+
historyTableBody.append(row);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function formatDate(dateString) {
|
|
80
|
+
const date = new Date(dateString);
|
|
81
|
+
const padTo2Digits = (num) => num.toString().padStart(2, '0');
|
|
82
|
+
|
|
83
|
+
const day = padTo2Digits(date.getDate());
|
|
84
|
+
const month = padTo2Digits(date.getMonth() + 1);
|
|
85
|
+
const year = date.getFullYear();
|
|
86
|
+
const hours = padTo2Digits(date.getHours());
|
|
87
|
+
const minutes = padTo2Digits(date.getMinutes());
|
|
88
|
+
|
|
89
|
+
return `${day}-${month} ${hours}:${minutes}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// event handler for the edit pencil icon
|
|
93
|
+
$('#history-table-body').on('click', '.edit-pencil', function() {
|
|
94
|
+
const queryText = $(this).data('query');
|
|
95
|
+
|
|
96
|
+
// copy the text to the chat input box
|
|
97
|
+
if (queryText) {
|
|
98
|
+
$('#question').val(queryText);
|
|
99
|
+
autoResizeTextarea($('#question')[0]);
|
|
100
|
+
$('#send-button').removeClass('disabled');
|
|
101
|
+
|
|
102
|
+
// Cerrar el modal
|
|
103
|
+
$('#historyModal').modal('hide');
|
|
104
|
+
|
|
105
|
+
// Hacer focus en el textarea
|
|
106
|
+
if (window.innerWidth > 768)
|
|
107
|
+
$('#question').focus();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
2
|
+
const logoutButton = document.getElementById('logout-button');
|
|
3
|
+
if (!logoutButton) {
|
|
4
|
+
console.warn('El botón de logout con id "logout-button" no fue encontrado.');
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (window.toastr) {
|
|
9
|
+
toastr.options = { "positionClass": "toast-bottom-right", "preventDuplicates": true };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
logoutButton.addEventListener('click', async function(event) {
|
|
13
|
+
event.preventDefault();
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const apiPath = '/api/logout';
|
|
17
|
+
const data = await callToolkit(apiPath, null, 'GET');
|
|
18
|
+
|
|
19
|
+
// Procesar la respuesta
|
|
20
|
+
if (data && data.status === 'success' && data.url) {
|
|
21
|
+
window.top.location.href = data.url;
|
|
22
|
+
} else {
|
|
23
|
+
// Si algo falla, callToolkit usualmente muestra un error.
|
|
24
|
+
// Mostramos un toast como fallback.
|
|
25
|
+
if (window.toastr) {
|
|
26
|
+
toastr.error('No se pudo procesar el cierre de sesión. Por favor, intente de nuevo.');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('Error durante el logout:', error);
|
|
31
|
+
if (window.toastr) {
|
|
32
|
+
toastr.error('Ocurrió un error de red al intentar cerrar sesión.');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|