- Change TRAICIE_VACANCY_DEFINTION_SPECIALIST to TRAICIE_ROLE_DEFINITION_SPECIALIST
- Introduce new vanilla-jsoneditor iso older jsoneditor (for viewing a.o. ChatSessions) - Introduce use of npm to install required javascript libraries - update Material-kit-pro - Introduce new top bar to show session defaults, remove old navbar buttons - Correct Task & Tools editor
1
.gitignore
vendored
@@ -52,3 +52,4 @@ scripts/__pycache__/run_eveai_app.cpython-312.pyc
|
||||
/docker/prometheus/data/
|
||||
/docker/grafana/data/
|
||||
/temp_requirements/
|
||||
/nginx/node_modules/
|
||||
|
||||
@@ -2,6 +2,7 @@ version: "1.0.0"
|
||||
name: "Traicie HR BP "
|
||||
role: >
|
||||
You are an HR BP (Human Resources Business Partner)
|
||||
{custom_role}
|
||||
goal: >
|
||||
As an HR Business Partner, your primary goal is to align people strategies with business objectives. You aim to
|
||||
ensure that the organisation has the right talent, capabilities, and culture in place to drive performance,
|
||||
@@ -9,16 +10,13 @@ goal: >
|
||||
while advocating for employees and fostering a healthy, high-performing workplace.
|
||||
{custom_goal}
|
||||
backstory: >
|
||||
You didn't start your career as a strategist. You began in traditional HR roles — perhaps as an HR officer or
|
||||
generalist — mastering recruitment, employee relations, and policy implementation. Over time, you developed a deeper
|
||||
understanding of how people decisions impact business outcomes.
|
||||
You didn't start your career as a strategist. You began in traditional HR roles, mastering recruitment, employee
|
||||
relations, and policy implementation. You developed a deeper understanding of how people decisions impact business
|
||||
outcomes.
|
||||
Through experience, exposure to leadership, and a strong interest in organisational dynamics, you transitioned into a
|
||||
role that bridges the gap between HR and the business. You’ve earned a seat at the table not just by knowing HR
|
||||
processes, but by understanding the business inside-out, speaking the language of executives, and backing their advice
|
||||
with data and insight.
|
||||
You often working side-by-side with senior managers to tackle challenges like workforce planning, leadership
|
||||
development, organisational change, and employee engagement. Your credibility comes not just from HR knowledge,
|
||||
but from your ability to co-create solutions that solve real business problems.
|
||||
{custom_backstory}
|
||||
full_model_name: "mistral.mistral-medium-latest"
|
||||
temperature: 0.3
|
||||
|
||||
|
Before Width: | Height: | Size: 812 KiB After Width: | Height: | Size: 812 KiB |
@@ -0,0 +1,29 @@
|
||||
version: "1.1.0"
|
||||
name: "Traicie Role Definition Specialist"
|
||||
framework: "crewai"
|
||||
partner: "traicie"
|
||||
chat: false
|
||||
configuration: {}
|
||||
arguments:
|
||||
vacancy_text:
|
||||
name: "vacancy_text"
|
||||
type: "text"
|
||||
description: "The Vacancy Text"
|
||||
required: true
|
||||
results:
|
||||
competencies:
|
||||
name: "competencies"
|
||||
type: "List[str, str]"
|
||||
description: "List of vacancy competencies and their descriptions"
|
||||
required: false
|
||||
agents:
|
||||
- type: "TRAICIE_HR_BP_AGENT"
|
||||
version: "1.0"
|
||||
tasks:
|
||||
- type: "TRAICIE_GET_COMPETENCIES_TASK"
|
||||
version: "1.1"
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-05-27"
|
||||
changes: "Updated for unified competencies and ko criteria"
|
||||
description: "Assistant to create a new Vacancy based on Vacancy Text"
|
||||
@@ -0,0 +1,41 @@
|
||||
version: "1.1.0"
|
||||
name: "Get Competencies"
|
||||
task_description: >
|
||||
You are provided with a vacancy text, in beween triple backquotes.
|
||||
Identify and list all explicitly stated competencies, skills, knowledge, qualifications, and requirements mentioned in
|
||||
the vacancy text, like:
|
||||
• Technical skills
|
||||
• Education or training
|
||||
• Work experience
|
||||
• Language proficiency
|
||||
• Certifications or driving licences
|
||||
• Personal characteristics
|
||||
|
||||
Based on job title, the job description and typical characteristics of similar roles, als identify minimum requirements
|
||||
that are absolutely essential to perform the job properly, even if they are not explicitly stated in the text. Ask
|
||||
yourself questions such as:
|
||||
• Does the job require physical stamina?
|
||||
• Is weekend or shift work involved?
|
||||
• Is contact with certain materials (e.g. meat, chemicals) unavoidable?
|
||||
• Is independent working essential?
|
||||
• Is knowledge of a specific language or system critical for customer interaction or safety?
|
||||
• Are there any specific characteristics, contexts, or requirements so obvious that they are often left unstated, yet essential to perform the job?
|
||||
|
||||
Create a prioritised list of the 10 most critical competencies as defined above, ranked in importance.
|
||||
Treat this as a logical and professional reasoning exercise.
|
||||
Respect the language of the vacancy text, and return answers / output in the same language.
|
||||
|
||||
{custom_description}
|
||||
|
||||
Vacancy Text:
|
||||
```{vacancy_text}```
|
||||
|
||||
expected_output: >
|
||||
A list of title and description of the competencies for the given vacancy text. The description should describe the
|
||||
competencies in context of the vacancy text.
|
||||
{custom_expected_output}
|
||||
metadata:
|
||||
author: "Josako"
|
||||
date_added: "2025-01-27"
|
||||
description: "A Task to collect all behavioural competencies and ko criteria from a vacancy text"
|
||||
changes: "Adapted to return a unified list of both competencies and ko criteria"
|
||||
@@ -12,9 +12,9 @@ SPECIALIST_TYPES = {
|
||||
"name": "Spin Sales Specialist",
|
||||
"description": "A specialist that allows to answer user queries, try to get SPIN-information and Identification",
|
||||
},
|
||||
"TRAICIE_VACANCY_DEFINITION_SPECIALIST": {
|
||||
"name": "Traicie Vacancy Definition Specialist",
|
||||
"description": "Assistant to create a new Vacancy based on Vacancy Text",
|
||||
"TRAICIE_ROLE_DEFINITION_SPECIALIST": {
|
||||
"name": "Traicie Role Definition Specialist",
|
||||
"description": "Assistant Defining Competencies and KO Criteria",
|
||||
"partner": "traicie"
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,6 @@ COPY ../../nginx/mime.types /etc/nginx/mime.types
|
||||
RUN mkdir -p /etc/nginx/static /etc/nginx/public
|
||||
|
||||
COPY ../../nginx/static /etc/nginx/static
|
||||
COPY ../../integrations/Wordpress/eveai-chat/assets/css/eveai-chat-style.css /etc/nginx/static/css/
|
||||
COPY ../../integrations/Wordpress/eveai-chat/assets/js/eveai-chat-widget.js /etc/nginx/static/js/
|
||||
COPY ../../integrations/Wordpress/eveai-chat/assets/js/eveai-token-manager.js /etc/nginx/static/js/
|
||||
COPY ../../integrations/Wordpress/eveai-chat/assets/js/eveai-sdk.js /etc/nginx/static/js
|
||||
|
||||
# Copy public files
|
||||
COPY ../../nginx/public /etc/nginx/public
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
{% include 'head.html' %}
|
||||
|
||||
<body class="presentation-page bg-gray-200">
|
||||
{% include 'session_defaults.html' %}
|
||||
{% include 'navbar.html' %}
|
||||
{% include 'header.html' %}
|
||||
<hr>
|
||||
|
||||
130
eveai_app/templates/eveai_json_editor.html
Normal file
@@ -0,0 +1,130 @@
|
||||
<script type="module">
|
||||
|
||||
window.EveAI = window.EveAI || {};
|
||||
window.EveAI.JsonEditors = {
|
||||
instances: {},
|
||||
initialize: function(containerId, data, options = {}) {
|
||||
console.log('Initializing JSONEditor for', containerId, 'with data', data, 'and options', options);
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container || typeof container !== 'object' || !('classList' in container)) {
|
||||
console.error(`Container met ID ${containerId} niet gevonden of geen geldig element:`, container);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
console.error(`Container with ID ${containerId} not found`);
|
||||
return null;
|
||||
}
|
||||
if (this.instances[containerId]) return this.instances[containerId];
|
||||
|
||||
if (typeof window.createJSONEditor !== 'function') {
|
||||
console.error('vanilla-jsoneditor not loaded (window.createJSONEditor missing).');
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error:</strong> vanilla-jsoneditor not loaded
|
||||
</div>`;
|
||||
return null;
|
||||
}
|
||||
|
||||
const isReadOnly = options.readOnly === true;
|
||||
|
||||
let content = {
|
||||
{#text: undefined,#}
|
||||
json: data
|
||||
}
|
||||
|
||||
// props voor vanilla-jsoneditor
|
||||
const editorProps = {
|
||||
content: content,
|
||||
mode: options.mode || (isReadOnly ? "text" : "tree"),
|
||||
readOnly: isReadOnly,
|
||||
mainMenuBar: options.mainMenuBar !== undefined ? options.mainMenuBar : true,
|
||||
navigationBar: options.navigationBar !== undefined ? options.navigationBar : false,
|
||||
statusBar: options.statusBar !== undefined ? options.statusBar : !isReadOnly,
|
||||
onChange: (updatedContent, previousContent, { contentErrors, patchResult }) => {
|
||||
// content is an object { json: unknown } | { text: string }
|
||||
console.log('onChange', { updatedContent, previousContent, contentErrors, patchResult })
|
||||
}
|
||||
};
|
||||
console.log('EditorProps', editorProps);
|
||||
|
||||
let editor;
|
||||
try {
|
||||
console.log('Creating JSONEditor for', containerId);
|
||||
editor = window.createJSONEditor({
|
||||
target: container,
|
||||
props: editorProps
|
||||
}
|
||||
);
|
||||
console.log('JSONEditor created for ', containerId);
|
||||
container.classList.add('jsoneditor-initialized', isReadOnly ? 'jsoneditor-readonly-mode' : 'jsoneditor-edit-mode');
|
||||
console.log('Container class set for ', containerId);
|
||||
this.instances[containerId] = editor;
|
||||
console.log('JSONEditor instance stored for ', containerId);
|
||||
return editor;
|
||||
} catch (e) {
|
||||
console.error(`Error initializing JSONEditor for ${containerId}:`, e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error loading JSON data:</strong><br>${e.message}
|
||||
</div>`;
|
||||
return null;
|
||||
}
|
||||
},
|
||||
initializeReadOnly: function(containerId, data, additionalOptions = {}) {
|
||||
const options = Object.assign({ readOnly: true, mode: 'text' }, additionalOptions);
|
||||
const editor = this.initialize(containerId, data, options);
|
||||
if (editor && additionalOptions.expandAll && typeof editor.expand === "function") {
|
||||
try { editor.expand(() => true); } catch {}
|
||||
}
|
||||
return editor;
|
||||
},
|
||||
get: function(containerId) {
|
||||
return this.instances[containerId] || null;
|
||||
},
|
||||
destroy: function(containerId) {
|
||||
if (this.instances[containerId]) {
|
||||
if (typeof this.instances[containerId].destroy === 'function') this.instances[containerId].destroy();
|
||||
delete this.instances[containerId];
|
||||
}
|
||||
const container = document.getElementById(containerId);
|
||||
if (container) {
|
||||
container.classList.remove('jsoneditor-initialized', 'jsoneditor-readonly-mode', 'jsoneditor-edit-mode');
|
||||
container.innerHTML = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Tooltips
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(trigger => new bootstrap.Tooltip(trigger));
|
||||
// Textarea->json editor conversies
|
||||
document.querySelectorAll('.json-editor').forEach(function(textarea) {
|
||||
const containerId = textarea.id + '-editor';
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container) return;
|
||||
try {
|
||||
const data = textarea.value ? JSON.parse(textarea.value) : {};
|
||||
const isReadOnly = textarea.readOnly || textarea.hasAttribute('readonly') || textarea.classList.contains('readonly');
|
||||
window.EveAI.JsonEditors.initialize(containerId, data, {
|
||||
mode: isReadOnly ? 'preview' : 'tree',
|
||||
readOnly: isReadOnly,
|
||||
onChangeText: isReadOnly ? undefined : (jsonString) => { textarea.value = jsonString; }
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Error parsing initial JSON for .json-editor:', e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3"><strong>Error loading JSON data:</strong><br>${e.message}</div>`;
|
||||
}
|
||||
});
|
||||
// Alleen-lezen containers
|
||||
document.querySelectorAll('.json-viewer').forEach(function(container) {
|
||||
const dataElement = document.getElementById(container.id + '-data');
|
||||
if (!dataElement) return;
|
||||
try {
|
||||
const data = dataElement.textContent ? JSON.parse(dataElement.textContent) : {};
|
||||
window.EveAI.JsonEditors.initializeReadOnly(container.id, data, { expandAll: true });
|
||||
} catch (e) {
|
||||
console.error('Error parsing JSON for .json-viewer:', e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3"><strong>Error loading JSON data:</strong><br>${e.message}</div>`;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -12,7 +12,7 @@
|
||||
<link href="{{url_for('static', filename='assets/css/nucleo-icons.css" rel="stylesheet')}}" />
|
||||
<link href="{{url_for('static', filename='assets/css/nucleo-svg.css" rel="stylesheet')}}" />
|
||||
<!-- Font Awesome Icons -->
|
||||
<script src="https://kit.fontawesome.com/42d5adcbca.js" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
|
||||
<!-- Material Icons -->
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-7 text-center mx-auto">
|
||||
<h1 class="text-white pt-3 mt-n5">EveAI Virtual Assistant</h1>
|
||||
<p class="lead text-white mt-3 px-5">Enhance Customer Interaction with AI</p>
|
||||
<h1 class="text-white pt-3 mt-n5">Ask Eve AI</h1>
|
||||
<h2 class="lead text-white mt-3 px-5">Humanize Information Access</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "interaction/component.html" %}
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "interaction/component.html" %}
|
||||
@@ -93,42 +93,4 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// JSONEditor initialiseren wanneer een accordion item wordt geopend
|
||||
const accordionButtons = document.querySelectorAll('.accordion-button');
|
||||
|
||||
accordionButtons.forEach(function(button, index) {
|
||||
button.addEventListener('click', function() {
|
||||
// Voeg een kleine vertraging toe om te zorgen dat de accordion volledig is geopend
|
||||
setTimeout(function() {
|
||||
const isExpanded = button.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
if (isExpanded) {
|
||||
// Als de json-viewer class niet wordt gebruikt, handmatige initialisatie
|
||||
const loopIndex = index + 1;
|
||||
|
||||
// Controleer of er elementen zijn die niet automatisch zijn geïnitialiseerd
|
||||
// Dit is een backup voor het geval de automatische initialisatie niet werkt
|
||||
const containers = document.querySelectorAll(`#collapse${loopIndex} .json-editor-container`);
|
||||
containers.forEach(function(container) {
|
||||
if (!container.classList.contains('jsoneditor-initialized')) {
|
||||
const dataElement = document.getElementById(`${container.id}-data`);
|
||||
if (dataElement) {
|
||||
try {
|
||||
const jsonData = JSON.parse(dataElement.value || dataElement.textContent);
|
||||
window.EveAI.JsonEditors.initializeReadOnly(container.id, jsonData);
|
||||
} catch (e) {
|
||||
console.error(`Error parsing JSON for ${container.id}:`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -128,24 +128,6 @@
|
||||
]) }}
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if current_user.is_authenticated %}
|
||||
<ul class="navbar-nav d-lg-block d-none">
|
||||
<li class="nav-item">
|
||||
<a href="/session_defaults" class="btn btn-sm bg-gradient-primary mb-0">
|
||||
{% if 'tenant' in session %}
|
||||
TENANT {{ session['tenant'].get('id', 'None') }}: {{ session['tenant'].get('name', 'None') }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% if 'partner' in session %}
|
||||
<li class="nav-item mt-2">
|
||||
<a href="/session_defaults" class="btn btn-sm bg-gradient-success mb-0">
|
||||
PARTNER {{ session['partner'].get('id', 'None') }}: {{ session['partner'].get('name', 'None') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -1,204 +1,15 @@
|
||||
<!-- Optional JavaScript -->
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/perfect-scrollbar.min.js"></script>
|
||||
# dist/main.js contains all used javascript libraries
|
||||
<script src="{{url_for('static', filename='dist/main.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/typedjs.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/prism.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/highlight.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/parallax.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/nouislider.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/anime.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/material-kit-pro.min.js')}}?v=3.0.4 type="text/javascript"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/10.1.0/jsoneditor.min.css" rel="stylesheet" type="text/css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/10.1.0/jsoneditor.min.js"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/material-kit-pro.min.js')}}"></script>
|
||||
|
||||
<script>
|
||||
window.EveAI = window.EveAI || {};
|
||||
{% include 'eveai_json_editor.html' %}
|
||||
|
||||
// Centraal beheer van JSONEditor instanties
|
||||
window.EveAI.JsonEditors = {
|
||||
instances: {},
|
||||
|
||||
// Initialiseer een nieuwe JSONEditor
|
||||
initialize: function(containerId, data, options = {}) {
|
||||
const container = document.getElementById(containerId);
|
||||
|
||||
if (!container) {
|
||||
console.error(`Container with ID ${containerId} not found`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.instances[containerId]) {
|
||||
console.log(`JSONEditor for ${containerId} already initialized`);
|
||||
return this.instances[containerId];
|
||||
}
|
||||
|
||||
// Bepaal of de editor in read-only modus moet worden weergegeven
|
||||
const isReadOnly = options.readOnly === true;
|
||||
|
||||
// Standaard opties
|
||||
const defaultOptions = {
|
||||
mode: isReadOnly ? 'tree' : 'tree', // Gebruik 'tree' voor read-only om expand/collapse te behouden
|
||||
modes: isReadOnly ? ['tree', 'view'] : ['tree', 'code', 'view'], // Voeg 'tree' toe aan read-only modes
|
||||
search: true,
|
||||
navigationBar: false,
|
||||
mainMenuBar: true, // Behoud menubar voor expand/collapse knoppen
|
||||
statusBar: !isReadOnly // Verberg alleen statusbar in read-only modus
|
||||
};
|
||||
|
||||
// Als expliciet onEditable=false is ingesteld, zorg ervoor dat de editor read-only is
|
||||
if (options.onEditable === false || options.onEditable && typeof options.onEditable === 'function') {
|
||||
defaultOptions.onEditable = function() { return false; };
|
||||
}
|
||||
|
||||
// Combineer standaard opties met aangepaste opties
|
||||
const editorOptions = {...defaultOptions, ...options};
|
||||
|
||||
try {
|
||||
const editor = new JSONEditor(container, editorOptions, data);
|
||||
container.classList.add('jsoneditor-initialized');
|
||||
|
||||
// Voeg read-only klasse toe indien nodig
|
||||
if (isReadOnly) {
|
||||
container.classList.add('jsoneditor-readonly-mode');
|
||||
} else {
|
||||
container.classList.add('jsoneditor-edit-mode');
|
||||
}
|
||||
|
||||
this.instances[containerId] = editor;
|
||||
return editor;
|
||||
} catch (e) {
|
||||
console.error(`Error initializing JSONEditor for ${containerId}:`, e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error loading JSON data:</strong><br>${e.message}
|
||||
</div>`;
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// Initialiseer een read-only JSONEditor (handige functie)
|
||||
initializeReadOnly: function(containerId, data, additionalOptions = {}) {
|
||||
const readOnlyOptions = {
|
||||
readOnly: true,
|
||||
mode: 'tree', // Gebruik tree mode voor navigatie
|
||||
modes: ['tree', 'view'], // Beperk tot tree en view
|
||||
expandAll: true, // Alles openklappen bij initialisatie
|
||||
onEditable: function() { return false; }
|
||||
};
|
||||
|
||||
// Combineer read-only opties met eventuele aanvullende opties
|
||||
const options = {...readOnlyOptions, ...additionalOptions};
|
||||
|
||||
return this.initialize(containerId, data, options);
|
||||
},
|
||||
|
||||
// Haal een bestaande instantie op of maak een nieuwe aan
|
||||
get: function(containerId, data, options = {}) {
|
||||
if (this.instances[containerId]) {
|
||||
return this.instances[containerId];
|
||||
}
|
||||
|
||||
return this.initialize(containerId, data, options);
|
||||
},
|
||||
|
||||
// Verwijder een instantie
|
||||
destroy: function(containerId) {
|
||||
if (this.instances[containerId]) {
|
||||
this.instances[containerId].destroy();
|
||||
delete this.instances[containerId];
|
||||
|
||||
const container = document.getElementById(containerId);
|
||||
if (container) {
|
||||
container.classList.remove('jsoneditor-initialized');
|
||||
container.classList.remove('jsoneditor-readonly-mode');
|
||||
container.classList.remove('jsoneditor-edit-mode');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Zoek en initialiseer standaard JSON editors bij DOMContentLoaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize tooltips
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
});
|
||||
|
||||
// Initialiseer JSON editors voor tekstgebieden met de klasse 'json-editor'
|
||||
document.querySelectorAll('.json-editor').forEach(function(textarea) {
|
||||
// Controleer of er een bijbehorende container is
|
||||
const containerId = textarea.id + '-editor';
|
||||
const container = document.getElementById(containerId);
|
||||
|
||||
if (container) {
|
||||
try {
|
||||
// Parse de JSON-data uit het tekstgebied
|
||||
const data = textarea.value ? JSON.parse(textarea.value) : {};
|
||||
|
||||
// Controleer of de editor in read-only modus moet worden getoond
|
||||
const isReadOnly = textarea.readOnly || textarea.hasAttribute('readonly') ||
|
||||
textarea.classList.contains('readonly');
|
||||
|
||||
// Bepaal de juiste editor-opties op basis van de read-only status
|
||||
const editorOptions = {
|
||||
mode: isReadOnly ? 'tree' : 'code', // Gebruik tree voor read-only
|
||||
modes: isReadOnly ? ['tree', 'view'] : ['code', 'tree'],
|
||||
readOnly: isReadOnly,
|
||||
onEditable: function() { return !isReadOnly; },
|
||||
onChangeText: isReadOnly ? undefined : function(jsonString) {
|
||||
textarea.value = jsonString;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialiseer de editor
|
||||
const editor = window.EveAI.JsonEditors.initialize(containerId, data, editorOptions);
|
||||
|
||||
// Voeg validatie toe als het een bewerkbare editor is
|
||||
if (!isReadOnly && editor) {
|
||||
editor.validate().then(function(errors) {
|
||||
if (errors.length) {
|
||||
container.style.border = '2px solid red';
|
||||
} else {
|
||||
container.style.border = '1px solid #ccc';
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing initial JSON:', e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error loading JSON data:</strong><br>${e.message}
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialiseer JSON editors voor containers met de klasse 'json-viewer' (alleen-lezen)
|
||||
document.querySelectorAll('.json-viewer').forEach(function(container) {
|
||||
const dataElement = document.getElementById(container.id + '-data');
|
||||
|
||||
if (dataElement) {
|
||||
try {
|
||||
// Parse de JSON-data
|
||||
const data = dataElement.textContent ? JSON.parse(dataElement.textContent) : {};
|
||||
|
||||
// Initialiseer een read-only editor met tree-mode voor navigatie
|
||||
window.EveAI.JsonEditors.initializeReadOnly(container.id, data);
|
||||
} catch (e) {
|
||||
console.error('Error parsing JSON for viewer:', e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error loading JSON data:</strong><br>${e.message}
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize tooltips
|
||||
@@ -207,38 +18,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
});
|
||||
|
||||
// Initialize JSON editors
|
||||
document.querySelectorAll('.json-editor').forEach(function(textarea) {
|
||||
// Create container for editor
|
||||
var container = document.getElementById(textarea.id + '-editor');
|
||||
|
||||
// Initialize the editor
|
||||
var editor = new JSONEditor(container, {
|
||||
mode: 'code',
|
||||
modes: ['code', 'tree'],
|
||||
onChangeText: function(jsonString) {
|
||||
textarea.value = jsonString;
|
||||
}
|
||||
});
|
||||
|
||||
// Set initial value
|
||||
try {
|
||||
const initialValue = textarea.value ? JSON.parse(textarea.value) : {};
|
||||
editor.set(initialValue);
|
||||
} catch (e) {
|
||||
console.error('Error parsing initial JSON:', e);
|
||||
editor.set({});
|
||||
}
|
||||
|
||||
// Add validation indicator
|
||||
editor.validate().then(function(errors) {
|
||||
if (errors.length) {
|
||||
container.style.border = '2px solid red';
|
||||
} else {
|
||||
container.style.border = '1px solid #ccc';
|
||||
}
|
||||
});
|
||||
});
|
||||
// De JSON editor initialisatie is hierboven al samengevoegd.
|
||||
// Deze dubbele DOMContentLoaded listener en .json-editor initialisatie kan verwijderd worden.
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
@@ -364,4 +145,31 @@ $(document).ready(function() {
|
||||
.tooltip {
|
||||
position: fixed;
|
||||
}
|
||||
/* Voeg CSS toe voor vanilla-jsoneditor */
|
||||
/* Je kunt het thema aanpassen of de standaardstijlen gebruiken */
|
||||
/* @import 'vanilla-jsoneditor/themes/jse-theme-dark.css'; */
|
||||
/* Of importeer de basisstijlen */
|
||||
/* @import 'vanilla-jsoneditor/dist/vanilla-jsoneditor.css'; */
|
||||
|
||||
/* Als je de CSS via een link tag wilt toevoegen: */
|
||||
/* <link href="path/to/vanilla-jsoneditor.min.css" rel="stylesheet"> */
|
||||
/* <link href="path/to/jse-theme-dark.css" rel="stylesheet"> (optioneel thema) */
|
||||
|
||||
/* Zorg ervoor dat de container de juiste hoogte heeft, de editor neemt de hoogte van de container over */
|
||||
.json-viewer, .json-editor-container /* Pas dit aan je HTML structuur aan indien nodig */ {
|
||||
height: 300px; /* Of de gewenste hoogte */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Voeg styling toe om de vanilla-jsoneditor eruit te laten zien als de oude, indien gewenst */
|
||||
.jsoneditor-readonly-mode .jse-main-menu,
|
||||
.jsoneditor-readonly-mode .jse-status-bar {
|
||||
/* Verberg menu en statusbalk in read-only modus indien gewenst */
|
||||
/* display: none; */
|
||||
}
|
||||
|
||||
.jse-read-only {
|
||||
/* Standaard read-only styling van vanilla-jsoneditor */
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
73
eveai_app/templates/session_defaults.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<div class="container-fluid position-relative z-index-2 px-0 py-2 bg-gradient-light">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if current_user.has_roles('Super User', 'Partner Admin') %}
|
||||
<!-- Partner information (links) - alleen voor Super User en Partner Admin -->
|
||||
<div class="col-md-4 d-flex align-items-center">
|
||||
<span class="material-symbols-outlined me-2" style="font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;">
|
||||
partner_exchange
|
||||
</span>
|
||||
<div>
|
||||
<small>
|
||||
{% if 'partner' in session and session['partner'] %}
|
||||
{{ session['partner'].get('id', 'Not selected') }}: {{ session['partner'].get('name', 'None') }}
|
||||
{% else %}
|
||||
No partner selected
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tenant information (centraal) - voor Super User en Partner Admin -->
|
||||
<div class="col-md-4 d-flex align-items-center justify-content-center">
|
||||
<span class="material-symbols-outlined me-2" style="font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;">
|
||||
source_environment
|
||||
</span>
|
||||
<div>
|
||||
<small>
|
||||
{% if 'tenant' in session and session['tenant'] %}
|
||||
{{ session['tenant'].get('id', 'Not selected') }}: {{ session['tenant'].get('name', 'None') }}
|
||||
{% else %}
|
||||
No tenant selected
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<!-- Tenant information (links) - voor andere gebruikers -->
|
||||
<div class="col-md-6 d-flex align-items-center">
|
||||
<span class="material-symbols-outlined me-2" style="font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;">
|
||||
source_environment
|
||||
</span>
|
||||
<div>
|
||||
<small>
|
||||
{% if 'tenant' in session and session['tenant'] %}
|
||||
{{ session['tenant'].get('id', 'Not selected') }}: {{ session['tenant'].get('name', 'None') }}
|
||||
{% else %}
|
||||
No tenant selected
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Catalog information (rechts) -->
|
||||
<div class="{% if current_user.has_roles('Super User', 'Partner Admin') %}col-md-4{% else %}col-md-6{% endif %} d-flex align-items-center justify-content-end">
|
||||
<span class="material-symbols-outlined me-2" style="font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;">
|
||||
note_stack
|
||||
</span>
|
||||
<div>
|
||||
<small>
|
||||
{% if 'catalog_id' in session and session['catalog_id'] %}
|
||||
{{ session.get('catalog_id', 'Not selected') }}: {{ session.get('catalog_name', 'None') }}
|
||||
{% else %}
|
||||
No catalog selected
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -337,6 +337,7 @@ def edit_agent(agent_id):
|
||||
title="Edit Agent",
|
||||
description="Configure the agent with company-specific details if required",
|
||||
submit_text="Save Agent")
|
||||
return None
|
||||
|
||||
|
||||
@interaction_bp.route('/agent/<int:agent_id>/save', methods=['POST'])
|
||||
@@ -372,7 +373,12 @@ def edit_task(task_id):
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return render_template('interaction/components/edit_task.html',
|
||||
form=form,
|
||||
task=task)
|
||||
task=task,
|
||||
title="Edit Task",
|
||||
description="Configure the task with company-specific details if required",
|
||||
submit_text="Save Task"
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
@interaction_bp.route('/task/<int:task_id>/save', methods=['POST'])
|
||||
@@ -406,7 +412,13 @@ def edit_tool(tool_id):
|
||||
form = EditEveAIToolForm(obj=tool)
|
||||
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return render_template('interaction/components/edit_tool.html', form=form, tool=tool)
|
||||
return render_template('interaction/components/edit_tool.html',
|
||||
form=form,
|
||||
tool=tool,
|
||||
title="Edit Tool",
|
||||
description="Configure the tool with company-specific details if required",
|
||||
submit_text="Save Tool"
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from eveai_chat_workers.outputs.globals.basic_types.list_item import ListItem
|
||||
|
||||
# class BehaviouralCompetence(BaseModel):
|
||||
# title: str = Field(..., description="The title of the behavioural competence.")
|
||||
# description: Optional[str] = Field(None, description="The description of the behavioural competence.")
|
||||
|
||||
class Competencies(BaseModel):
|
||||
competencies: List[ListItem] = Field(
|
||||
default_factory=list,
|
||||
description="A list of competencies and their descriptions."
|
||||
)
|
||||
@@ -0,0 +1,147 @@
|
||||
import asyncio
|
||||
import json
|
||||
from os import wait
|
||||
from typing import Optional, List
|
||||
|
||||
from crewai.flow.flow import start, listen, and_
|
||||
from crewai import Process
|
||||
from flask import current_app
|
||||
from gevent import sleep
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from common.extensions import cache_manager
|
||||
from common.models.user import Tenant
|
||||
from common.utils.business_event_context import current_event
|
||||
from eveai_chat_workers.outputs.globals.basic_types.list_item import ListItem
|
||||
from eveai_chat_workers.retrievers.retriever_typing import RetrieverArguments
|
||||
from eveai_chat_workers.specialists.crewai_base_specialist import CrewAIBaseSpecialistExecutor
|
||||
from eveai_chat_workers.specialists.specialist_typing import SpecialistResult, SpecialistArguments
|
||||
from eveai_chat_workers.outputs.traicie.competencies.competencies_v1_1 import Competencies
|
||||
from eveai_chat_workers.specialists.crewai_base_classes import EveAICrewAICrew, EveAICrewAIFlow, EveAIFlowState
|
||||
from common.utils.pydantic_utils import flatten_pydantic_model
|
||||
|
||||
|
||||
class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
|
||||
"""
|
||||
type: TRAICIE_ROLE_DEFINITION_SPECIALIST
|
||||
type_version: 1.0
|
||||
Traicie Role Definition Specialist Executor class
|
||||
"""
|
||||
|
||||
def __init__(self, tenant_id, specialist_id, session_id, task_id, **kwargs):
|
||||
self.role_definition_crew = None
|
||||
|
||||
super().__init__(tenant_id, specialist_id, session_id, task_id)
|
||||
|
||||
# Load the Tenant & set language
|
||||
self.tenant = Tenant.query.get_or_404(tenant_id)
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
return "TRAICIE_ROLE_DEFINITION_SPECIALIST"
|
||||
|
||||
@property
|
||||
def type_version(self) -> str:
|
||||
return "1.1"
|
||||
|
||||
def _config_task_agents(self):
|
||||
self._add_task_agent("traicie_get_competencies_task", "traicie_hr_bp_agent")
|
||||
|
||||
def _config_pydantic_outputs(self):
|
||||
self._add_pydantic_output("traicie_get_competencies_task", Competencies, "competencies")
|
||||
|
||||
def _instantiate_specialist(self):
|
||||
verbose = self.tuning
|
||||
|
||||
role_definition_agents = [self.traicie_hr_bp_agent]
|
||||
role_definition_tasks = [self.traicie_get_competencies_task]
|
||||
self.role_definition_crew = EveAICrewAICrew(
|
||||
self,
|
||||
"Role Definition Crew",
|
||||
agents=role_definition_agents,
|
||||
tasks=role_definition_tasks,
|
||||
verbose=verbose,
|
||||
)
|
||||
|
||||
self.flow = RoleDefinitionFlow(
|
||||
self,
|
||||
self.role_definition_crew
|
||||
)
|
||||
|
||||
def execute(self, arguments: SpecialistArguments, formatted_context, citations) -> SpecialistResult:
|
||||
self.log_tuning("Traicie Role Definition Specialist execution started", {})
|
||||
|
||||
flow_inputs = {
|
||||
"vacancy_text": arguments.vacancy_text,
|
||||
}
|
||||
|
||||
flow_results = self.flow.kickoff(inputs=flow_inputs)
|
||||
|
||||
flow_state = self.flow.state
|
||||
|
||||
results = RoleDefinitionSpecialistResult.create_for_type(self.type, self.type_version)
|
||||
if flow_state.competencies:
|
||||
results.competencies = flow_state.competencies
|
||||
|
||||
self.log_tuning(f"Traicie Role Definition Specialist execution ended", {"Results": results.model_dump()})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
class RoleDefinitionSpecialistInput(BaseModel):
|
||||
vacancy_text: Optional[str] = Field(None, alias="vacancy_text")
|
||||
|
||||
|
||||
class RoleDefinitionSpecialistResult(SpecialistResult):
|
||||
competencies: Optional[List[ListItem]] = None
|
||||
|
||||
|
||||
class RoleDefFlowState(EveAIFlowState):
|
||||
"""Flow state for Traicie Role Definition specialist that automatically updates from task outputs"""
|
||||
input: Optional[RoleDefinitionSpecialistInput] = None
|
||||
competencies: Optional[List[ListItem]] = None
|
||||
|
||||
|
||||
class RoleDefinitionFlow(EveAICrewAIFlow[RoleDefFlowState]):
|
||||
def __init__(self,
|
||||
specialist_executor: CrewAIBaseSpecialistExecutor,
|
||||
role_definitiion_crew: EveAICrewAICrew,
|
||||
**kwargs):
|
||||
super().__init__(specialist_executor, "Traicie Role Definition Specialist Flow", **kwargs)
|
||||
self.specialist_executor = specialist_executor
|
||||
self.role_definition_crew = role_definitiion_crew
|
||||
self.exception_raised = False
|
||||
|
||||
@start()
|
||||
def process_inputs(self):
|
||||
return ""
|
||||
|
||||
@listen(process_inputs)
|
||||
async def execute_role_definition(self):
|
||||
inputs = self.state.input.model_dump()
|
||||
try:
|
||||
current_app.logger.debug("In execute_role_definition")
|
||||
crew_output = await self.role_definition_crew.kickoff_async(inputs=inputs)
|
||||
# Unfortunately, crew_output will only contain the output of the latest task.
|
||||
# As we will only take into account the flow state, we need to ensure both competencies and criteria
|
||||
# are copies to the flow state.
|
||||
update = {}
|
||||
for task in self.role_definition_crew.tasks:
|
||||
current_app.logger.debug(f"Task {task.name} output:\n{task.output}")
|
||||
if task.name == "traicie_get_competencies_task":
|
||||
# update["competencies"] = task.output.pydantic.competencies
|
||||
self.state.competencies = task.output.pydantic.competencies
|
||||
# crew_output.pydantic = crew_output.pydantic.model_copy(update=update)
|
||||
current_app.logger.debug(f"State after execute_role_definition: {self.state}")
|
||||
current_app.logger.debug(f"State dump after execute_role_definition: {self.state.model_dump()}")
|
||||
return crew_output
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"CREW execute_role_definition Kickoff Error: {str(e)}")
|
||||
self.exception_raised = True
|
||||
raise e
|
||||
|
||||
async def kickoff_async(self, inputs=None):
|
||||
current_app.logger.debug(f"Async kickoff {self.name}")
|
||||
self.state.input = RoleDefinitionSpecialistInput.model_validate(inputs)
|
||||
result = await super().kickoff_async(inputs)
|
||||
return self.state
|
||||
46
nginx/frontend_src/js/main.js
Normal file
@@ -0,0 +1,46 @@
|
||||
// Importeer de bibliotheken die je wilt bundelen.
|
||||
// Parcel zal deze vinden in je node_modules map.
|
||||
|
||||
// jQuery
|
||||
import $ from 'jquery';
|
||||
// Maak jQuery globaal beschikbaar als window.jQuery en window.$
|
||||
// Dit is vaak nodig als oudere scripts of plugins dit verwachten.
|
||||
window.jQuery = $;
|
||||
window.$ = $;
|
||||
|
||||
// Popper.js (noodzakelijk voor Bootstrap 5 dropdowns, tooltips, popovers)
|
||||
// Controleer je package.json. Als je Bootstrap 5 gebruikt, heb je waarschijnlijk '@popperjs/core' nodig.
|
||||
// Als 'popper.js' in je package.json staat, is dat v1, en moet je mogelijk de import aanpassen
|
||||
// of Bootstrap's eigen gebundelde Popper gebruiken (indien aanwezig).
|
||||
import * as Popper from '@popperjs/core';
|
||||
window.Popper = Popper; // Maak het globaal beschikbaar als Bootstrap het extern verwacht.
|
||||
|
||||
// Bootstrap JavaScript
|
||||
import 'bootstrap'; // Importeert alle BS JS componenten.
|
||||
// Bootstrap's JS koppelt zichzelf meestal aan jQuery en gebruikt Popper.
|
||||
// Als je 'bootstrap' als object nodig hebt (bijv. voor new bootstrap.Modal()), importeer het dan als:
|
||||
// import * as bootstrap from 'bootstrap';
|
||||
// window.bootstrap = bootstrap;
|
||||
|
||||
// DataTables.net Core
|
||||
import DataTable from 'datatables.net';
|
||||
// Maak DataTable globaal beschikbaar
|
||||
window.DataTable = DataTable;
|
||||
|
||||
// Select2
|
||||
// Select2 is een jQuery plugin, dus het moet na jQuery geïmporteerd worden.
|
||||
// Het zou zichzelf moeten koppelen aan de jQuery instance.
|
||||
import 'select2';
|
||||
|
||||
// vanilla-jsoneditor
|
||||
// De import hieronder is voor recentere versies van vanilla-jsoneditor.
|
||||
// Controleer of de versie in je package.json ('^0.5.0') hiermee compatibel is.
|
||||
// Mogelijk moet je vanilla-jsoneditor updaten in package.json
|
||||
// of een andere import/initialisatie gebruiken voor v0.5.0.
|
||||
import { createJSONEditor } from 'vanilla-jsoneditor';
|
||||
// import { createJSONEditor } from 'vanilla-jsoneditor/standalone.js' staat in de documentatie
|
||||
// Maak de factory functie globaal beschikbaar als je dit elders in je code gebruikt.
|
||||
window.createJSONEditor = createJSONEditor;
|
||||
|
||||
// Eventueel een log om te bevestigen dat de bundel is geladen
|
||||
console.log('JavaScript bibliotheken gebundeld en geladen via main.js.');
|
||||
3801
nginx/package-lock.json
generated
Normal file
19
nginx/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"bootstrap": "^5.3.6",
|
||||
"datatables.net": "^2.3.1",
|
||||
"jquery": "^3.7.1",
|
||||
"select2": "^4.1.0-rc.0",
|
||||
"vanilla-jsoneditor": "^3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@parcel/transformer-sass": "^2.15.2",
|
||||
"parcel": "^2.15.2"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "parcel frontend_src/js/main.js --dist-dir static/dist --public-url ./",
|
||||
"build": "parcel build frontend_src/js/main.js --dist-dir static/dist --public-url ./",
|
||||
"watch": "parcel watch frontend_src/js/main.js --dist-dir static/dist --public-url ./"
|
||||
}
|
||||
}
|
||||
@@ -704,210 +704,113 @@ select.select2[multiple] {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Aanpassingen voor JSONEditor */
|
||||
.json-editor-container {
|
||||
height: 400px;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e9ecef;
|
||||
/* JSON Editor Styling - EveAI Aanpassingen */
|
||||
:root {
|
||||
/* Hoofdkleuren gebaseerd op EveAI kleurenschema */
|
||||
--jse-theme-color: var(--bs-primary); /* Paars als hoofdkleur */
|
||||
--jse-theme-color-highlight: var(--bs-secondary); /* Secundair paars voor highlights */
|
||||
|
||||
/* Achtergrondkleuren */
|
||||
--jse-background-color: #fff;
|
||||
--jse-panel-background: #f8f9fa;
|
||||
--jse-panel-border: 1px solid var(--bs-secondary);
|
||||
--jse-panel-border-radius: 0.375rem;
|
||||
|
||||
/* Tekstkleuren */
|
||||
--jse-text-color: var(--bs-body-color);
|
||||
--jse-text-color-inverse: #ffffff;
|
||||
|
||||
/* Navigatie */
|
||||
--jse-navigation-bar-background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%);
|
||||
--jse-navigation-bar-background-highlight: var(--bs-secondary);
|
||||
--jse-navigation-bar-text-color: #ffffff;
|
||||
|
||||
/* Status balk */
|
||||
--jse-status-bar-background: var(--bs-light);
|
||||
--jse-status-bar-color: var(--bs-body-color);
|
||||
--jse-status-bar-border: 1px solid var(--bs-secondary);
|
||||
--jse-status-bar-border-radius: 0 0 0.375rem 0.375rem;
|
||||
|
||||
/* Main menu bar */
|
||||
--jse-main-menu-background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%);
|
||||
--jse-main-menu-color: #ffffff;
|
||||
--jse-main-menu-button-background-highlight: var(--bs-secondary);
|
||||
--jse-main-menu-button-color-highlight: #ffffff;
|
||||
|
||||
/* Contextmenu */
|
||||
--jse-context-menu-background: #fff;
|
||||
--jse-context-menu-background-highlight: var(--bs-secondary);
|
||||
--jse-context-menu-color: var(--bs-body-color);
|
||||
--jse-context-menu-color-highlight: #ffffff;
|
||||
--jse-context-menu-border: 1px solid var(--bs-secondary);
|
||||
--jse-context-menu-box-shadow: 0 4px 8px rgba(118, 89, 154, 0.2);
|
||||
--jse-context-menu-border-radius: 0.375rem;
|
||||
|
||||
/* Knoppen */
|
||||
--jse-button-background: var(--bs-primary);
|
||||
--jse-button-background-highlight: var(--bs-secondary);
|
||||
--jse-button-color: #ffffff;
|
||||
--jse-button-color-highlight: #ffffff;
|
||||
--jse-button-border-radius: 0.375rem;
|
||||
|
||||
/* JSON Tree Mode */
|
||||
--jse-key-color: var(--bs-info);
|
||||
--jse-delimiter-color: #666;
|
||||
--jse-string-color: var(--bs-primary);
|
||||
--jse-number-color: var(--bs-warning);
|
||||
--jse-boolean-color: var(--bs-danger);
|
||||
--jse-null-color: #888;
|
||||
--jse-invalid-color: #e0b4b4;
|
||||
--jse-readonly-color: #888;
|
||||
--jse-readonly-background-color: #f0f0f0;
|
||||
|
||||
/* Selectie */
|
||||
--jse-selection-background-color: rgba(118, 89, 154, 0.2);
|
||||
--jse-selection-background-inactive-color: rgba(118, 89, 154, 0.1);
|
||||
|
||||
/* Foutmeldingen */
|
||||
--jse-error-color: var(--bs-danger);
|
||||
--jse-error-background-color: rgba(156, 45, 102, 0.1);
|
||||
|
||||
/* Tooltips */
|
||||
--jse-tooltip-background: var(--bs-primary);
|
||||
--jse-tooltip-color: #ffffff;
|
||||
--jse-tooltip-border-radius: 0.375rem;
|
||||
--jse-tooltip-box-shadow: 0 4px 8px rgba(118, 89, 154, 0.2);
|
||||
}
|
||||
|
||||
/* Hoofdmenu styling */
|
||||
.jsoneditor-menu {
|
||||
background-color: #ee912e !important;
|
||||
border-bottom: 1px solid #ee912e !important;
|
||||
color: #495057 !important;
|
||||
/* Extra stijlen voor de containers */
|
||||
.jsoneditor-initialized {
|
||||
border: 1px solid var(--bs-secondary);
|
||||
border-radius: 0.375rem;
|
||||
min-height: 300px;
|
||||
box-shadow: 0 4px 8px rgba(118, 89, 154, 0.1);
|
||||
}
|
||||
|
||||
/* Speciaal voor read-only modus */
|
||||
.jsoneditor-readonly-mode .jsoneditor-menu {
|
||||
background-color: #ee912e !important;
|
||||
border-bottom: 1px solid #ee912e !important;
|
||||
.jsoneditor-readonly-mode {
|
||||
background-color: var(--bs-light);
|
||||
}
|
||||
|
||||
/* Verberg bewerkingsknoppen in readonly mode, maar behoud expand/collapse knoppen */
|
||||
.jsoneditor-readonly-mode .jsoneditor-modes,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-separator,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-repair,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-undo,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-redo,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-compact,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-sort,
|
||||
.jsoneditor-readonly-mode button.jsoneditor-transform {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Toon belangrijke navigatieknoppen in read-only modus */
|
||||
.jsoneditor-readonly-mode .jsoneditor-expand-all,
|
||||
.jsoneditor-readonly-mode .jsoneditor-collapse-all,
|
||||
.jsoneditor-readonly-mode .jsoneditor-search {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
/* Verberg alle bewerkingselementen in de tree-view */
|
||||
.jsoneditor-readonly-mode td.jsoneditor-tree button.jsoneditor-button.jsoneditor-contextmenu-button {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Behoud wel de expand/collapse knoppen in de tree */
|
||||
.jsoneditor-readonly-mode td.jsoneditor-tree button.jsoneditor-button.jsoneditor-expanded,
|
||||
.jsoneditor-readonly-mode td.jsoneditor-tree button.jsoneditor-button.jsoneditor-collapsed {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
|
||||
/* Knoppen in het menu */
|
||||
.jsoneditor-menu button {
|
||||
background-color: transparent !important;
|
||||
color: #495057 !important;
|
||||
/* Stijlen voor de knoppen in de editor */
|
||||
.jse-button {
|
||||
border: none !important;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.jsoneditor-menu button:hover {
|
||||
background-color: #e8a34d !important;
|
||||
/* Stijlen voor veldlabels in de boom */
|
||||
.jse-tree .jse-key {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Mode selector (Tree ▾) */
|
||||
.jsoneditor-modes button {
|
||||
background-color: transparent !important;
|
||||
color: #495057 !important;
|
||||
border: none !important;
|
||||
padding: 4px 10px !important;
|
||||
/* Stijlen voor waarden in de boom */
|
||||
.jse-tree .jse-value {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.jsoneditor-modes button:hover {
|
||||
background-color: #e8a34d !important;
|
||||
}
|
||||
|
||||
/* Zoekbalk */
|
||||
.jsoneditor-search {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.jsoneditor-search input {
|
||||
border: 1px solid #ced4da !important;
|
||||
border-radius: 4px !important;
|
||||
color: #495057 !important;
|
||||
padding: 4px 8px !important;
|
||||
}
|
||||
|
||||
.jsoneditor-search button {
|
||||
background-color: transparent !important;
|
||||
color: #495057 !important;
|
||||
}
|
||||
|
||||
/* Binnengebied */
|
||||
.jsoneditor-outer {
|
||||
border: none !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
/* Tree view */
|
||||
.jsoneditor-tree {
|
||||
background-color: #fff !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
/* Read-only tree achtergrond */
|
||||
.jsoneditor-readonly-mode .jsoneditor-tree {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
/* Value & field styling */
|
||||
div.jsoneditor-field, div.jsoneditor-value {
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-string {
|
||||
color: #0d6efd !important; /* Bootstrap primary color voor strings */
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-number {
|
||||
color: #198754 !important; /* Bootstrap success color voor getallen */
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-boolean {
|
||||
color: #dc3545 !important; /* Bootstrap danger color voor booleans */
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-null {
|
||||
color: #6c757d !important; /* Bootstrap secondary color voor null */
|
||||
}
|
||||
|
||||
/* Expand/collapse knoppen */
|
||||
.jsoneditor-button.jsoneditor-expanded,
|
||||
.jsoneditor-button.jsoneditor-collapsed {
|
||||
filter: brightness(0.8) !important;
|
||||
}
|
||||
|
||||
/* Context menu buttons (drie puntjes) */
|
||||
.jsoneditor-button.jsoneditor-contextmenu-button {
|
||||
filter: brightness(0.8) !important;
|
||||
}
|
||||
|
||||
/* Verberg context menu knoppen in read-only modus */
|
||||
.jsoneditor-readonly-mode .jsoneditor-contextmenu-button {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hover effect op rijen */
|
||||
.jsoneditor-tree tr:hover {
|
||||
background-color: rgba(0, 123, 255, 0.05) !important;
|
||||
}
|
||||
|
||||
/* Geselecteerde rij */
|
||||
.jsoneditor-tree tr.jsoneditor-selected {
|
||||
background-color: rgba(0, 123, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Consistent font */
|
||||
.jsoneditor, .jsoneditor-tree, div.jsoneditor-field, div.jsoneditor-value {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
/* Consistente separators */
|
||||
td.jsoneditor-separator {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
/* Contextmenu indien nodig */
|
||||
div.jsoneditor-contextmenu {
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
|
||||
border-radius: 4px !important;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button {
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button:hover {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
/* Onzichtbare dragarea buttons verbergen voor een schoner uiterlijk */
|
||||
.jsoneditor-button.jsoneditor-dragarea {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Alleen tonen bij hover */
|
||||
tr:hover .jsoneditor-button.jsoneditor-dragarea {
|
||||
visibility: visible !important;
|
||||
opacity: 0.6 !important;
|
||||
}
|
||||
|
||||
/* Verberg de textarea met JSON-data */
|
||||
.d-none {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Zorg ervoor dat de JSONEditor goed zichtbaar is */
|
||||
.jsoneditor {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border: none !important;
|
||||
/* Verbeter de leesbaarheid van de tekstmodus */
|
||||
.jse-text-mode {
|
||||
font-family: monospace;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
34
nginx/static/assets/css/material-kit-pro.min.css
vendored
|
Before Width: | Height: | Size: 672 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 227 KiB |
|
Before Width: | Height: | Size: 253 KiB |
|
Before Width: | Height: | Size: 348 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 203 KiB |
|
Before Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 454 KiB |
|
Before Width: | Height: | Size: 271 KiB |
|
Before Width: | Height: | Size: 512 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 203 KiB |
|
Before Width: | Height: | Size: 320 KiB |
|
Before Width: | Height: | Size: 381 KiB |
|
Before Width: | Height: | Size: 450 KiB |
|
Before Width: | Height: | Size: 934 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 625 KiB |
|
Before Width: | Height: | Size: 263 KiB |
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 809 B |
|
Before Width: | Height: | Size: 300 KiB |