From 000636a2291cd0dffeb12cb3b67591767a33b670 Mon Sep 17 00:00:00 2001 From: Josako Date: Mon, 14 Jul 2025 18:58:54 +0200 Subject: [PATCH] - Changes to the list views - now using tabulator with filtering and sorting, client-side pagination, ... - Adaptation of all list views in the app --- common/models/document.py | 6 + common/utils/nginx_utils.py | 13 +- .../static/assets/css/eveai-tabulator.css | 42 +- eveai_app/static/assets/js/eveai-list-view.js | 183 +++++ .../static/assets/js/eveai-tabulator-setup.js | 83 ++ eveai_app/templates/base.html | 1 + eveai_app/templates/document/catalogs.html | 27 - .../templates/document/document_versions.html | 27 - .../document/document_versions_list_view.html | 94 --- eveai_app/templates/document/documents.html | 95 --- .../templates/document/full_documents.html | 114 --- eveai_app/templates/document/processors.html | 26 - eveai_app/templates/document/retrievers.html | 26 - .../entitlements/view_license_tiers.html | 36 - .../templates/entitlements/view_licenses.html | 28 - eveai_app/templates/eveai_list_view.html | 726 +++++++++++------- eveai_app/templates/interaction/assets.html | 97 --- .../templates/interaction/chat_sessions.html | 26 - .../interaction/specialist_magic_links.html | 26 - .../templates/interaction/specialists.html | 77 -- eveai_app/templates/list_view.html | 82 ++ eveai_app/templates/navbar.html | 10 +- .../templates/partner/partner_services.html | 27 - eveai_app/templates/partner/partners.html | 27 - eveai_app/templates/scripts.html | 7 +- eveai_app/templates/user/select_tenant.html | 55 -- eveai_app/templates/user/tenant_makes.html | 26 - eveai_app/templates/user/tenant_projects.html | 28 - .../templates/user/view_tenant_domains.html | 2 +- eveai_app/templates/user/view_users.html | 27 - eveai_app/views/document_views.py | 211 +---- eveai_app/views/entitlements_views.py | 135 +--- eveai_app/views/interaction_views.py | 87 +-- eveai_app/views/list_views/__init__.py | 2 + .../views/list_views/assets_list_view.py | 83 -- .../views/list_views/document_list_view.py | 81 -- .../views/list_views/document_list_views.py | 324 ++++++++ .../list_views/document_version_list_view.py | 83 -- .../list_views/entitlement_list_views.py | 164 ++++ .../views/list_views/filtered_list_view.py | 54 -- .../list_views/full_document_list_view.py | 178 ----- .../list_views/interaction_list_views.py | 198 +++++ eveai_app/views/list_views/list_view_utils.py | 92 +++ .../views/list_views/partner_list_views.py | 129 ++++ eveai_app/views/list_views/user_list_views.py | 234 ++++++ eveai_app/views/partner_views.py | 39 +- eveai_app/views/security_views.py | 2 +- eveai_app/views/user_views.py | 147 +--- nginx/frontend_src/js/main.js | 20 + nginx/frontend_src/js/tabulator-setup.js | 29 +- 50 files changed, 2162 insertions(+), 2174 deletions(-) create mode 100644 eveai_app/static/assets/js/eveai-list-view.js create mode 100644 eveai_app/static/assets/js/eveai-tabulator-setup.js delete mode 100644 eveai_app/templates/document/catalogs.html delete mode 100644 eveai_app/templates/document/document_versions.html delete mode 100644 eveai_app/templates/document/document_versions_list_view.html delete mode 100644 eveai_app/templates/document/documents.html delete mode 100644 eveai_app/templates/document/full_documents.html delete mode 100644 eveai_app/templates/document/processors.html delete mode 100644 eveai_app/templates/document/retrievers.html delete mode 100644 eveai_app/templates/entitlements/view_license_tiers.html delete mode 100644 eveai_app/templates/entitlements/view_licenses.html delete mode 100644 eveai_app/templates/interaction/assets.html delete mode 100644 eveai_app/templates/interaction/chat_sessions.html delete mode 100644 eveai_app/templates/interaction/specialist_magic_links.html delete mode 100644 eveai_app/templates/interaction/specialists.html create mode 100644 eveai_app/templates/list_view.html delete mode 100644 eveai_app/templates/partner/partner_services.html delete mode 100644 eveai_app/templates/partner/partners.html delete mode 100644 eveai_app/templates/user/select_tenant.html delete mode 100644 eveai_app/templates/user/tenant_makes.html delete mode 100644 eveai_app/templates/user/tenant_projects.html delete mode 100644 eveai_app/templates/user/view_users.html delete mode 100644 eveai_app/views/list_views/assets_list_view.py delete mode 100644 eveai_app/views/list_views/document_list_view.py create mode 100644 eveai_app/views/list_views/document_list_views.py delete mode 100644 eveai_app/views/list_views/document_version_list_view.py create mode 100644 eveai_app/views/list_views/entitlement_list_views.py delete mode 100644 eveai_app/views/list_views/filtered_list_view.py delete mode 100644 eveai_app/views/list_views/full_document_list_view.py create mode 100644 eveai_app/views/list_views/interaction_list_views.py create mode 100644 eveai_app/views/list_views/list_view_utils.py create mode 100644 eveai_app/views/list_views/partner_list_views.py create mode 100644 eveai_app/views/list_views/user_list_views.py diff --git a/common/models/document.py b/common/models/document.py index 3a92d23..de688ad 100644 --- a/common/models/document.py +++ b/common/models/document.py @@ -105,6 +105,12 @@ class Document(db.Model): # Relations versions = db.relationship('DocumentVersion', backref='document', lazy=True) + @property + def latest_version(self): + """Returns the latest document version (the one with highest id)""" + from sqlalchemy import desc + return DocumentVersion.query.filter_by(doc_id=self.id).order_by(desc(DocumentVersion.id)).first() + def __repr__(self): return f"" diff --git a/common/utils/nginx_utils.py b/common/utils/nginx_utils.py index c20d586..1a5771b 100644 --- a/common/utils/nginx_utils.py +++ b/common/utils/nginx_utils.py @@ -12,7 +12,16 @@ def prefixed_url_for(endpoint, **values): if external: path, query, fragment = urlsplit(generated_url)[2:5] - new_path = prefix + path + # Check if the prefix is already present in the path + if prefix and not path.startswith(prefix): + new_path = prefix + path + else: + new_path = path return urlunsplit((scheme, host, new_path, query, fragment)) else: - return prefix + generated_url \ No newline at end of file + # Check if the prefix is already present in the generated URL + if prefix and not generated_url.startswith(prefix): + return prefix + generated_url + else: + return generated_url + diff --git a/eveai_app/static/assets/css/eveai-tabulator.css b/eveai_app/static/assets/css/eveai-tabulator.css index 297a391..9a50bfe 100644 --- a/eveai_app/static/assets/css/eveai-tabulator.css +++ b/eveai_app/static/assets/css/eveai-tabulator.css @@ -96,9 +96,9 @@ /* Style for the table header */ .ordered-list-editor .tabulator-header { - background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%); /* Match JSE gradient */ + background: #e1e1e1; border-bottom: 2px solid var(--bs-secondary); /* Secondary color for border */ - color: #ffffff; /* White text for better contrast on gradient */ + color: #ffffff; } /* Style for the headers container */ @@ -108,14 +108,14 @@ /* Style for the header cells */ .ordered-list-editor .tabulator-col { - background: transparent; /* Let the header gradient show through */ + background: transparent; padding: 8px; font-weight: bold; text-align: center; display: table-cell !important; /* Force display as table cell */ box-sizing: border-box !important; /* Include padding in width calculation */ position: relative !important; /* Ensure proper positioning */ - color: #ffffff; /* White text for better contrast on gradient */ + color: #ffffff; } /* Override any inline styles that might hide column headers */ @@ -135,7 +135,7 @@ word-break: break-word; /* Break words to prevent horizontal overflow */ font-weight: bold; font-size: 0.85rem; /* Kleinere font grootte, dezelfde als in de rijen */ - color: #ffffff; /* White text for better contrast on gradient */ + color: #ffffff; } /* Style for the table rows */ @@ -385,7 +385,7 @@ } /* Extra specifieke override stijlen voor tabulator paginator en footer */ .tabulator .tabulator-footer .tabulator-paginator { - background: transparent !important; /* Transparante achtergrond, want de footer heeft al gradient */ + background: transparent !important; border-top: none !important; padding: 0 !important; } @@ -407,14 +407,14 @@ border-radius: 4px !important; border: 1px solid white !important; background-color: rgba(255, 255, 255, 0.2) !important; - color: white !important; + color: #67518c !important; font-size: 0.85rem !important; font-family: inherit !important; } /* Styling voor de paginator container */ .tabulator .tabulator-footer .tabulator-paginator label { - color: white !important; /* Witte tekst voor betere leesbaarheid op donkere gradient */ + color: #67518c !important; font-size: 0.85rem !important; font-weight: normal !important; margin: 0 5px !important; @@ -465,7 +465,7 @@ } /* Styling voor de tabulator paginator -------------------------------------------------------------- */ .tabulator-paginator { - background: linear-gradient(90deg, var(--bs-secondary) 0%, var(--bs-primary) 100%) !important; /* Omgekeerde gradient van de header */ + background: #e1e1e1; padding: 10px; border-bottom-left-radius: 0.375rem; border-bottom-right-radius: 0.375rem; @@ -485,13 +485,13 @@ .tabulator-paginator .tabulator-page:hover { background-color: var(--bs-secondary); - color: white; + color: #67518c; } .tabulator-paginator .tabulator-page.active, .tabulator .tabulator-footer .tabulator-page.active { background-color: var(--bs-primary) !important; - color: white !important; + color: #67518c !important; border-color: var(--bs-primary) !important; } @@ -515,7 +515,7 @@ .tabulator-footer, .tabulator .tabulator-footer { - background: linear-gradient(90deg, var(--bs-secondary) 0%, var(--bs-primary) 100%) !important; /* Omgekeerde gradient van de header */ + background: #e1e1e1; border-top: 1px solid var(--bs-secondary) !important; border-bottom-left-radius: 0.375rem !important; border-bottom-right-radius: 0.375rem !important; @@ -548,7 +548,7 @@ /* Algemene tabulator header stijlen -------------------------------------------------------------- */ .tabulator .tabulator-header { - background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%); + background: #e1e1e1; border-bottom: 2px solid var(--bs-secondary); color: #ffffff; } @@ -579,7 +579,7 @@ } .tabulator .tabulator-header .tabulator-col-title { - color: #ffffff; + color: #67518c; font-weight: bold; } @@ -588,7 +588,7 @@ } .tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title { - color: #ffffff; + color: #67518c; font-size: 0.85rem; /* Kleinere font grootte, dezelfde als in de rijen */ } @@ -607,7 +607,7 @@ /* Tabulator List View paginator stijlen */ .tabulator-list-view .tabulator-footer { - background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%); /* Match EveAI gradient */ + background: #e1e1e1; padding: 8px; border-bottom-left-radius: 0.375rem; border-bottom-right-radius: 0.375rem; @@ -635,20 +635,20 @@ /* Stijl voor de tabel header */ .tabulator-list-view .tabulator-header { - background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%); /* Match EveAI gradient */ + background: #e1e1e1; border-bottom: 2px solid var(--bs-secondary); /* Secundaire kleur voor rand */ - color: #ffffff; /* Witte tekst voor beter contrast op gradient */ + color: #ffffff; } /* Stijl voor de header cellen */ .tabulator-list-view .tabulator-col { - background: transparent; /* Laat de header gradient doorschijnen */ + background: transparent; padding: 8px; font-weight: bold; text-align: center; box-sizing: border-box !important; /* Padding meenemen in breedte berekening */ position: relative !important; /* Juiste positionering verzekeren */ - color: #ffffff; /* Witte tekst voor beter contrast op gradient */ + color: #ffffff; } /* Voorkom kleurverandering bij hover over kolomkoppen */ @@ -662,7 +662,7 @@ word-break: break-word; /* Breek woorden om horizontale overflow te voorkomen */ font-weight: bold; font-size: 0.85rem; /* Kleinere font grootte, dezelfde als in de rijen */ - color: #ffffff; /* Witte tekst voor beter contrast op gradient */ + color: #ffffff; } /* Stijl voor de tabel rijen */ diff --git a/eveai_app/static/assets/js/eveai-list-view.js b/eveai_app/static/assets/js/eveai-list-view.js new file mode 100644 index 0000000..31cdc76 --- /dev/null +++ b/eveai_app/static/assets/js/eveai-list-view.js @@ -0,0 +1,183 @@ +/** + * EveAI List View Component + * JavaScript functionaliteit voor het beheren van lijst-weergaven + */ + +// Namespace aanmaken als deze nog niet bestaat +if (typeof window.EveAI === 'undefined') { + window.EveAI = {}; +} + +// List View namespace +window.EveAI.ListView = { + // Opslag voor lijst-view instanties + instances: {}, + + /** + * Initialiseer een Tabulator lijst-view + * @param {string} elementId - ID van het HTML element + * @param {object} config - Configuratie object voor Tabulator + * @returns {Tabulator} - Tabulator instantie + */ + initialize: function(elementId, config) { + // Combineer standaard configuratie met aangepaste configuratie + const defaultConfig = { + height: 600, + layout: "fitColumns", + selectable: true, + movableColumns: true, + pagination: "local", + paginationSize: 15, + paginationSizeSelector: [10, 15, 20, 50, 100], + }; + + const tableConfig = {...defaultConfig, ...config}; + + // Voeg rij selectie event toe + tableConfig.rowSelectionChanged = (data, rows) => { + console.log("Rij selectie gewijzigd:", rows.length, "rijen geselecteerd"); + + // Update de geselecteerde rij in onze instance + if (this.instances[elementId]) { + this.instances[elementId].selectedRow = rows.length > 0 ? rows[0].getData() : null; + this.updateActionButtons(elementId); + } + }; + + // Initialiseer de Tabulator + try { + const table = new Tabulator(`#${elementId}`, tableConfig); + + // Bewaar de instance + this.instances[elementId] = { + table: table, + config: config || {}, + selectedRow: null + }; + + // Bij initialisatie, update de knoppen (standaard inactief voor requiresSelection=true) + setTimeout(() => { + this.updateActionButtons(elementId); + }, 0); + + return table; + } catch (error) { + console.error(`Fout bij het initialiseren van Tabulator voor ${elementId}:`, error); + return null; + } + }, + + /** + * Afhandelen van actieknoppen + * @param {string} action - Actie identifier + * @param {boolean} requiresSelection - Of de actie een selectie vereist + * @param {string} tableId - ID van de tabel + * @returns {boolean} - Succes indicator + */ + /** + * Update actieknoppen op basis van geselecteerde rij + * @param {string} tableId - ID van de tabel + */ + updateActionButtons: function(tableId) { + const instance = this.instances[tableId]; + if (!instance) return; + + const container = document.getElementById(tableId); + if (!container) return; + + const buttons = container.parentElement.querySelectorAll('button[onclick*="handleListViewAction"]'); + + buttons.forEach(button => { + // Parse de onclick attribuut om de actiewaarde te krijgen + const onclickAttr = button.getAttribute('onclick'); + const match = onclickAttr.match(/handleListViewAction\('([^']+)'/); + if (match) { + const actionValue = match[1]; + // Vind de actie in de configuratie + const action = instance.config.actions.find(a => a.value === actionValue); + if (action && action.requiresSelection === true) { + // Schakel de knop in/uit op basis van selectie + button.disabled = !instance.selectedRow; + } + } + }); + + // Update de verborgen input met geselecteerde rij data + this._updateSelectedRowInput(tableId); + }, + + /** + * Update de verborgen input met geselecteerde rij gegevens + * @param {string} tableId - ID van de tabel + * @private + */ + _updateSelectedRowInput: function(tableId) { + const instance = this.instances[tableId]; + const hiddenInput = document.getElementById(`${tableId}-selected-row`); + + if (hiddenInput && instance && instance.selectedRow) { + // Bewaar de geselecteerde rij-ID + hiddenInput.value = JSON.stringify({value: instance.selectedRow.id}); + } else if (hiddenInput) { + hiddenInput.value = ''; + } + }, + + handleAction: function(action, requiresSelection, tableId) { + const selectedRowInput = document.getElementById(`${tableId}-selected-row`); + const actionInput = document.getElementById(`${tableId}-action`); + const table = Tabulator.findTable(`#${tableId}`)[0]; + + if (!table) { + console.error(`Tabulator tabel met ID ${tableId} niet gevonden`); + return false; + } + + // Als de actie een selectie vereist, controleer of er een rij is geselecteerd + if (requiresSelection) { + const selectedRows = table.getSelectedRows(); + if (selectedRows.length === 0) { + alert('Selecteer a.u.b. eerst een item uit de lijst.'); + return false; + } + + // Haal de data van de geselecteerde rij op en sla deze op + const rowData = selectedRows[0].getData(); + selectedRowInput.value = JSON.stringify({ value: rowData.id }); + + // Update de instance als deze bestaat + if (this.instances[tableId]) { + this.instances[tableId].selectedRow = rowData; + } + } + + // Stel de actie in en verstuur het formulier + actionInput.value = action; + + // Zoek het juiste formulier en verstuur het + const form = document.getElementById(`${tableId}-form`) || + table.element.closest('form'); + + if (form) { + form.submit(); + return true; + } else { + console.error(`Geen formulier gevonden voor tabel ${tableId}`); + return false; + } + } +}; + +// Functie om beschikbaar te maken in templates +function handleListViewAction(action, requiresSelection) { + // Vind het tableId op basis van de button die is aangeklikt + const target = event?.target || event?.srcElement; + + // Vind het formulier en tableId op basis daarvan + const form = target ? target.closest('form') : null; + const tableId = form ? form.id.replace('-form', '') : 'unknown_table'; + + return window.EveAI.ListView.handleAction(action, requiresSelection, tableId); +} + +console.log('EveAI List View component geladen'); diff --git a/eveai_app/static/assets/js/eveai-tabulator-setup.js b/eveai_app/static/assets/js/eveai-tabulator-setup.js new file mode 100644 index 0000000..64bc642 --- /dev/null +++ b/eveai_app/static/assets/js/eveai-tabulator-setup.js @@ -0,0 +1,83 @@ +/** + * EveAI Tabulator Setup + * Standaard Tabulator configuratie voor consistente tabelweergaven + */ + +document.addEventListener('DOMContentLoaded', function() { + // Controleer of Tabulator is geladen + if (typeof Tabulator !== 'function') { + console.warn('Tabulator is niet geladen - overslaan van initialisatie'); + return; + } + + // Zorg ervoor dat de modules correct zijn gedefinieerd + if (!Tabulator.modules) { + Tabulator.modules = {}; + } + + if (!Tabulator.modules.format) { + Tabulator.modules.format = { formatters: {} }; + } else if (!Tabulator.modules.format.formatters) { + Tabulator.modules.format.formatters = {}; + } + + // Registreer algemene Tabulator opties en formatters + // Gebruik rechtstreekse toewijzing i.p.v. extendModule indien deze functie niet beschikbaar is + if (typeof Tabulator.extendModule === 'function') { + try { + Tabulator.extendModule("format", "formatters", { + // Aangepaste formatter voor boolean waarden met mooie iconen + "boolean": function(cell, formatterParams){ + const value = cell.getValue(); + if (value === true || value === 'true' || value === 1 || value === '1') { + return ''; + } else if (value === false || value === 'false' || value === 0 || value === '0') { + return ''; + } + return ''; // Geef lege string terug voor null/undefined waarden + } + }); + } catch (e) { + console.warn('Fout bij extendModule:', e); + // Fallback: rechtstreeks formatters toevoegen + Tabulator.modules.format.formatters.boolean = function(cell, formatterParams){ + const value = cell.getValue(); + if (value === true || value === 'true' || value === 1 || value === '1') { + return ''; + } else if (value === false || value === 'false' || value === 0 || value === '0') { + return ''; + } + return ''; + }; + } + } else { + // Directe toewijzing als extendModule niet beschikbaar is + Tabulator.modules.format.formatters.boolean = function(cell, formatterParams){ + const value = cell.getValue(); + if (value === true || value === 'true' || value === 1 || value === '1') { + return ''; + } else if (value === false || value === 'false' || value === 0 || value === '0') { + return ''; + } + return ''; + }; + } + + // Definieer standaard tabelconfiguratie + Tabulator.defaultOptions = { + ...Tabulator.defaultOptions, + layout: "fitColumns", + responsiveLayout: false, + pagination: "local", + paginationSize: 25, + paginationSizeSelector: [10, 25, 50, 100], + movableColumns: true, + tooltips: false, + placeholder: "No Data Available", + // Verbeterde virtuele DOM-instellingen voor betere prestaties + renderVerticalBuffer: 20, + virtualDomBuffer: 80 + }; + + console.log('EveAI Tabulator Setup successfully loaded'); +}); diff --git a/eveai_app/templates/base.html b/eveai_app/templates/base.html index 789fc38..aab5399 100644 --- a/eveai_app/templates/base.html +++ b/eveai_app/templates/base.html @@ -1,6 +1,7 @@ + {% include 'head.html' %} diff --git a/eveai_app/templates/document/catalogs.html b/eveai_app/templates/document/catalogs.html deleted file mode 100644 index f7ad3df..0000000 --- a/eveai_app/templates/document/catalogs.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination %} - -{% block title %}Documents{% endblock %} - -{% block content_title %}Catalogs{% endblock %} -{% block content_description %}View Catalogs for Tenant{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} -
-
- {{ render_selectable_table(headers=["Catalog ID", "Name", "Type"], rows=rows, selectable=True, id="catalogsTable") }} -
-
- - -
- -
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.catalogs') }} -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/document/document_versions.html b/eveai_app/templates/document/document_versions.html deleted file mode 100644 index a29c563..0000000 --- a/eveai_app/templates/document/document_versions.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination %} - -{% block title %}Document Versions{% endblock %} - -{% block content_title %}Document Versions{% endblock %} -{% block content_description %}View Versions for Document {{ document }}{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} -
-
- {{ render_selectable_table(headers=["ID", "File Type", "File Size", "Process.", "Proces. Start", "Proces. Finish", "Proces. Error"], rows=rows, selectable=True, id="versionsTable") }} -
-
- - - -
-
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.documents') }} -{% endblock %} diff --git a/eveai_app/templates/document/document_versions_list_view.html b/eveai_app/templates/document/document_versions_list_view.html deleted file mode 100644 index c934068..0000000 --- a/eveai_app/templates/document/document_versions_list_view.html +++ /dev/null @@ -1,94 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination, render_filter_field, render_date_filter_field, render_collapsible_section, render_selectable_sortable_table %} - -{% block title %}Documents{% endblock %} - -{% block content_title %}Document Versions{% endblock %} -{% block content_description %}View Document Versions for Tenant{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} - - {% set filter_form %} -
- {{ render_filter_field('file_type', 'File Type', filter_options['file_type'], filters.get('file_type')) }} - {{ render_filter_field('processing', 'Processing Status', filter_options['processing'], filters.get('processing')) }} - {{ render_filter_field('processing_error', 'Error Status', filter_options['processing_error'], filters.get('processing_error')) }} - {{ render_date_filter_field('start_date', 'Processing Start Date', filters.get('start_date')) }} - {{ render_date_filter_field('end_date', 'Processing End Date', filters.get('end_date')) }} - - -
- {% endset %} - - {{ render_collapsible_section('Filter', 'Filter Options', filter_form) }} - -
-
- - {{ render_selectable_sortable_table( - headers=["ID", "File Type", "Processing", "Processing Start", "Processing Finish", "Processing Error"], - rows=rows, - selectable=True, - id="documentVersionsTable", - sort_by=sort_by, - sort_order=sort_order - ) }} -
-
- - - -
-
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.document_versions_list') }} -{% endblock %} - -{% block scripts %} - -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/document/documents.html b/eveai_app/templates/document/documents.html deleted file mode 100644 index fa0c29f..0000000 --- a/eveai_app/templates/document/documents.html +++ /dev/null @@ -1,95 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination, render_filter_field, render_date_filter_field, render_collapsible_section, render_selectable_sortable_table_with_dict_headers %} - -{% block title %}Documents{% endblock %} - -{% block content_title %}Documents{% endblock %} -{% block content_description %}View Documents for Catalog {% if session.catalog_name %}{{ session.catalog_name }}{% else %}No Catalog{% endif %}{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} - - {% set filter_form %} -
- {{ render_filter_field('validity', 'Validity', filter_options['validity'], filters.get('validity', [])) }} - - -
- {% endset %} - - {{ render_collapsible_section('Filter', 'Filter Options', filter_form) }} - -
-
- - {{ render_selectable_sortable_table_with_dict_headers( - headers=[ - {"text": "ID", "sort": "id"}, - {"text": "Name", "sort": "name"}, - {"text": "Valid From", "sort": "valid_from"}, - {"text": "Valid To", "sort": "valid_to"} - ], - rows=rows, - selectable=True, - id="documentsTable", - sort_by=sort_by, - sort_order=sort_order - ) }} -
-
- - - -
-
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.documents') }} -{% endblock %} - -{% block scripts %} - -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/document/full_documents.html b/eveai_app/templates/document/full_documents.html deleted file mode 100644 index 584eafb..0000000 --- a/eveai_app/templates/document/full_documents.html +++ /dev/null @@ -1,114 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination, render_filter_field, render_date_filter_field, render_collapsible_section, render_selectable_sortable_table_with_dict_headers %} - -{% block title %}Complete Document Overview{% endblock %} - -{% block content_title %}Complete Document Overview{% endblock %} -{% block content_description %}View Documents with Latest Version for Catalog {% if session.catalog_name %}{{ session.catalog_name }}{% else %}No Catalog{% endif %}{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} - - {% set filter_form %} -
- {{ render_filter_field('validity', 'Validity', filter_options['validity'], filters.get('validity', [])) }} - {{ render_filter_field('file_type', 'File Type', filter_options['file_type'], filters.get('file_type', [])) }} - {{ render_filter_field('processing', 'Processing Status', filter_options['processing'], filters.get('processing', [])) }} - {{ render_filter_field('processing_error', 'Error Status', filter_options['processing_error'], filters.get('processing_error', [])) }} - {{ render_date_filter_field('start_date', 'Processing Start Date', filters.get('start_date', [])) }} - {{ render_date_filter_field('end_date', 'Processing End Date', filters.get('end_date', [])) }} - - -
- {% endset %} - - {{ render_collapsible_section('Filter', 'Filter Options', filter_form) }} - -
-
- - - - - {{ render_selectable_sortable_table_with_dict_headers( - headers=[ - {"text": "Document ID", "sort": "id"}, - {"text": "Name", "sort": "name"}, - {"text": "Valid From", "sort": "valid_from"}, - {"text": "Valid To", "sort": "valid_to"}, - {"text": "Version ID", "sort": ""}, - {"text": "File Type", "sort": "file_type"}, - {"text": "Processing", "sort": "processing"}, - {"text": "Error", "sort": "processing_error"} - ], - rows=rows, - selectable=True, - id="fullDocumentsTable", - sort_by=sort_by, - sort_order=sort_order - ) }} -
-
- - - - - - -
-
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.full_documents') }} -{% endblock %} - -{% block scripts %} - -{% endblock %} diff --git a/eveai_app/templates/document/processors.html b/eveai_app/templates/document/processors.html deleted file mode 100644 index 07555fa..0000000 --- a/eveai_app/templates/document/processors.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination %} - -{% block title %}Processors{% endblock %} - -{% block content_title %}Processors{% endblock %} -{% block content_description %}View Processors for Catalog {% if session.catalog_name %}{{ session.catalog_name }}{% else %}No Catalog{% endif %}{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} -
-
- {{ render_selectable_table(headers=["Processor ID", "Name", "Type", "Active"], rows=rows, selectable=True, id="retrieversTable") }} -
-
- -
- -
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.processors') }} -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/document/retrievers.html b/eveai_app/templates/document/retrievers.html deleted file mode 100644 index a8fe208..0000000 --- a/eveai_app/templates/document/retrievers.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination %} - -{% block title %}Retrievers{% endblock %} - -{% block content_title %}Retrievers{% endblock %} -{% block content_description %}View Retrievers for Catalog {% if session.catalog_name %}{{ session.catalog_name }}{% else %}No Catalog{% endif %}{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} -
-
- {{ render_selectable_table(headers=["Retriever ID", "Name", "Type"], rows=rows, selectable=True, id="retrieversTable") }} -
-
- -
- -
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'document_bp.retrievers') }} -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/entitlements/view_license_tiers.html b/eveai_app/templates/entitlements/view_license_tiers.html deleted file mode 100644 index 8b0e149..0000000 --- a/eveai_app/templates/entitlements/view_license_tiers.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends 'base.html' %} -{% from "macros.html" import render_selectable_table, render_pagination, render_field %} -{% block title %}License Tier Selection{% endblock %} -{% block content_title %}Select a License Tier{% endblock %} -{% block content_description %}Select a License Tier to continue{% endblock %} -{% block content %} - - -
- {{ render_selectable_table(headers=["ID", "Name", "Version", "Start Date", "End Date"], rows=rows, selectable=True, id="licenseTierTable") }} -
-
- {% if current_user.has_role('Super User') %} - - {% endif %} - {% if current_user.has_role('Super User') or (current_user.has_role('Partner Admin') and can_assign_license) %} - - {% endif %} - {% if current_user.has_role('Super User') %} - - {% endif %} -
- {% if current_user.has_role('Super User') %} - - {% endif %} -
-
- -{% endblock %} - -{% block content_footer %} -{{ render_pagination(pagination, 'user_bp.select_tenant') }} -{% endblock %} - - - diff --git a/eveai_app/templates/entitlements/view_licenses.html b/eveai_app/templates/entitlements/view_licenses.html deleted file mode 100644 index 35f4e5b..0000000 --- a/eveai_app/templates/entitlements/view_licenses.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends 'base.html' %} -{% from "macros.html" import render_selectable_table, render_pagination %} - -{% block title %}View Licenses{% endblock %} - -{% block content_title %}View Licenses{% endblock %} -{% block content_description %}View Licenses{% endblock %} - -{% block content %} -
- {{ render_selectable_table(headers=["License ID", "Name", "Start Date", "Nr of Periods", "Active"], rows=rows, selectable=True, id="licensesTable") }} -
-
- - -
- -
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'entitlements_bp.view_licenses') }} -{% endblock %} - -{% block scripts %} - -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/eveai_list_view.html b/eveai_app/templates/eveai_list_view.html index 880e7ca..c9723fb 100644 --- a/eveai_app/templates/eveai_list_view.html +++ b/eveai_app/templates/eveai_list_view.html @@ -1,301 +1,493 @@ - + // Definieer de handleListViewAction functie als deze nog niet bestaat + if (typeof window.handleListViewAction !== 'function') { + window.handleListViewAction = function(action, requiresSelection, e) { + // Gebruik explicit de event parameter om de browser event warning te vermijden + const evt = e || window.event; + const target = evt?.target || evt?.srcElement; + + // Voorkom acties vanuit gedisabled buttons + if (target && (target.disabled || target.classList.contains('disabled'))) { + console.log('Button actie geblokkeerd: button is disabled'); + return false; + } + + // Vind het tableId op basis van het formulier waarin we zitten + const form = target ? target.closest('form') : null; + const tableId = form ? form.id.replace('-form', '') : document.querySelector('.tabulator-list-view')?.id; + + if (!tableId) { + console.error('Kan tableId niet bepalen voor action:', action); + return false; + } + + // Controleer direct of de button disabled zou moeten zijn + if (requiresSelection === true) { + const instance = window.EveAI.ListView.instances[tableId]; + if (!instance || !instance.selectedRow) { + console.log('Button actie geblokkeerd: geen rij geselecteerd'); + return false; + } + } + + // Als EveAI.ListView beschikbaar is, gebruik dan de handleAction functie + if (window.EveAI && window.EveAI.ListView && typeof window.EveAI.ListView.handleAction === 'function') { + return window.EveAI.ListView.handleAction(action, requiresSelection, tableId); + } + + // Fallback naar de originele implementatie + const actionInput = document.getElementById(`${tableId}-action`); + if (actionInput) { + actionInput.value = action; + } + + // Controleer of er een rij geselecteerd is indien nodig + if (requiresSelection) { + const selectedRowInput = document.getElementById(`${tableId}-selected-row`); + if (!selectedRowInput || !selectedRowInput.value) { + alert('Selecteer eerst een item uit de lijst.'); + return false; + } + } + + // Verstuur het formulier met behoud van de originele form action + if (form) { + // Controleer of de form action correct is ingesteld + if (!form.action || form.action === '' || form.action === window.location.href || form.action === window.location.pathname) { + console.warn('Form action is mogelijk niet correct ingesteld:', form.action); + // Als er geen action is ingesteld, gebruik dan de huidige URL + form.action = window.location.href; + } + console.log(`Form action is: ${form.action}`); + form.submit(); + return true; + } + + return false; + }; + } + + console.log('EveAI List View component geladen'); +}); + \ No newline at end of file diff --git a/eveai_app/templates/interaction/assets.html b/eveai_app/templates/interaction/assets.html deleted file mode 100644 index 1bbf72a..0000000 --- a/eveai_app/templates/interaction/assets.html +++ /dev/null @@ -1,97 +0,0 @@ - -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination, render_filter_field, render_date_filter_field, render_collapsible_section, render_selectable_sortable_table_with_dict_headers %} - -{% block title %}Assets{% endblock %} - -{% block content_title %}Assets{% endblock %} -{% block content_description %}View Assets{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} - - {% set filter_form %} -
- {{ render_filter_field('type', 'Type', filter_options['type'], filters.get('type', [])) }} - {{ render_filter_field('file_type', 'Bestandstype', filter_options['file_type'], filters.get('file_type', [])) }} - - -
- {% endset %} - - {{ render_collapsible_section('Filter', 'Filter Options', filter_form) }} - -
-
- - {{ render_selectable_sortable_table_with_dict_headers( - headers=[ - {"text": "ID", "sort": "id"}, - {"text": "Naam", "sort": "name"}, - {"text": "Type", "sort": "type"}, - {"text": "Type Versie", "sort": "type_version"}, - {"text": "Bestandstype", "sort": "file_type"}, - {"text": "Laatst Gebruikt", "sort": "last_used_at"} - ], - rows=rows, - selectable=True, - id="assetsTable", - sort_by=sort_by, - sort_order=sort_order - ) }} -
-
- -
-
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'interaction_bp.assets') }} -{% endblock %} - -{% block scripts %} - -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/interaction/chat_sessions.html b/eveai_app/templates/interaction/chat_sessions.html deleted file mode 100644 index cbdc5c3..0000000 --- a/eveai_app/templates/interaction/chat_sessions.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination %} - -{% block title %}Chat Sessions{% endblock %} - -{% block content_title %}Chat Sessions{% endblock %} -{% block content_description %}View Chat Sessions for Tenant{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} -
-
- {{ render_selectable_table(headers=["ID", "Session ID", "Session Start", "Session End"], rows=rows, selectable=True, id="chatSessionsTable") }} -
-
- - -
-
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'interaction_bp.chat_sessions') }} -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/interaction/specialist_magic_links.html b/eveai_app/templates/interaction/specialist_magic_links.html deleted file mode 100644 index 2947fd3..0000000 --- a/eveai_app/templates/interaction/specialist_magic_links.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends 'base.html' %} -{% from 'macros.html' import render_selectable_table, render_pagination %} - -{% block title %}Specialist Magic Links{% endblock %} - -{% block content_title %}Specialist Magic Links{% endblock %} -{% block content_description %}View Specialists Magic Links{% endblock %} -{% block content_class %}
{% endblock %} - -{% block content %} -
-
- {{ render_selectable_table(headers=["Specialist ML ID", "Name", "Magic Link Code"], rows=rows, selectable=True, id="specialistMagicLinksTable") }} -
-
- -
- -
-
-
-{% endblock %} - -{% block content_footer %} - {{ render_pagination(pagination, 'interaction_bp.specialist_magic_links') }} -{% endblock %} \ No newline at end of file diff --git a/eveai_app/templates/interaction/specialists.html b/eveai_app/templates/interaction/specialists.html deleted file mode 100644 index 59aa7e9..0000000 --- a/eveai_app/templates/interaction/specialists.html +++ /dev/null @@ -1,77 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Specialists{% endblock %} -{% block content_title %}Specialists{% endblock %} -{% block content_description %}View Specialists for Tenant{% endblock %} - -{% block content %} -
-
-
-
-
- - -{% include 'eveai_list_view.html' %} - - -{% endblock %} diff --git a/eveai_app/templates/list_view.html b/eveai_app/templates/list_view.html new file mode 100644 index 0000000..ce715c7 --- /dev/null +++ b/eveai_app/templates/list_view.html @@ -0,0 +1,82 @@ +{% extends 'base.html' %} + +{% block title %}{{ title }}{% endblock %} +{% block content_title %}{{ title }}{% endblock %} +{% block content_description %}{{ description|default('') }}{% endblock %} + +{% block content %} +
+
+ {% include 'eveai_list_view.html' %} +
+
+ + +{% endblock %} diff --git a/eveai_app/templates/navbar.html b/eveai_app/templates/navbar.html index 87a226a..2c4cd37 100644 --- a/eveai_app/templates/navbar.html +++ b/eveai_app/templates/navbar.html @@ -69,10 +69,9 @@