- 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
This commit is contained in:
Josako
2025-05-27 17:37:32 +02:00
parent 1fdbd2ff45
commit 5123de55cc
1041 changed files with 4480 additions and 292099 deletions

1
.gitignore vendored
View File

@@ -52,3 +52,4 @@ scripts/__pycache__/run_eveai_app.cpython-312.pyc
/docker/prometheus/data/
/docker/grafana/data/
/temp_requirements/
/nginx/node_modules/

View File

@@ -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. Youve 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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"
}
}

View File

@@ -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

View File

@@ -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>

View 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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -0,0 +1 @@
{% extends "interaction/component.html" %}

View File

@@ -0,0 +1 @@
{% extends "interaction/component.html" %}

View File

@@ -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 %}

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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

View File

@@ -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."
)

View File

@@ -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

View 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

File diff suppressed because it is too large Load Diff

19
nginx/package.json Normal file
View 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 ./"
}
}

View File

@@ -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;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 934 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

Some files were not shown because too many files have changed in this diff Show More