Refactor HTML templates for improved readability and consistency

- Updated search_results_table.html to enhance formatting and maintain consistent indentation.
- Refined search_results.html layout for better structure and clarity.
- Improved upload.html for better organization and readability of the upload form and data source table.
- Removed unnecessary lines in package.json and streamlined devDependencies section.
This commit is contained in:
2025-05-17 21:45:50 +02:00
parent 6b19cbcb51
commit e8f2d2adc2
35 changed files with 3406 additions and 3588 deletions

View File

@ -18,8 +18,8 @@ indent_size = 4
# HTML and Django/Jinja2 template files # HTML and Django/Jinja2 template files
[*.{html,htm}] [*.{html,htm}]
indent_style = tab indent_size = 2
indent_size = 4
# Allow prettier to format Django/Jinja templates properly # Allow prettier to format Django/Jinja templates properly
# The following comment options can be used in individual files if needed: # The following comment options can be used in individual files if needed:
# <!-- prettier-ignore --> # <!-- prettier-ignore -->

1
.gitignore vendored
View File

@ -407,6 +407,7 @@ pyrightconfig.json
*Zone.Identifier *Zone.Identifier
examples/ examples/
**/migrations/[0-9]**.py **/migrations/[0-9]**.py
package-lock.json
# UV specific # UV specific
.uv/ .uv/

View File

@ -3,6 +3,7 @@ default_install_hook_types:
- post-checkout - post-checkout
- post-merge - post-merge
- post-rewrite - post-rewrite
repos: repos:
# uv hooks for dependency management # uv hooks for dependency management
- repo: https://github.com/astral-sh/uv-pre-commit - repo: https://github.com/astral-sh/uv-pre-commit
@ -33,18 +34,18 @@ repos:
# rev: 3.0.7 # rev: 3.0.7
# hooks: # hooks:
# - id: djhtml # - id: djhtml
# entry: djhtml --tabwidth 4 -- # entry: djhtml --tabwidth 4
# - id: djcss
# - id: djjs
- repo: https://github.com/pre-commit/mirrors-prettier - repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8 rev: v3.1.0
hooks: hooks:
- id: prettier - id: prettier
types_or: [javascript, jsx, ts, tsx, css, scss, html, json, yaml, markdown] types_or: [javascript, jsx, ts, tsx, css, scss, html, json, yaml, markdown]
additional_dependencies: additional_dependencies:
- prettier - prettier
- prettier-plugin-jinja-template - prettier-plugin-jinja-template
# types_or: [javascript, jsx, ts, tsx, css, scss, json, yaml, markdown]
# exclude: '.*\.html$'
# Ruff for linting and formatting # Ruff for linting and formatting
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit

View File

@ -47,3 +47,6 @@ docker-compose.override.yml
.vscode/ .vscode/
*.swp *.swp
*.swo *.swo
# Ignore all SQLite3 files:
**/*.sqlite3

View File

@ -11,7 +11,7 @@
"requirePragma": false, "requirePragma": false,
"semi": true, "semi": true,
"singleQuote": false, "singleQuote": false,
"useTabs": true, "useTabs": false,
"overrides": [ "overrides": [
{ {
"files": ["*.html"], "files": ["*.html"],

View File

@ -1,4 +1,4 @@
.PHONY: venv install install-dev lint test format clean run migrate makemigrations superuser setup-node format-js .PHONY: venv install install-dev lint test format clean run migrate makemigrations superuser setup-node
# Create a virtual environment # Create a virtual environment
venv: venv:
@ -25,13 +25,9 @@ format:
uv run -m ruff format dashboard_project uv run -m ruff format dashboard_project
uv run -m black dashboard_project uv run -m black dashboard_project
# Format JavaScript/CSS/HTML files with Prettier
format-js:
npx run format
# Setup Node.js dependencies # Setup Node.js dependencies
setup-node: setup-node:
npm install npm install --include=dev
# Clean Python cache files # Clean Python cache files
clean: clean:
@ -45,6 +41,9 @@ clean:
find . -type d -name ".coverage" -exec rm -rf {} + find . -type d -name ".coverage" -exec rm -rf {} +
find . -type d -name "htmlcov" -exec rm -rf {} + find . -type d -name "htmlcov" -exec rm -rf {} +
find . -type d -name ".ruff_cache" -exec rm -rf {} + find . -type d -name ".ruff_cache" -exec rm -rf {} +
find . -type d -name ".mypy_cache" -exec rm -rf {} +
find . -type d -name ".tox" -exec rm -rf {} +
find . -type d -name "node_modules" -exec rm -rf {} +
rm -rf build/ rm -rf build/
rm -rf dist/ rm -rf dist/

86
TODO.md
View File

@ -1,31 +1,57 @@
# TODO List # LiveGraphs Project TODO
- When I zoom into the dasboard page, the graphs don't scale/adjust to fit the window until I completely refresh the page, can we solve that? ## Dashboard UI Improvements
- Add export functionality to the dashboard:
- File formats: ### Responsiveness
- CSV
- Excel - [ ] Fix dashboard graphs scaling/adjustment when zooming (currently requires page refresh)
- JSON
- XML ### Theming
- HTML
- PDF - [ ] Add dark mode/light mode toggle
- Make the export button a dropdown with the following options: - [ ] Add Notso AI branding elements
- Export as CSV - [ ] Implement responsive table design (reduce rows to fit screen)
- Export as Excel
- Export as JSON ### Data Export
- Export as XML
- Export as HTML - [ ] Implement multi-format export functionality
- Export as PDF - [ ] CSV format
- Make the export data section folded by default and only show the export button. - [ ] Excel format
- Adjust the downloaded file name to include the company name, date and time of the export. - [ ] JSON format
- Add a button to download the CSV file for the selected company. - [ ] XML format
- Make it possible to modify the column names in the CSV file through the admin interface. - [ ] HTML format
- Add possibility to add a company logo in the admin interface. - [ ] PDF format
- Add periodic download from <https://proto.notso.ai/XY/chats> possibility for the XY company. - [ ] Create dropdown menu for export options
- Authentication: Basic Auth - [ ] Make export data section collapsible (folded by default)
- URL: <https://proto.notso.ai/XY/chats> - [ ] Add company name, date and timestamp to exported filenames
- Username: xxxx
- Password: xxxx ## Admin Interface Enhancements
- Reduce amount of rows in the table to fit the screen.
- Add dark mode/theming to the dashboard. ### Company Management
- Add Notso AI branding to the dashboard.
- [ ] Add company logo upload functionality
- [ ] Add direct CSV download button for each company (superusers only)
- [ ] Include company name, date and timestamp in filename
- [ ] Add UI for customizing CSV column names
## Data Integration
### External Data Sources
- [ ] Implement periodic data download from external API
- [ ] Source: <https://proto.notso.ai/XY/chats>
- [ ] Authentication: Basic Auth
- [ ] Credentials: [stored securely]
- [ ] Add scheduling options for data refresh
## Technical Debt
### Performance Optimization
- [ ] Profile and optimize dashboard rendering
- [ ] Implement lazy loading for dashboard elements
### Testing
- [ ] Add unit tests for export functionality
- [ ] Add integration tests for data import process

View File

@ -91,8 +91,8 @@ AUTH_PASSWORD_VALIDATORS = [
] ]
# Internationalization # Internationalization
LANGUAGE_CODE = "en-us" LANGUAGE_CODE = "nl"
TIME_ZONE = "UTC" TIME_ZONE = "Europe/Amsterdam"
USE_I18N = True USE_I18N = True
USE_TZ = True USE_TZ = True

View File

@ -1,9 +1,8 @@
<!-- templates/accounts/login.html --> <!-- templates/accounts/login.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% load crispy_forms_tags %}
{% load crispy_forms_tags %} {% block title %}
Login | Chat Analytics
{% block title %}Login | Chat Analytics{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -13,17 +12,14 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %} {{ form|crispy }}
{{ form|crispy }}
<div class="d-grid gap-2"> <div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Login</button> <button type="submit" class="btn btn-primary">Login</button>
</div> </div>
</form> </form>
</div> </div>
<div class="card-footer text-center"> <div class="card-footer text-center">
<p class="mb-0"> <p class="mb-0">Don't have an account? <a href="{% url 'register' %}">Register</a></p>
Don't have an account? <a href="{% url 'register' %}">Register</a>
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,9 +1,7 @@
<!-- templates/accounts/password_change.html --> <!-- templates/accounts/password_change.html -->
{% extends 'base.html' %} {% extends 'base.html' %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block title %}Change Password | Chat Analytics{% endblock %} {% block title %}Change Password | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -24,8 +22,7 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %} {{ form|crispy }}
{{ form|crispy }}
<div class="d-grid gap-2"> <div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Change Password</button> <button type="submit" class="btn btn-primary">Change Password</button>
</div> </div>

View File

@ -1,8 +1,5 @@
<!-- templates/accounts/password_change_done.html --> <!-- templates/accounts/password_change_done.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% block title %}Password Changed | Chat Analytics{% endblock %}
{% block title %}Password Changed | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -25,10 +22,7 @@
<div class="mb-4"> <div class="mb-4">
<i class="fas fa-check-circle fa-4x text-success mb-3"></i> <i class="fas fa-check-circle fa-4x text-success mb-3"></i>
<h4>Your password has been changed successfully!</h4> <h4>Your password has been changed successfully!</h4>
<p> <p>Your new password is now active. You can use it the next time you log in.</p>
Your new password is now active. You can use it the next time you log
in.
</p>
</div> </div>
<div class="mt-4"> <div class="mt-4">

View File

@ -1,8 +1,6 @@
<!-- templates/accounts/profile.html --> <!-- templates/accounts/profile.html -->
{% extends 'base.html' %} {% extends 'base.html' %}
{% block title %}My Profile | Chat Analytics{% endblock %} {% block title %}My Profile | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -62,9 +60,7 @@
</div> </div>
</div> </div>
<div class="card-footer"> <div class="card-footer">
<a href="{% url 'password_change' %}" class="btn btn-primary" <a href="{% url 'password_change' %}" class="btn btn-primary">Change Password</a>
>Change Password</a
>
</div> </div>
</div> </div>
</div> </div>
@ -118,9 +114,7 @@
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title">Manage Users</h5> <h5 class="card-title">Manage Users</h5>
<p class="card-text"> <p class="card-text">Manage users and assign them to companies.</p>
Manage users and assign them to companies.
</p>
<a <a
href="{% url 'admin:accounts_customuser_changelist' %}" href="{% url 'admin:accounts_customuser_changelist' %}"
class="btn btn-primary" class="btn btn-primary"
@ -133,9 +127,7 @@
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title">Manage Companies</h5> <h5 class="card-title">Manage Companies</h5>
<p class="card-text"> <p class="card-text">Create and edit companies in the system.</p>
Create and edit companies in the system.
</p>
<a <a
href="{% url 'admin:accounts_company_changelist' %}" href="{% url 'admin:accounts_company_changelist' %}"
class="btn btn-primary" class="btn btn-primary"
@ -149,11 +141,7 @@
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title">Admin Dashboard</h5> <h5 class="card-title">Admin Dashboard</h5>
<p class="card-text">Go to the full admin dashboard.</p> <p class="card-text">Go to the full admin dashboard.</p>
<a <a href="{% url 'admin:index' %}" class="btn btn-primary">Admin Dashboard</a>
href="{% url 'admin:index' %}"
class="btn btn-primary"
>Admin Dashboard</a
>
</div> </div>
</div> </div>
</div> </div>
@ -162,12 +150,8 @@
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title">Manage Dashboards</h5> <h5 class="card-title">Manage Dashboards</h5>
<p class="card-text"> <p class="card-text">Create and edit dashboards for your company.</p>
Create and edit dashboards for your company. <a href="{% url 'create_dashboard' %}" class="btn btn-primary"
</p>
<a
href="{% url 'create_dashboard' %}"
class="btn btn-primary"
>Manage Dashboards</a >Manage Dashboards</a
> >
</div> </div>
@ -177,14 +161,8 @@
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title">Upload Data</h5> <h5 class="card-title">Upload Data</h5>
<p class="card-text"> <p class="card-text">Upload and manage data sources for analysis.</p>
Upload and manage data sources for analysis. <a href="{% url 'upload_data' %}" class="btn btn-primary">Upload Data</a>
</p>
<a
href="{% url 'upload_data' %}"
class="btn btn-primary"
>Upload Data</a
>
</div> </div>
</div> </div>
</div> </div>
@ -192,12 +170,8 @@
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title">Search Sessions</h5> <h5 class="card-title">Search Sessions</h5>
<p class="card-text"> <p class="card-text">Search and analyze chat sessions.</p>
Search and analyze chat sessions. <a href="{% url 'search_chat_sessions' %}" class="btn btn-primary"
</p>
<a
href="{% url 'search_chat_sessions' %}"
class="btn btn-primary"
>Search Sessions</a >Search Sessions</a
> >
</div> </div>

View File

@ -1,9 +1,8 @@
<!-- templates/accounts/register.html --> <!-- templates/accounts/register.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% load crispy_forms_tags %}
{% load crispy_forms_tags %} {% block title %}
Register | Chat Analytics
{% block title %}Register | Chat Analytics{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -13,17 +12,14 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %} {{ form|crispy }}
{{ form|crispy }}
<div class="d-grid gap-2"> <div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Register</button> <button type="submit" class="btn btn-primary">Register</button>
</div> </div>
</form> </form>
</div> </div>
<div class="card-footer text-center"> <div class="card-footer text-center">
<p class="mb-0"> <p class="mb-0">Already have an account? <a href="{% url 'login' %}">Login</a></p>
Already have an account? <a href="{% url 'login' %}">Login</a>
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -81,37 +81,24 @@
aria-expanded="false" aria-expanded="false"
> >
{% if user.company %} {% if user.company %}
<span class="badge bg-info me-1" <span class="badge bg-info me-1">{{ user.company.name }}</span>
>{{ user.company.name }}</span
>
{% endif %} {% endif %}
{{ user.username }} {{ user.username }}
</button> </button>
<ul <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
class="dropdown-menu dropdown-menu-end"
aria-labelledby="userDropdown"
>
<li> <li>
<a <a class="dropdown-item ajax-nav-link" href="{% url 'profile' %}">Profile</a>
class="dropdown-item ajax-nav-link"
href="{% url 'profile' %}"
>Profile</a
>
</li> </li>
{% if user.is_staff %} {% if user.is_staff %}
<li> <li>
<a class="dropdown-item" href="{% url 'admin:index' %}" <a class="dropdown-item" href="{% url 'admin:index' %}">Admin</a>
>Admin</a
>
</li> </li>
{% endif %} {% endif %}
<li> <li>
<hr class="dropdown-divider" /> <hr class="dropdown-divider" />
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'logout' %}" <a class="dropdown-item" href="{% url 'logout' %}">Logout</a>
>Logout</a
>
</li> </li>
</ul> </ul>
</div> </div>
@ -195,10 +182,7 @@
<li class="nav-header"><strong>Data Sources</strong></li> <li class="nav-header"><strong>Data Sources</strong></li>
{% for data_source in data_sources %} {% for data_source in data_sources %}
<li class="nav-item"> <li class="nav-item">
<a <a class="nav-link" href="{% url 'data_source_detail' data_source.id %}">
class="nav-link"
href="{% url 'data_source_detail' data_source.id %}"
>
<i class="fas fa-database me-2"></i> <i class="fas fa-database me-2"></i>
{{ data_source.name }} {{ data_source.name }}
</a> </a>
@ -224,10 +208,7 @@
{# </div> #} {# </div> #}
{# {% endif %} #} {# {% endif %} #}
<div id="main-content"> <div id="main-content">{% block content %}{% endblock %}</div>
{% block content %}
{% endblock %}
</div>
</main> </main>
</div> </div>
</div> </div>
@ -276,7 +257,7 @@
{% block extra_js %} {% block extra_js %}
{{ block.super }} {{ block.super }}
{% if messages %} {% if messages %}
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1100;"> <div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1100">
<!-- Toasts will be appended here --> <!-- Toasts will be appended here -->
</div> </div>
@ -296,9 +277,7 @@
if (!toastContainer) return; if (!toastContainer) return;
// Find all message data elements // Find all message data elements
const messageDataElements = document.querySelectorAll( const messageDataElements = document.querySelectorAll('script[id^="message-data-"]');
'script[id^="message-data-"]',
);
messageDataElements.forEach(function (dataElement) { messageDataElements.forEach(function (dataElement) {
try { try {
const messageData = JSON.parse(dataElement.textContent); const messageData = JSON.parse(dataElement.textContent);
@ -330,10 +309,7 @@
} }
const toastId = const toastId =
"toast-" + "toast-" + Date.now() + "-" + Math.random().toString(36).substring(2, 11);
Date.now() +
"-" +
Math.random().toString(36).substring(2, 11);
const toastHtml = ` const toastHtml = `
<div id="${toastId}" class="toast ${toastClass}" role="alert" aria-live="assertive" aria-atomic="true"> <div id="${toastId}" class="toast ${toastClass}" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header"> <div class="toast-header">

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block title %}
{% block title %}Chat Session {{ session.session_id }} | Chat Analytics{% endblock %} Chat Session {{ session.session_id }} | Chat Analytics
{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -31,12 +31,8 @@
<strong>Start Time:</strong> <strong>Start Time:</strong>
{{ session.start_time|date:"F d, Y H:i" }} {{ session.start_time|date:"F d, Y H:i" }}
</p> </p>
<p> <p><strong>End Time:</strong> {{ session.end_time|date:"F d, Y H:i" }}</p>
<strong>End Time:</strong> {{ session.end_time|date:"F d, Y H:i" }} <p><strong>IP Address:</strong> {{ session.ip_address|default:"N/A" }}</p>
</p>
<p>
<strong>IP Address:</strong> {{ session.ip_address|default:"N/A" }}
</p>
<p><strong>Country:</strong> {{ session.country|default:"N/A" }}</p> <p><strong>Country:</strong> {{ session.country|default:"N/A" }}</p>
<p><strong>Language:</strong> {{ session.language|default:"N/A" }}</p> <p><strong>Language:</strong> {{ session.language|default:"N/A" }}</p>
</div> </div>
@ -47,27 +43,19 @@
{{ session.avg_response_time|floatformat:2 }}s {{ session.avg_response_time|floatformat:2 }}s
</p> </p>
<p><strong>Tokens:</strong> {{ session.tokens }}</p> <p><strong>Tokens:</strong> {{ session.tokens }}</p>
<p> <p><strong>Token Cost:</strong> €{{ session.tokens_eur|floatformat:2 }}</p>
<strong>Token Cost:</strong> €{{ session.tokens_eur|floatformat:2 }}
</p>
<p><strong>Category:</strong> {{ session.category|default:"N/A" }}</p> <p><strong>Category:</strong> {{ session.category|default:"N/A" }}</p>
<p> <p>
<strong>Sentiment:</strong> <strong>Sentiment:</strong>
{% if session.sentiment %} {% if session.sentiment %}
{% if 'positive' in session.sentiment|lower %} {% if 'positive' in session.sentiment|lower %}
<span class="badge bg-success" <span class="badge bg-success">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% elif 'negative' in session.sentiment|lower %} {% elif 'negative' in session.sentiment|lower %}
<span class="badge bg-danger">{{ session.sentiment }}</span> <span class="badge bg-danger">{{ session.sentiment }}</span>
{% elif 'neutral' in session.sentiment|lower %} {% elif 'neutral' in session.sentiment|lower %}
<span class="badge bg-warning" <span class="badge bg-warning">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% else %} {% else %}
<span class="badge bg-secondary" <span class="badge bg-secondary">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% endif %} {% endif %}
{% else %} {% else %}
<span class="text-muted">N/A</span> <span class="text-muted">N/A</span>
@ -130,8 +118,8 @@
</div> </div>
<div class="card-body"> <div class="card-body">
{% if session.full_transcript %} {% if session.full_transcript %}
<div class="chat-transcript" style="max-height: 500px; overflow-y: auto;"> <div class="chat-transcript" style="max-height: 500px; overflow-y: auto">
<pre style="white-space: pre-wrap; font-family: inherit;"> <pre style="white-space: pre-wrap; font-family: inherit">
{{ session.full_transcript }}</pre {{ session.full_transcript }}</pre
> >
</div> </div>

View File

@ -1,9 +1,8 @@
<!-- templates/dashboard/dashboard.html --> <!-- templates/dashboard/dashboard.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% load static %}
{% load static %} {% block title %}
Dashboard | Chat Analytics
{% block title %}Dashboard | Chat Analytics{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -42,30 +41,22 @@
</button> </button>
<ul class="dropdown-menu" aria-labelledby="timeRangeDropdown"> <ul class="dropdown-menu" aria-labelledby="timeRangeDropdown">
<li> <li>
<a <a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=7"
class="dropdown-item"
href="?dashboard_id={{ selected_dashboard.id }}&time_range=7"
>Last 7 days</a >Last 7 days</a
> >
</li> </li>
<li> <li>
<a <a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=30"
class="dropdown-item"
href="?dashboard_id={{ selected_dashboard.id }}&time_range=30"
>Last 30 days</a >Last 30 days</a
> >
</li> </li>
<li> <li>
<a <a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=90"
class="dropdown-item"
href="?dashboard_id={{ selected_dashboard.id }}&time_range=90"
>Last 90 days</a >Last 90 days</a
> >
</li> </li>
<li> <li>
<a <a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=all"
class="dropdown-item"
href="?dashboard_id={{ selected_dashboard.id }}&time_range=all"
>All time</a >All time</a
> >
</li> </li>
@ -159,30 +150,31 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
<!-- prettier-ignore-start --> <!-- prettier-ignore-start -->
<!-- Store the JSON data in script tags to avoid parsing issues --> <!-- Store the JSON data in script tags to avoid parsing issues -->
<script type="application/json" id="time-series-data">{{ time_series_data_json|safe }}</script> <script type="application/json" id="time-series-data">
<script type="application/json" id="sentiment-data">{{ sentiment_data_json|safe }}</script> {{ time_series_data_json|safe }}
<script type="application/json" id="country-data">{{ country_data_json|safe }}</script> </script>
<script type="application/json" id="category-data">{{ category_data_json|safe }}</script> <script type="application/json" id="sentiment-data">
<!-- prettier-ignore-end --> {{ sentiment_data_json|safe }}
</script>
<script type="application/json" id="country-data">
{{ country_data_json|safe }}
</script>
<script type="application/json" id="category-data">
{{ category_data_json|safe }}
</script>
<!-- prettier-ignore-end -->
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
try { try {
// Parse the dashboard data components from script tags // Parse the dashboard data components from script tags
const timeSeriesData = JSON.parse( const timeSeriesData = JSON.parse(document.getElementById("time-series-data").textContent);
document.getElementById("time-series-data").textContent, const sentimentData = JSON.parse(document.getElementById("sentiment-data").textContent);
);
const sentimentData = JSON.parse(
document.getElementById("sentiment-data").textContent,
);
const countryData = JSON.parse(document.getElementById("country-data").textContent); const countryData = JSON.parse(document.getElementById("country-data").textContent);
const categoryData = JSON.parse( const categoryData = JSON.parse(document.getElementById("category-data").textContent);
document.getElementById("category-data").textContent,
);
console.log("Time series data loaded:", timeSeriesData); console.log("Time series data loaded:", timeSeriesData);
console.log("Sentiment data loaded:", sentimentData); console.log("Sentiment data loaded:", sentimentData);
@ -233,8 +225,7 @@
const sentimentValues = sentimentData.map((item) => item.count); const sentimentValues = sentimentData.map((item) => item.count);
const sentimentColors = sentimentLabels.map((sentiment) => { const sentimentColors = sentimentLabels.map((sentiment) => {
if (sentiment.toLowerCase().includes("positive")) return "rgb(75, 192, 92)"; if (sentiment.toLowerCase().includes("positive")) return "rgb(75, 192, 92)";
if (sentiment.toLowerCase().includes("negative")) if (sentiment.toLowerCase().includes("negative")) return "rgb(255, 99, 132)";
return "rgb(255, 99, 132)";
if (sentiment.toLowerCase().includes("neutral")) return "rgb(255, 205, 86)"; if (sentiment.toLowerCase().includes("neutral")) return "rgb(255, 205, 86)";
return "rgb(201, 203, 207)"; return "rgb(201, 203, 207)";
}); });

View File

@ -1,7 +1,4 @@
{% extends 'base.html' %} {% extends 'base.html' %} {% block title %}Delete Dashboard | Chat Analytics{% endblock %}
{% block title %}Delete Dashboard | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -22,12 +19,11 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<p class="lead"> <p class="lead">
Are you sure you want to delete the dashboard Are you sure you want to delete the dashboard "<strong>{{ dashboard.name }}</strong>"?
"<strong>{{ dashboard.name }}</strong>"?
</p> </p>
<p> <p>
This action cannot be undone. The dashboard will be permanently deleted, but This action cannot be undone. The dashboard will be permanently deleted, but the
the underlying data sources will remain intact. underlying data sources will remain intact.
</p> </p>
<form method="post"> <form method="post">

View File

@ -1,11 +1,12 @@
{% extends 'base.html' %} {% extends 'base.html' %} {% load crispy_forms_tags %}
{% load crispy_forms_tags %}
{% block title %} {% block title %}
{% if is_create %}Create Dashboard{% else %}Edit Dashboard{% endif %} {% if is_create %}
Create Dashboard
{% else %}
Edit Dashboard
{% endif %}
| Chat Analytics | Chat Analytics
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -28,8 +29,7 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %} {{ form|crispy }}
{{ form|crispy }}
<div class="d-grid gap-2"> <div class="d-grid gap-2">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary">
{% if is_create %}Create Dashboard{% else %}Update Dashboard{% endif %} {% if is_create %}Create Dashboard{% else %}Update Dashboard{% endif %}

View File

@ -1,8 +1,5 @@
<!-- templates/dashboard/data_source_confirm_delete.html --> <!-- templates/dashboard/data_source_confirm_delete.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% block title %}Delete Data Source | Chat Analytics{% endblock %}
{% block title %}Delete Data Source | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -30,17 +27,14 @@
"<strong>{{ data_source.name }}</strong>"? "<strong>{{ data_source.name }}</strong>"?
</p> </p>
<p> <p>
This action cannot be undone. The data source and all associated chat This action cannot be undone. The data source and all associated chat sessions
sessions ({{ data_source.chat_sessions.count }} sessions) will be ({{ data_source.chat_sessions.count }} sessions) will be permanently deleted.
permanently deleted.
</p> </p>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
<div class="d-flex justify-content-between mt-4"> <div class="d-flex justify-content-between mt-4">
<a <a href="{% url 'data_source_detail' data_source.id %}" class="btn btn-secondary"
href="{% url 'data_source_detail' data_source.id %}"
class="btn btn-secondary"
>Cancel</a >Cancel</a
> >
<button type="submit" class="btn btn-danger">Delete Data Source</button> <button type="submit" class="btn btn-danger">Delete Data Source</button>

View File

@ -1,9 +1,9 @@
<!-- templates/dashboard/data_source_detail.html --> <!-- templates/dashboard/data_source_detail.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% load dashboard_extras %}
{% load dashboard_extras %} {% block title %}
{{ data_source.name }}
{% block title %}{{ data_source.name }} | Chat Analytics{% endblock %} | Chat Analytics
{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -19,10 +19,7 @@
> >
<i class="fas fa-file-csv"></i> Export CSV <i class="fas fa-file-csv"></i> Export CSV
</a> </a>
<a <a href="{% url 'delete_data_source' data_source.id %}" class="btn btn-sm btn-outline-danger">
href="{% url 'delete_data_source' data_source.id %}"
class="btn btn-sm btn-outline-danger"
>
<i class="fas fa-trash"></i> Delete <i class="fas fa-trash"></i> Delete
</a> </a>
</div> </div>
@ -68,11 +65,7 @@
placeholder="Search sessions..." placeholder="Search sessions..."
aria-label="Search sessions" aria-label="Search sessions"
/> />
<input <input type="hidden" name="data_source_id" value="{{ data_source.id }}" />
type="hidden"
name="data_source_id"
value="{{ data_source.id }}"
/>
<button class="btn btn-outline-primary" type="submit"> <button class="btn btn-outline-primary" type="submit">
<i class="fas fa-search"></i> <i class="fas fa-search"></i>
</button> </button>
@ -115,21 +108,13 @@
<td> <td>
{% if session.sentiment %} {% if session.sentiment %}
{% if 'positive' in session.sentiment|lower %} {% if 'positive' in session.sentiment|lower %}
<span class="badge bg-success" <span class="badge bg-success">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% elif 'negative' in session.sentiment|lower %} {% elif 'negative' in session.sentiment|lower %}
<span class="badge bg-danger" <span class="badge bg-danger">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% elif 'neutral' in session.sentiment|lower %} {% elif 'neutral' in session.sentiment|lower %}
<span class="badge bg-warning" <span class="badge bg-warning">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% else %} {% else %}
<span class="badge bg-secondary" <span class="badge bg-secondary">{{ session.sentiment }}</span>
>{{ session.sentiment }}</span
>
{% endif %} {% endif %}
{% else %} {% else %}
<span class="text-muted">N/A</span> <span class="text-muted">N/A</span>
@ -147,10 +132,7 @@
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
{% else %} {% else %}
<button <button class="btn btn-sm btn-outline-secondary" disabled>
class="btn btn-sm btn-outline-secondary"
disabled
>
<i class="fas fa-eye-slash"></i> <i class="fas fa-eye-slash"></i>
</button> </button>
{% endif %} {% endif %}
@ -158,9 +140,7 @@
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="9" class="text-center"> <td colspan="9" class="text-center">No chat sessions found.</td>
No chat sessions found.
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -197,23 +177,17 @@
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% for num in page_obj.paginator.page_range %} {% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %} {% if page_obj.number == num %}
<li class="page-item active"> <li class="page-item active">
<a class="page-link" href="?page={{ num }}" <a class="page-link" href="?page={{ num }}">{{ num }}</a>
>{{ num }}</a
>
</li> </li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %} {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="?page={{ num }}" <a class="page-link" href="?page={{ num }}">{{ num }}</a>
>{{ num }}</a
>
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if page_obj.has_next %} {% if page_obj.has_next %}
<li class="page-item"> <li class="page-item">
<a <a

View File

@ -1,9 +1,8 @@
<!-- templates/dashboard/data_view.html --> <!-- templates/dashboard/data_view.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% load dashboard_extras %}
{% load dashboard_extras %} {% block title %}
Data View | Chat Analytics
{% block title %}Data View | Chat Analytics{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -11,10 +10,7 @@
<h1 class="h2">Data View</h1> <h1 class="h2">Data View</h1>
<div class="btn-toolbar mb-2 mb-md-0"> <div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2"> <div class="btn-group me-2">
<a <a href="{% url 'dashboard' %}" class="btn btn-sm btn-outline-secondary ajax-nav-link">
href="{% url 'dashboard' %}"
class="btn btn-sm btn-outline-secondary ajax-nav-link"
>
<i class="fas fa-arrow-left"></i> Back to Dashboard <i class="fas fa-arrow-left"></i> Back to Dashboard
</a> </a>
{% if selected_data_source %} {% if selected_data_source %}
@ -41,24 +37,16 @@
<a class="dropdown-item ajax-nav-link" href="?view=all">All Sessions</a> <a class="dropdown-item ajax-nav-link" href="?view=all">All Sessions</a>
</li> </li>
<li> <li>
<a class="dropdown-item ajax-nav-link" href="?view=recent" <a class="dropdown-item ajax-nav-link" href="?view=recent">Recent Sessions</a>
>Recent Sessions</a
>
</li> </li>
<li> <li>
<a class="dropdown-item ajax-nav-link" href="?view=positive" <a class="dropdown-item ajax-nav-link" href="?view=positive">Positive Sentiment</a>
>Positive Sentiment</a
>
</li> </li>
<li> <li>
<a class="dropdown-item ajax-nav-link" href="?view=negative" <a class="dropdown-item ajax-nav-link" href="?view=negative">Negative Sentiment</a>
>Negative Sentiment</a
>
</li> </li>
<li> <li>
<a class="dropdown-item ajax-nav-link" href="?view=escalated" <a class="dropdown-item ajax-nav-link" href="?view=escalated">Escalated Sessions</a>
>Escalated Sessions</a
>
</li> </li>
</ul> </ul>
</div> </div>
@ -75,16 +63,14 @@
<div class="card-body"> <div class="card-body">
<form method="get" class="row g-3 align-items-center filter-form"> <form method="get" class="row g-3 align-items-center filter-form">
<div class="col-md-6"> <div class="col-md-6">
<select <select name="data_source_id" class="form-select" aria-label="Select Data Source">
name="data_source_id"
class="form-select"
aria-label="Select Data Source"
>
<option value="">All Data Sources</option> <option value="">All Data Sources</option>
{% for ds in data_sources %} {% for ds in data_sources %}
<option <option
value="{{ ds.id }}" value="{{ ds.id }}"
{% if selected_data_source.id == ds.id %}selected{% endif %} {% if selected_data_source.id == ds.id %}
selected
{% endif %}
> >
{{ ds.name }} {{ ds.name }}
</option> </option>
@ -93,28 +79,17 @@
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<select name="view" class="form-select" aria-label="Select View"> <select name="view" class="form-select" aria-label="Select View">
<option value="all" {% if view == 'all' %}selected{% endif %}> <option value="all" {% if view == 'all' %}selected{% endif %}>All Sessions</option>
All Sessions
</option>
<option value="recent" {% if view == 'recent' %}selected{% endif %}> <option value="recent" {% if view == 'recent' %}selected{% endif %}>
Recent Sessions Recent Sessions
</option> </option>
<option <option value="positive" {% if view == 'positive' %}selected{% endif %}>
value="positive"
{% if view == 'positive' %}selected{% endif %}
>
Positive Sentiment Positive Sentiment
</option> </option>
<option <option value="negative" {% if view == 'negative' %}selected{% endif %}>
value="negative"
{% if view == 'negative' %}selected{% endif %}
>
Negative Sentiment Negative Sentiment
</option> </option>
<option <option value="escalated" {% if view == 'escalated' %}selected{% endif %}>
value="escalated"
{% if view == 'escalated' %}selected{% endif %}
>
Escalated Sessions Escalated Sessions
</option> </option>
</select> </select>
@ -136,28 +111,14 @@
<h5 class="card-title mb-0">Export Data</h5> <h5 class="card-title mb-0">Export Data</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<form <form id="export-form" method="get" action="{% url 'export_chats_csv' %}" class="row g-3">
id="export-form"
method="get"
action="{% url 'export_chats_csv' %}"
class="row g-3"
>
<!-- Pass current filters to export --> <!-- Pass current filters to export -->
<input <input type="hidden" name="data_source_id" value="{{ selected_data_source.id }}" />
type="hidden"
name="data_source_id"
value="{{ selected_data_source.id }}"
/>
<input type="hidden" name="view" value="{{ view }}" /> <input type="hidden" name="view" value="{{ view }}" />
<div class="col-md-3"> <div class="col-md-3">
<label for="start_date" class="form-label">Start Date</label> <label for="start_date" class="form-label">Start Date</label>
<input <input type="date" name="start_date" id="start_date" class="form-control" />
type="date"
name="start_date"
id="start_date"
class="form-control"
/>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<label for="end_date" class="form-label">End Date</label> <label for="end_date" class="form-label">End Date</label>
@ -211,9 +172,7 @@
{% if selected_data_source %} {% if selected_data_source %}
for {{ selected_data_source.name }} for {{ selected_data_source.name }}
{% endif %} {% endif %}
{% if view != 'all' %} {% if view != 'all' %}({{ view|title }}){% endif %}
({{ view|title }})
{% endif %}
</h5> </h5>
<span class="badge bg-primary">{{ page_obj.paginator.count }} sessions</span> <span class="badge bg-primary">{{ page_obj.paginator.count }} sessions</span>
</div> </div>
@ -227,9 +186,7 @@
</div> </div>
<!-- Data table container that will be updated via AJAX --> <!-- Data table container that will be updated via AJAX -->
<div id="ajax-content-container"> <div id="ajax-content-container">{% include "dashboard/partials/data_table.html" %}</div>
{% include "dashboard/partials/data_table.html" %}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -288,7 +245,6 @@
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
<script> <script>
// Function to update the summary section with new data // Function to update the summary section with new data

View File

@ -1,8 +1,5 @@
<!-- templates/dashboard/no_company.html --> <!-- templates/dashboard/no_company.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% block title %}No Company | Chat Analytics{% endblock %}
{% block title %}No Company | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -20,22 +17,18 @@
<div class="mb-4"> <div class="mb-4">
<i class="fas fa-building fa-4x text-warning mb-3"></i> <i class="fas fa-building fa-4x text-warning mb-3"></i>
<h4>You are not currently associated with any company</h4> <h4>You are not currently associated with any company</h4>
<p class="lead"> <p class="lead">You need to be associated with a company to access the dashboard.</p>
You need to be associated with a company to access the dashboard.
</p>
</div> </div>
<p> <p>
Please contact an administrator to have your account assigned to a company. Please contact an administrator to have your account assigned to a company. Once your
Once your account is associated with a company, you'll be able to access the account is associated with a company, you'll be able to access the dashboard and its
dashboard and its features. features.
</p> </p>
<div class="mt-4"> <div class="mt-4">
<a href="{% url 'profile' %}" class="btn btn-primary">View Your Profile</a> <a href="{% url 'profile' %}" class="btn btn-primary">View Your Profile</a>
<a href="{% url 'logout' %}" class="btn btn-outline-secondary ms-2" <a href="{% url 'logout' %}" class="btn btn-outline-secondary ms-2">Logout</a>
>Logout</a
>
</div> </div>
</div> </div>
</div> </div>

View File

@ -99,9 +99,7 @@
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% for num in page_obj.paginator.page_range %}{% if page_obj.number == num %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"> <li class="page-item active">
<a <a
class="page-link pagination-link" class="page-link pagination-link"
@ -119,9 +117,7 @@
>{{ num }}</a >{{ num }}</a
> >
</li> </li>
{% endif %} {% endif %}{% endfor %}
{% endfor %}
{% if page_obj.has_next %} {% if page_obj.has_next %}
<li class="page-item"> <li class="page-item">
<a <a

View File

@ -20,9 +20,7 @@
<td>{{ session.session_id|truncatechars:10 }}</td> <td>{{ session.session_id|truncatechars:10 }}</td>
<td>{{ session.start_time|date:"M d, Y H:i" }}</td> <td>{{ session.start_time|date:"M d, Y H:i" }}</td>
<td> <td>
<a <a href="{% url 'data_source_detail' session.data_source.id %}" class="ajax-nav-link"
href="{% url 'data_source_detail' session.data_source.id %}"
class="ajax-nav-link"
>{{ session.data_source.name|truncatechars:15 }}</a >{{ session.data_source.name|truncatechars:15 }}</a
> >
</td> </td>
@ -62,9 +60,7 @@
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="9" class="text-center"> <td colspan="9" class="text-center">No chat sessions found matching your criteria.</td>
No chat sessions found matching your criteria.
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -107,9 +103,7 @@
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% for num in page_obj.paginator.page_range %}{% if page_obj.number == num %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"> <li class="page-item active">
<a <a
class="page-link pagination-link" class="page-link pagination-link"
@ -127,9 +121,7 @@
>{{ num }}</a >{{ num }}</a
> >
</li> </li>
{% endif %} {% endif %}{% endfor %}
{% endfor %}
{% if page_obj.has_next %} {% if page_obj.has_next %}
<li class="page-item"> <li class="page-item">
<a <a

View File

@ -1,8 +1,5 @@
<!-- templates/dashboard/search_results.html --> <!-- templates/dashboard/search_results.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% block title %}Search Results | Chat Analytics{% endblock %}
{% block title %}Search Results | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
@ -22,11 +19,7 @@
<h5 class="card-title mb-0">Search Chat Sessions</h5> <h5 class="card-title mb-0">Search Chat Sessions</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<form <form method="get" action="{% url 'search_chat_sessions' %}" class="search-form">
method="get"
action="{% url 'search_chat_sessions' %}"
class="search-form"
>
<div class="input-group"> <div class="input-group">
<input <input
type="text" type="text"
@ -37,11 +30,7 @@
aria-label="Search sessions" aria-label="Search sessions"
/> />
{% if data_source %} {% if data_source %}
<input <input type="hidden" name="data_source_id" value="{{ data_source.id }}" />
type="hidden"
name="data_source_id"
value="{{ data_source.id }}"
/>
{% endif %} {% endif %}
<button class="btn btn-outline-primary" type="submit"> <button class="btn btn-outline-primary" type="submit">
<i class="fas fa-search"></i> Search <i class="fas fa-search"></i> Search
@ -49,8 +38,8 @@
</div> </div>
<div class="mt-2 text-muted"> <div class="mt-2 text-muted">
<small <small
>Search by session ID, country, language, sentiment, category, or >Search by session ID, country, language, sentiment, category, or message
message content.</small content.</small
> >
</div> </div>
</form> </form>
@ -87,7 +76,6 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
<!-- No need for extra JavaScript here, using common ajax-pagination.js --> <!-- No need for extra JavaScript here, using common ajax-pagination.js -->
{% endblock %} {% endblock %}

View File

@ -1,10 +1,8 @@
<!-- templates/dashboard/upload.html --> <!-- templates/dashboard/upload.html -->
{% extends 'base.html' %} {% extends 'base.html' %} {% load crispy_forms_tags %} {% load dashboard_extras %}
{% load crispy_forms_tags %} {% block title %}
{% load dashboard_extras %} Upload Data | Chat Analytics
{% endblock %}
{% block title %}Upload Data | Chat Analytics{% endblock %}
{% block content %} {% block content %}
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom" class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"

View File

@ -1,15 +1,4 @@
{ {
"name": "livegraphsdjango",
"version": "0.1.0",
"description": "Live Graphs Django Dashboard",
"private": true,
"scripts": {
"lint": "eslint dashboard_project/static/js/",
"format": "prettier --write \"dashboard_project/static/**/*.{js,css,html}\"",
"format:check": "prettier --check \"dashboard_project/static/**/*.{js,css,html}\"",
"stylelint": "stylelint \"dashboard_project/static/css/**/*.css\" --fix",
"stylelint:check": "stylelint \"dashboard_project/static/css/**/*.css\""
},
"devDependencies": { "devDependencies": {
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-jinja-template": "^2.1.0" "prettier-plugin-jinja-template": "^2.1.0"