mirror of
https://github.com/kjanat/livegraphs-django.git
synced 2026-02-13 12:55:42 +01:00
chore(deps): update pre-commit config and apply bulk formatting
- build(pre-commit): upgrade hooks (django-upgrade 1.29.1, uv 0.9.7, ruff 0.14.3, bandit 1.8.6) - build(pre-commit): add uv-lock hook, tombi TOML formatter, prettier-plugin-packagejson - build(pre-commit): disable Django check hooks (commented out) - build(pre-commit): switch npx → bunx for prettier execution - build(node): add bun.lock, update prettier config with schema + packagejson plugin - style: apply ruff format to all Python files (comments, spacing, imports) - style: apply prettier format to all JS/CSS files (comment styles, spacing) - style: apply tombi format to pyproject.toml (reordered sections, consistent formatting) - chore: remove emoji from bash script comments for consistency BREAKING CHANGE: Django check and migration check hooks disabled in pre-commit config
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# !/usr/bin/env python
|
||||
"""
|
||||
Entry point for Django commands executed as Python modules.
|
||||
This enables commands like `python -m runserver`.
|
||||
|
||||
@@ -4,7 +4,7 @@ ASGI config for dashboard_project project.
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
|
||||
<https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/>
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# dashboard/management/__init__.py
|
||||
|
||||
# This file is intentionally left empty to mark the directory as a Python package
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# dashboard/management/commands/__init__.py
|
||||
|
||||
# This file is intentionally left empty to mark the directory as a Python package
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# dashboard/templatetags/__init__.py
|
||||
|
||||
# This file is intentionally left empty to mark the directory as a Python package
|
||||
|
||||
@@ -200,12 +200,10 @@ def chat_session_detail_view(request, session_id):
|
||||
# Check if this is an AJAX navigation request
|
||||
if is_ajax_navigation(request):
|
||||
html_content = render_to_string("dashboard/chat_session_detail.html", context, request=request)
|
||||
return JsonResponse(
|
||||
{
|
||||
"html": html_content,
|
||||
"title": f"Chat Session {session_id} | Chat Analytics",
|
||||
}
|
||||
)
|
||||
return JsonResponse({
|
||||
"html": html_content,
|
||||
"title": f"Chat Session {session_id} | Chat Analytics",
|
||||
})
|
||||
|
||||
return render(request, "dashboard/chat_session_detail.html", context)
|
||||
|
||||
@@ -282,12 +280,10 @@ def edit_dashboard_view(request, dashboard_id):
|
||||
# Check if this is an AJAX navigation request
|
||||
if is_ajax_navigation(request):
|
||||
html_content = render_to_string("dashboard/dashboard_form.html", context, request=request)
|
||||
return JsonResponse(
|
||||
{
|
||||
"html": html_content,
|
||||
"title": f"Edit Dashboard: {dashboard.name} | Chat Analytics",
|
||||
}
|
||||
)
|
||||
return JsonResponse({
|
||||
"html": html_content,
|
||||
"title": f"Edit Dashboard: {dashboard.name} | Chat Analytics",
|
||||
})
|
||||
|
||||
return render(request, "dashboard/dashboard_form.html", context)
|
||||
|
||||
@@ -349,6 +345,8 @@ def delete_data_source_view(request, data_source_id):
|
||||
|
||||
|
||||
# API views for dashboard data
|
||||
|
||||
|
||||
@login_required
|
||||
def dashboard_data_api(request, dashboard_id):
|
||||
"""API endpoint for dashboard data"""
|
||||
@@ -450,26 +448,24 @@ def search_chat_sessions(request):
|
||||
|
||||
# Check if this is an AJAX pagination request
|
||||
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"html_data": render(request, "dashboard/partials/search_results_table.html", context).content.decode(
|
||||
"utf-8"
|
||||
),
|
||||
"page_obj": {
|
||||
"number": page_obj.number,
|
||||
"has_previous": page_obj.has_previous(),
|
||||
"has_next": page_obj.has_next(),
|
||||
"previous_page_number": page_obj.previous_page_number() if page_obj.has_previous() else None,
|
||||
"next_page_number": page_obj.next_page_number() if page_obj.has_next() else None,
|
||||
"paginator": {
|
||||
"num_pages": page_obj.paginator.num_pages,
|
||||
"count": page_obj.paginator.count,
|
||||
},
|
||||
return JsonResponse({
|
||||
"status": "success",
|
||||
"html_data": render(request, "dashboard/partials/search_results_table.html", context).content.decode(
|
||||
"utf-8"
|
||||
),
|
||||
"page_obj": {
|
||||
"number": page_obj.number,
|
||||
"has_previous": page_obj.has_previous(),
|
||||
"has_next": page_obj.has_next(),
|
||||
"previous_page_number": page_obj.previous_page_number() if page_obj.has_previous() else None,
|
||||
"next_page_number": page_obj.next_page_number() if page_obj.has_next() else None,
|
||||
"paginator": {
|
||||
"num_pages": page_obj.paginator.num_pages,
|
||||
"count": page_obj.paginator.count,
|
||||
},
|
||||
"query": query,
|
||||
}
|
||||
)
|
||||
},
|
||||
"query": query,
|
||||
})
|
||||
|
||||
return render(request, "dashboard/search_results.html", context)
|
||||
|
||||
@@ -554,26 +550,24 @@ def data_view(request):
|
||||
|
||||
# Check if this is an AJAX pagination request
|
||||
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"html_data": render(request, "dashboard/partials/data_table.html", context).content.decode("utf-8"),
|
||||
"page_obj": {
|
||||
"number": page_obj.number,
|
||||
"has_previous": page_obj.has_previous(),
|
||||
"has_next": page_obj.has_next(),
|
||||
"previous_page_number": page_obj.previous_page_number() if page_obj.has_previous() else None,
|
||||
"next_page_number": page_obj.next_page_number() if page_obj.has_next() else None,
|
||||
"paginator": {
|
||||
"num_pages": page_obj.paginator.num_pages,
|
||||
"count": page_obj.paginator.count,
|
||||
},
|
||||
return JsonResponse({
|
||||
"status": "success",
|
||||
"html_data": render(request, "dashboard/partials/data_table.html", context).content.decode("utf-8"),
|
||||
"page_obj": {
|
||||
"number": page_obj.number,
|
||||
"has_previous": page_obj.has_previous(),
|
||||
"has_next": page_obj.has_next(),
|
||||
"previous_page_number": page_obj.previous_page_number() if page_obj.has_previous() else None,
|
||||
"next_page_number": page_obj.next_page_number() if page_obj.has_next() else None,
|
||||
"paginator": {
|
||||
"num_pages": page_obj.paginator.num_pages,
|
||||
"count": page_obj.paginator.count,
|
||||
},
|
||||
"view": view,
|
||||
"avg_response_time": avg_response_time,
|
||||
"avg_messages": avg_messages,
|
||||
"escalation_rate": escalation_rate,
|
||||
}
|
||||
)
|
||||
},
|
||||
"view": view,
|
||||
"avg_response_time": avg_response_time,
|
||||
"avg_messages": avg_messages,
|
||||
"escalation_rate": escalation_rate,
|
||||
})
|
||||
|
||||
return render(request, "dashboard/data_view.html", context)
|
||||
|
||||
@@ -91,51 +91,47 @@ def export_chats_csv(request):
|
||||
writer = csv.writer(response)
|
||||
|
||||
# Write CSV header
|
||||
writer.writerow(
|
||||
[
|
||||
"Session ID",
|
||||
"Start Time",
|
||||
"End Time",
|
||||
"IP Address",
|
||||
"Country",
|
||||
"Language",
|
||||
"Messages Sent",
|
||||
"Sentiment",
|
||||
"Escalated",
|
||||
"Forwarded HR",
|
||||
"Full Transcript",
|
||||
"Avg Response Time (s)",
|
||||
"Tokens",
|
||||
"Tokens EUR",
|
||||
"Category",
|
||||
"Initial Message",
|
||||
"User Rating",
|
||||
]
|
||||
)
|
||||
writer.writerow([
|
||||
"Session ID",
|
||||
"Start Time",
|
||||
"End Time",
|
||||
"IP Address",
|
||||
"Country",
|
||||
"Language",
|
||||
"Messages Sent",
|
||||
"Sentiment",
|
||||
"Escalated",
|
||||
"Forwarded HR",
|
||||
"Full Transcript",
|
||||
"Avg Response Time (s)",
|
||||
"Tokens",
|
||||
"Tokens EUR",
|
||||
"Category",
|
||||
"Initial Message",
|
||||
"User Rating",
|
||||
])
|
||||
|
||||
# Write data rows
|
||||
for session in sessions:
|
||||
writer.writerow(
|
||||
[
|
||||
session.session_id,
|
||||
session.start_time,
|
||||
session.end_time,
|
||||
session.ip_address,
|
||||
session.country,
|
||||
session.language,
|
||||
session.messages_sent,
|
||||
session.sentiment,
|
||||
"Yes" if session.escalated else "No",
|
||||
"Yes" if session.forwarded_hr else "No",
|
||||
session.full_transcript,
|
||||
session.avg_response_time,
|
||||
session.tokens,
|
||||
session.tokens_eur,
|
||||
session.category,
|
||||
session.initial_msg,
|
||||
session.user_rating,
|
||||
]
|
||||
)
|
||||
writer.writerow([
|
||||
session.session_id,
|
||||
session.start_time,
|
||||
session.end_time,
|
||||
session.ip_address,
|
||||
session.country,
|
||||
session.language,
|
||||
session.messages_sent,
|
||||
session.sentiment,
|
||||
"Yes" if session.escalated else "No",
|
||||
"Yes" if session.forwarded_hr else "No",
|
||||
session.full_transcript,
|
||||
session.avg_response_time,
|
||||
session.tokens,
|
||||
session.tokens_eur,
|
||||
session.category,
|
||||
session.initial_msg,
|
||||
session.user_rating,
|
||||
])
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ ASGI config for dashboard_project project.
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
|
||||
<https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/>
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
@@ -2,18 +2,24 @@ import os
|
||||
|
||||
from celery import Celery
|
||||
|
||||
# Set the default Django settings module for the 'celery' program.
|
||||
# Set the default Django settings module for the 'celery' program
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dashboard_project.settings")
|
||||
|
||||
app = Celery("dashboard_project")
|
||||
|
||||
# Using a string here means the worker doesn't have to serialize
|
||||
# the configuration object to child processes.
|
||||
|
||||
# the configuration object to child processes
|
||||
|
||||
# - namespace='CELERY' means all celery-related configuration keys
|
||||
# should have a `CELERY_` prefix.
|
||||
|
||||
# should have a `CELERY_` prefix
|
||||
|
||||
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||
|
||||
# Load task modules from all registered Django app configs.
|
||||
# Load task modules from all registered Django app configs
|
||||
|
||||
app.autodiscover_tasks()
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from pathlib import Path
|
||||
from django.core.management.utils import get_random_secret_key
|
||||
|
||||
# Load environment variables from .env file if present
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
|
||||
@@ -14,18 +15,22 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
# SECURITY WARNING: keep the secret key used in production secret
|
||||
|
||||
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", get_random_secret_key())
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
# SECURITY WARNING: don't run with debug turned on in production
|
||||
|
||||
DEBUG = os.environ.get("DJANGO_DEBUG", "True") == "True"
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
@@ -80,6 +85,7 @@ TEMPLATES = [
|
||||
WSGI_APPLICATION = "dashboard_project.wsgi.application"
|
||||
|
||||
# Database
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
@@ -88,6 +94,7 @@ DATABASES = {
|
||||
}
|
||||
|
||||
# Password validation
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
@@ -104,12 +111,14 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
|
||||
LANGUAGE_CODE = "en-US"
|
||||
TIME_ZONE = "Europe/Amsterdam"
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
|
||||
STATIC_URL = "static/"
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, "static"),
|
||||
@@ -125,23 +134,28 @@ STORAGES = {
|
||||
}
|
||||
|
||||
# Media files
|
||||
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||
|
||||
# Default primary key field type
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# Crispy Forms
|
||||
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||
CRISPY_TEMPLATE_PACK = "bootstrap5"
|
||||
|
||||
# Authentication
|
||||
|
||||
AUTH_USER_MODEL = "accounts.CustomUser"
|
||||
LOGIN_REDIRECT_URL = "dashboard"
|
||||
LOGOUT_REDIRECT_URL = "login"
|
||||
ACCOUNT_LOGOUT_ON_GET = True
|
||||
|
||||
# django-allauth
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
"allauth.account.auth_backends.AuthenticationBackend",
|
||||
@@ -150,7 +164,9 @@ SITE_ID = 1
|
||||
ACCOUNT_EMAIL_VERIFICATION = "none"
|
||||
|
||||
# Celery Configuration
|
||||
|
||||
# Check if Redis is available
|
||||
|
||||
try:
|
||||
import redis
|
||||
|
||||
@@ -184,6 +200,7 @@ CELERY_TIMEZONE = TIME_ZONE
|
||||
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
|
||||
|
||||
# Get schedule from environment variables or use defaults
|
||||
|
||||
CHAT_DATA_FETCH_INTERVAL = int(os.environ.get("CHAT_DATA_FETCH_INTERVAL", 3600)) # Default: 1 hour
|
||||
|
||||
CELERY_BEAT_SCHEDULE = {
|
||||
|
||||
@@ -4,7 +4,7 @@ WSGI config for dashboard_project project.
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
|
||||
<https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/>
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# !/usr/bin/env python
|
||||
"""
|
||||
Migration Fix Script for ExternalDataSource
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# !/usr/bin/env python
|
||||
"""
|
||||
Test the ExternalDataSource Model Schema
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class ChatMessage(models.Model):
|
||||
|
||||
class ExternalDataSource(models.Model):
|
||||
name = models.CharField(max_length=255, default="External API")
|
||||
api_url = models.URLField(default="https://proto.notso.ai/jumbo/chats")
|
||||
api_url = models.URLField(default="<https://proto.notso.ai/jumbo/chats>")
|
||||
auth_username = models.CharField(max_length=255, blank=True, null=True)
|
||||
auth_password = models.CharField(
|
||||
max_length=255, blank=True, null=True
|
||||
|
||||
@@ -1 +1 @@
|
||||
# Create your tests here.
|
||||
# Create your tests here
|
||||
|
||||
@@ -7,7 +7,7 @@ from .models import ExternalDataSource
|
||||
from .tasks import periodic_fetch_chat_data, refresh_specific_source
|
||||
from .utils import fetch_and_store_chat_data
|
||||
|
||||
# Create your views here.
|
||||
# Create your views here
|
||||
|
||||
|
||||
def is_superuser(user):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# !/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
|
||||
import os
|
||||
|
||||
@@ -4,6 +4,7 @@ import os
|
||||
import sys
|
||||
|
||||
# Add the project root to sys.path
|
||||
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dashboard_project.settings")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# !/usr/bin/env python
|
||||
|
||||
# scripts/fix_dashboard_data.py
|
||||
|
||||
import os
|
||||
@@ -15,11 +16,13 @@ from django.db import transaction
|
||||
from django.utils.timezone import make_aware
|
||||
|
||||
# Set up Django environment
|
||||
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dashboard_project.settings")
|
||||
django.setup()
|
||||
|
||||
# SCRIPT CONFIG
|
||||
|
||||
CREATE_TEST_DATA = False # Set to True to create sample data if none exists
|
||||
COMPANY_NAME = "Notso AI" # The company name to use
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/**
|
||||
* dashboard.css - Styles specific to dashboard functionality
|
||||
|
||||
* dashboard.css - Styles specific to dashboard functionality
|
||||
*/
|
||||
|
||||
/* Theme variables */
|
||||
/*Theme variables */
|
||||
:root {
|
||||
/* Light theme (default) */
|
||||
/* Light theme (default)*/
|
||||
--bg-color: #f8f9fa;
|
||||
--text-color: #212529;
|
||||
--card-bg: #ffffff;
|
||||
@@ -26,7 +27,7 @@
|
||||
color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
/* Dark theme */
|
||||
/*Dark theme*/
|
||||
[data-bs-theme="dark"] {
|
||||
--bg-color: #212529;
|
||||
--text-color: #f8f9fa;
|
||||
@@ -47,7 +48,7 @@
|
||||
--icon-color: #6ea8fe;
|
||||
}
|
||||
|
||||
/* Apply theme variables */
|
||||
/*Apply theme variables*/
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
@@ -91,7 +92,7 @@ body {
|
||||
background-color: var(--sidebar-bg) !important;
|
||||
}
|
||||
|
||||
/* Sidebar navigation styling with dark mode support */
|
||||
/*Sidebar navigation styling with dark mode support*/
|
||||
.sidebar .nav-link {
|
||||
color: var(--text-color);
|
||||
transition: all 0.2s ease;
|
||||
@@ -168,7 +169,7 @@ body {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
/*Footer*/
|
||||
footer {
|
||||
background-color: var(--card-bg);
|
||||
border-top: 1px solid var(--border-color);
|
||||
@@ -182,7 +183,7 @@ footer {
|
||||
background-color: var(--navbar-bg);
|
||||
}
|
||||
|
||||
/* Dashboard grid layout */
|
||||
/*Dashboard grid layout*/
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
@@ -193,7 +194,7 @@ footer {
|
||||
/* Increased gap */
|
||||
}
|
||||
|
||||
/* Dashboard widget cards */
|
||||
/*Dashboard widget cards*/
|
||||
.dashboard-widget {
|
||||
display: flex;
|
||||
|
||||
@@ -254,7 +255,7 @@ footer {
|
||||
/* Consistent padding */
|
||||
}
|
||||
|
||||
/* Chart widgets */
|
||||
/*Chart widgets*/
|
||||
.chart-widget .card-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -270,7 +271,7 @@ footer {
|
||||
/* Ensure it takes full width of card body */
|
||||
}
|
||||
|
||||
/* Stat widgets / Stat Cards */
|
||||
/*Stat widgets / Stat Cards*/
|
||||
.stat-card {
|
||||
text-align: center;
|
||||
padding: 1.5rem;
|
||||
@@ -319,7 +320,7 @@ footer {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Dashboard theme variations */
|
||||
/*Dashboard theme variations*/
|
||||
.dashboard-theme-light .card {
|
||||
background-color: #fff;
|
||||
}
|
||||
@@ -344,7 +345,7 @@ footer {
|
||||
color: #adb5bd;
|
||||
}
|
||||
|
||||
/* Time period selector */
|
||||
/*Time period selector*/
|
||||
.time-period-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -367,7 +368,7 @@ footer {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Custom metric selector */
|
||||
/*Custom metric selector*/
|
||||
.metric-selector {
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
@@ -388,7 +389,7 @@ footer {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
/* Dashboard loading states */
|
||||
/*Dashboard loading states*/
|
||||
.widget-placeholder {
|
||||
min-height: 300px;
|
||||
background: linear-gradient(90deg, #e9ecef 25%, #f8f9fa 50%, #e9ecef 75%);
|
||||
@@ -413,7 +414,7 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
/* Dashboard empty states */
|
||||
/*Dashboard empty states*/
|
||||
.empty-state {
|
||||
padding: 2.5rem;
|
||||
|
||||
@@ -449,7 +450,7 @@ footer {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
/*Responsive adjustments*/
|
||||
@media (width <=767.98px) {
|
||||
.dashboard-grid {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -471,7 +472,7 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
/* Preserve colored background for stat cards in both themes */
|
||||
/*Preserve colored background for stat cards in both themes*/
|
||||
.col-md-3 .card.stats-card.bg-primary {
|
||||
background-color: var(--bs-primary) !important;
|
||||
color: white !important;
|
||||
@@ -507,7 +508,7 @@ footer {
|
||||
color: var(--bs-dark) !important;
|
||||
}
|
||||
|
||||
/* Stats Cards Alignment Fix (Bottom Align, No Overlap) */
|
||||
/*Stats Cards Alignment Fix (Bottom Align, No Overlap)*/
|
||||
.stats-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* style.css - Global styles for the application
|
||||
|
||||
* style.css - Global styles for the application
|
||||
*/
|
||||
|
||||
/* General Styles */
|
||||
/*General Styles*/
|
||||
body {
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif,
|
||||
@@ -25,14 +26,14 @@ body {
|
||||
/* Ensures body takes at least full viewport height */
|
||||
}
|
||||
|
||||
/* Navbar adjustments (if needed, Bootstrap usually handles this well) */
|
||||
/*Navbar adjustments (if needed, Bootstrap usually handles this well)*/
|
||||
.navbar {
|
||||
box-shadow: 0 2px 4px rgb(0 0 0 / 5%);
|
||||
|
||||
/* Subtle shadow for depth */
|
||||
}
|
||||
|
||||
/* Helper Classes */
|
||||
/*Helper Classes*/
|
||||
.text-truncate-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
@@ -49,7 +50,7 @@ body {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
/* Card styles */
|
||||
/*Card styles*/
|
||||
.card {
|
||||
border: 1px solid #e0e5e9;
|
||||
|
||||
@@ -91,7 +92,7 @@ body {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Sidebar enhancements */
|
||||
/*Sidebar enhancements*/
|
||||
.sidebar {
|
||||
background-color: #fff;
|
||||
|
||||
@@ -159,7 +160,7 @@ body {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Dashboard stats cards */
|
||||
/*Dashboard stats cards*/
|
||||
.stats-card {
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
@@ -176,14 +177,14 @@ body {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Chart containers */
|
||||
/*Chart containers*/
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Loading overlay */
|
||||
/*Loading overlay*/
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -197,7 +198,7 @@ body {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* Table enhancements */
|
||||
/*Table enhancements*/
|
||||
.table {
|
||||
border-color: #e0e5e9;
|
||||
}
|
||||
@@ -224,7 +225,7 @@ body {
|
||||
/* Consistent hover with sidebar */
|
||||
}
|
||||
|
||||
/* Form improvements */
|
||||
/*Form improvements*/
|
||||
.form-control,
|
||||
.form-select {
|
||||
border-color: #ced4da;
|
||||
@@ -246,7 +247,7 @@ body {
|
||||
/* Bootstrap focus shadow */
|
||||
}
|
||||
|
||||
/* Button styling */
|
||||
/*Button styling*/
|
||||
.btn {
|
||||
border-radius: 0.375rem;
|
||||
|
||||
@@ -281,13 +282,13 @@ body {
|
||||
border-color: #545b62;
|
||||
}
|
||||
|
||||
/* Alert styling */
|
||||
/*Alert styling*/
|
||||
.alert {
|
||||
border-radius: 0.375rem;
|
||||
padding: 0.9rem 1.25rem;
|
||||
}
|
||||
|
||||
/* Chat transcript styling */
|
||||
/*Chat transcript styling*/
|
||||
.chat-transcript {
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #e9ecef;
|
||||
@@ -304,7 +305,7 @@ body {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Footer styling */
|
||||
/*Footer styling*/
|
||||
footer {
|
||||
background-color: #fff;
|
||||
|
||||
@@ -318,7 +319,7 @@ footer {
|
||||
/* Added for sticky footer */
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
/*Responsive adjustments*/
|
||||
@media (width <=767.98px) {
|
||||
.main-content {
|
||||
margin-left: 0;
|
||||
@@ -337,7 +338,7 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
/* Print styles */
|
||||
/*Print styles*/
|
||||
@media print {
|
||||
.sidebar,
|
||||
.navbar,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* ajax-navigation.js - JavaScript for AJAX-based navigation across the entire application
|
||||
*
|
||||
* This script handles AJAX navigation between pages in the Chat Analytics Dashboard.
|
||||
* It intercepts link clicks, loads content via AJAX, and updates the browser history.
|
||||
|
||||
* ajax-navigation.js - JavaScript for AJAX-based navigation across the entire application
|
||||
*
|
||||
* This script handles AJAX navigation between pages in the Chat Analytics Dashboard.
|
||||
* It intercepts link clicks, loads content via AJAX, and updates the browser history.
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* ajax-pagination.js - Common JavaScript for AJAX pagination across the application
|
||||
*
|
||||
* This script handles AJAX-based pagination for all pages in the Chat Analytics Dashboard.
|
||||
* It intercepts pagination link clicks, loads content via AJAX, and updates the browser history.
|
||||
|
||||
* ajax-pagination.js - Common JavaScript for AJAX pagination across the application
|
||||
*
|
||||
* This script handles AJAX-based pagination for all pages in the Chat Analytics Dashboard.
|
||||
* It intercepts pagination link clicks, loads content via AJAX, and updates the browser history.
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
* dashboard.js - JavaScript for the dashboard functionality
|
||||
*
|
||||
* This file handles the interactive features of the dashboard,
|
||||
* including chart refreshing, dashboard filtering, and dashboard
|
||||
* customization.
|
||||
|
||||
* dashboard.js - JavaScript for the dashboard functionality
|
||||
*
|
||||
* This file handles the interactive features of the dashboard,
|
||||
* including chart refreshing, dashboard filtering, and dashboard
|
||||
* customization.
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* main.js - Global JavaScript functionality
|
||||
*
|
||||
* This file contains general JavaScript functionality used across
|
||||
* the entire application, including navigation, forms, and UI interactions.
|
||||
|
||||
* main.js - Global JavaScript functionality
|
||||
*
|
||||
* This file contains general JavaScript functionality used across
|
||||
* the entire application, including navigation, forms, and UI interactions.
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
@@ -4,7 +4,7 @@ WSGI config for dashboard_project project.
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
|
||||
<https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/>
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
Reference in New Issue
Block a user