- Adding functionality for listing and editing assets
- Started adding functionality for creating a 'full_documents' list view.
This commit is contained in:
114
eveai_app/templates/document/full_documents.html
Normal file
114
eveai_app/templates/document/full_documents.html
Normal file
@@ -0,0 +1,114 @@
|
||||
{% 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 <b>{% if session.catalog_name %}{{ session.catalog_name }}{% else %}No Catalog{% endif %}</b>{% endblock %}
|
||||
{% block content_class %}<div class="col-xl-12 col-lg-5 col-md-7 mx-auto"></div>{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Filter Form -->
|
||||
{% set filter_form %}
|
||||
<form method="GET" action="{{ url_for('document_bp.full_documents') }}">
|
||||
{{ 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', [])) }}
|
||||
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
</form>
|
||||
{% endset %}
|
||||
|
||||
{{ render_collapsible_section('Filter', 'Filter Options', filter_form) }}
|
||||
|
||||
<div class="form-group mt-3">
|
||||
<form method="POST" action="{{ url_for('document_bp.handle_full_document_selection') }}" id="fullDocumentsForm">
|
||||
<!-- Hidden field to store the selected version ID -->
|
||||
<input type="hidden" name="version_id" id="selectedVersionId" value="">
|
||||
|
||||
<!-- Documents Table -->
|
||||
{{ 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
|
||||
) }}
|
||||
<div class="form-group mt-3 d-flex justify-content-between">
|
||||
<div>
|
||||
<button type="submit" name="action" value="edit_document" class="btn btn-primary" onclick="return validateTableSelection('fullDocumentsForm')">Edit Document</button>
|
||||
<button type="submit" name="action" value="edit_document_version" class="btn btn-primary" onclick="return validateTableSelection('fullDocumentsForm')">Edit Document Version</button>
|
||||
<button type="submit" name="action" value="document_versions" class="btn btn-secondary" onclick="return validateTableSelection('fullDocumentsForm')">Show All Document Versions</button>
|
||||
<button type="submit" name="action" value="refresh_document" class="btn btn-secondary" onclick="return validateTableSelection('fullDocumentsForm')">Refresh Document (new version)</button>
|
||||
<button type="submit" name="action" value="view_document_version_markdown" class="btn btn-danger" onclick="return validateTableSelection('fullDocumentsForm')">View Processed Document</button>
|
||||
<button type="submit" name="action" value="process_document_version" class="btn btn-danger" onclick="return validateTableSelection('fullDocumentsForm')">Process Document Version</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_footer %}
|
||||
{{ render_pagination(pagination, 'document_bp.full_documents') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const table = document.getElementById('fullDocumentsTable');
|
||||
const headers = table.querySelectorAll('th.sortable');
|
||||
|
||||
headers.forEach(header => {
|
||||
header.addEventListener('click', function() {
|
||||
const sortBy = this.dataset.sort;
|
||||
let sortOrder = 'asc';
|
||||
|
||||
if (this.querySelector('.fa-sort-up')) {
|
||||
sortOrder = 'desc';
|
||||
} else if (this.querySelector('.fa-sort-down')) {
|
||||
sortOrder = 'none';
|
||||
}
|
||||
|
||||
window.location.href = updateQueryStringParameter(window.location.href, 'sort_by', sortBy);
|
||||
window.location.href = updateQueryStringParameter(window.location.href, 'sort_order', sortOrder);
|
||||
});
|
||||
});
|
||||
|
||||
function updateQueryStringParameter(uri, key, value) {
|
||||
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
|
||||
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
|
||||
if (uri.match(re)) {
|
||||
return uri.replace(re, '$1' + key + "=" + value + '$2');
|
||||
}
|
||||
else {
|
||||
return uri + separator + key + "=" + value;
|
||||
}
|
||||
}
|
||||
|
||||
table.addEventListener('change', function(event) {
|
||||
if (event.target.type === 'radio') {
|
||||
var selectedRow = event.target.closest('tr');
|
||||
var documentId = selectedRow.cells[1].textContent;
|
||||
var versionId = selectedRow.cells[5].textContent;
|
||||
console.log('Selected Document ID:', documentId, 'Version ID:', versionId);
|
||||
|
||||
// Update the hidden field with the version ID
|
||||
document.getElementById('selectedVersionId').value = versionId;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
97
eveai_app/templates/interaction/assets.html
Normal file
97
eveai_app/templates/interaction/assets.html
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
{% 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 %}<div class="col-xl-12 col-lg-5 col-md-7 mx-auto"></div>{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Filter Form -->
|
||||
{% set filter_form %}
|
||||
<form method="GET" action="{{ url_for('interaction_bp.assets') }}">
|
||||
{{ 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', [])) }}
|
||||
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
</form>
|
||||
{% endset %}
|
||||
|
||||
{{ render_collapsible_section('Filter', 'Filter Options', filter_form) }}
|
||||
|
||||
<div class="form-group mt-3">
|
||||
<form method="POST" action="{{ url_for('interaction_bp.handle_asset_selection') }}" id="assetsForm">
|
||||
<!-- Assets Table -->
|
||||
{{ 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
|
||||
) }}
|
||||
<div class="form-group mt-3 d-flex justify-content-between">
|
||||
<div>
|
||||
<button type="submit" name="action" value="edit_asset" class="btn btn-primary" onclick="return validateTableSelection('assetsForm')">Edit Asset</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_footer %}
|
||||
{{ render_pagination(pagination, 'interaction_bp.assets') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const table = document.getElementById('assetsTable');
|
||||
const headers = table.querySelectorAll('th.sortable');
|
||||
|
||||
headers.forEach(header => {
|
||||
header.addEventListener('click', function() {
|
||||
const sortBy = this.dataset.sort;
|
||||
let sortOrder = 'asc';
|
||||
|
||||
if (this.querySelector('.fa-sort-up')) {
|
||||
sortOrder = 'desc';
|
||||
} else if (this.querySelector('.fa-sort-down')) {
|
||||
sortOrder = 'none';
|
||||
}
|
||||
|
||||
window.location.href = updateQueryStringParameter(window.location.href, 'sort_by', sortBy);
|
||||
window.location.href = updateQueryStringParameter(window.location.href, 'sort_order', sortOrder);
|
||||
});
|
||||
});
|
||||
|
||||
function updateQueryStringParameter(uri, key, value) {
|
||||
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
|
||||
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
|
||||
if (uri.match(re)) {
|
||||
return uri.replace(re, '$1' + key + "=" + value + '$2');
|
||||
}
|
||||
else {
|
||||
return uri + separator + key + "=" + value;
|
||||
}
|
||||
}
|
||||
|
||||
table.addEventListener('change', function(event) {
|
||||
if (event.target.type === 'radio') {
|
||||
var selectedRow = event.target.closest('tr');
|
||||
var assetId = selectedRow.cells[1].textContent;
|
||||
console.log('Selected Asset ID:', assetId);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
201
eveai_app/templates/interaction/edit_asset.html
Normal file
201
eveai_app/templates/interaction/edit_asset.html
Normal file
@@ -0,0 +1,201 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Edit Asset{% endblock %}
|
||||
|
||||
{% block content_title %}Edit Asset{% endblock %}
|
||||
{% block content_description %}Edit Asset: <b>{{ asset.name }}</b>{% endblock %}
|
||||
{% block content_class %}<div class="col-xl-10 col-lg-8 col-md-10 mx-auto"></div>{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h4 class="card-title">Asset Details</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Asset Information -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<p><strong>ID:</strong> {{ asset.id }}</p>
|
||||
<p><strong>Name:</strong> {{ asset.name }}</p>
|
||||
<p><strong>Type:</strong> {{ asset.type }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p><strong>Type Version:</strong> {{ asset.type_version }}</p>
|
||||
<p><strong>File Type:</strong> {{ asset.file_type }}</p>
|
||||
<p><strong>File Size:</strong> {{ asset.file_size or 'N/A' }} bytes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- JSON Editor Form -->
|
||||
<form method="POST" id="editAssetForm">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5>JSON Content</h5>
|
||||
|
||||
<!-- JSON Editor - gebruik het eveai_json_editor patroon -->
|
||||
<div class="form-group">
|
||||
<textarea name="json_content" id="json_content" class="json-editor" style="display: none;">{{ json_content }}</textarea>
|
||||
<div id="json_content-editor" class="json-editor-container" style="height: 500px; border: 1px solid #ddd; border-radius: 5px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div>
|
||||
<a href="{{ url_for('interaction_bp.assets') }}" class="btn btn-secondary">
|
||||
<i class="material-icons">cancel</i> Annuleren
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="material-icons">save</i> Opslaan
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const textareaElement = document.getElementById('json_content');
|
||||
let currentEditor = null;
|
||||
|
||||
// Wacht even en probeer dan de editor te krijgen via de EveAI namespace
|
||||
setTimeout(function() {
|
||||
currentEditor = window.EveAI?.JsonEditors?.get('json_content-editor');
|
||||
if (currentEditor) {
|
||||
console.log('JSON Editor gevonden en gekoppeld');
|
||||
} else {
|
||||
console.log('JSON Editor nog niet beschikbaar, probeer handmatige initialisatie');
|
||||
|
||||
// Probeer handmatige initialisatie als fallback
|
||||
if (window.EveAI?.JsonEditors?.initialize) {
|
||||
try {
|
||||
const initialContent = JSON.parse(textareaElement.value);
|
||||
currentEditor = window.EveAI.JsonEditors.initialize('json_content-editor', initialContent, {
|
||||
mode: 'tree',
|
||||
readOnly: false,
|
||||
mainMenuBar: true,
|
||||
navigationBar: false,
|
||||
statusBar: true,
|
||||
onChange: (updatedContent, previousContent, { contentErrors, patchResult }) => {
|
||||
console.log('Editor content changed');
|
||||
// Automatisch de textarea updaten bij wijzigingen
|
||||
syncEditorToTextarea();
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Error bij handmatige initialisatie:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Functie om editor inhoud naar textarea te synchroniseren
|
||||
function syncEditorToTextarea() {
|
||||
if (currentEditor && currentEditor.get) {
|
||||
try {
|
||||
const content = currentEditor.get();
|
||||
if (content.json !== undefined) {
|
||||
textareaElement.value = JSON.stringify(content.json, null, 2);
|
||||
} else if (content.text !== undefined) {
|
||||
textareaElement.value = content.text;
|
||||
}
|
||||
console.log('Editor content gesynchroniseerd naar textarea');
|
||||
} catch (e) {
|
||||
console.error('Error bij synchronisatie:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sync knop
|
||||
document.getElementById('getEditorContentBtn').addEventListener('click', function() {
|
||||
syncEditorToTextarea();
|
||||
alert('Editor inhoud gesynchroniseerd naar textarea');
|
||||
});
|
||||
|
||||
// Validate JSON button
|
||||
document.getElementById('validateJsonBtn').addEventListener('click', function() {
|
||||
// Eerst synchroniseren
|
||||
syncEditorToTextarea();
|
||||
|
||||
try {
|
||||
const content = textareaElement.value;
|
||||
JSON.parse(content);
|
||||
|
||||
// Show success message
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
title: 'Geldig JSON',
|
||||
text: 'De JSON syntax is correct!',
|
||||
icon: 'success',
|
||||
timer: 2000,
|
||||
showConfirmButton: false
|
||||
});
|
||||
} else {
|
||||
alert('De JSON syntax is correct!');
|
||||
}
|
||||
} catch (e) {
|
||||
// Show error message
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
title: 'Ongeldig JSON',
|
||||
text: 'JSON syntax fout: ' + e.message,
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
} else {
|
||||
alert('JSON syntax fout: ' + e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Form submission validation
|
||||
document.getElementById('editAssetForm').addEventListener('submit', function(e) {
|
||||
// Eerst de editor content synchroniseren
|
||||
syncEditorToTextarea();
|
||||
|
||||
try {
|
||||
const content = textareaElement.value;
|
||||
JSON.parse(content);
|
||||
|
||||
// JSON is valid, allow submission
|
||||
return true;
|
||||
} catch (error) {
|
||||
e.preventDefault();
|
||||
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
title: 'Ongeldig JSON',
|
||||
text: 'Kan het formulier niet verzenden: JSON syntax fout - ' + error.message,
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
} else {
|
||||
alert('Kan het formulier niet verzenden: JSON syntax fout - ' + error.message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -100,6 +100,7 @@
|
||||
{'name': 'Add Document', 'url': '/document/add_document', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Add URL', 'url': '/document/add_url', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Documents', 'url': '/document/documents', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Full Documents', 'url': '/document/full_documents', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Document Versions', 'url': '/document/document_versions_list', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Library Operations', 'url': '/document/library_operations', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
]) }}
|
||||
@@ -108,6 +109,7 @@
|
||||
{{ dropdown('Interactions', 'hub', [
|
||||
{'name': 'Specialists', 'url': '/interaction/specialists', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Specialist Magic Links', 'url': '/interaction/specialist_magic_links', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Assets', 'url': '/interaction/assets', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Chat Sessions', 'url': '/interaction/chat_sessions', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user