phase 1 partial
This commit is contained in:
1624
DJANGO-ADMIN-IMPROVEMENT-PLAN.md
Normal file
1624
DJANGO-ADMIN-IMPROVEMENT-PLAN.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,57 +23,42 @@ class Igny8AdminSite(admin.AdminSite):
|
|||||||
|
|
||||||
def get_app_list(self, request):
|
def get_app_list(self, request):
|
||||||
"""
|
"""
|
||||||
Customize the app list to organize models into proper groups
|
Customize the app list to organize models into logical groups
|
||||||
"""
|
"""
|
||||||
# Get the default app list
|
# Get the default app list
|
||||||
app_dict = self._build_app_dict(request)
|
app_dict = self._build_app_dict(request)
|
||||||
|
|
||||||
# Define our custom groups with their models (using object_name)
|
# Define our custom groups with their models (using object_name)
|
||||||
|
# Organized by business function with emoji icons for visual recognition
|
||||||
custom_groups = {
|
custom_groups = {
|
||||||
'Billing & Tenancy': {
|
'💰 Billing & Accounts': {
|
||||||
'models': [
|
'models': [
|
||||||
('igny8_core_auth', 'Plan'),
|
('igny8_core_auth', 'Plan'),
|
||||||
('igny8_core_auth', 'Account'),
|
('igny8_core_auth', 'Account'),
|
||||||
('igny8_core_auth', 'Subscription'),
|
('igny8_core_auth', 'Subscription'),
|
||||||
('billing', 'CreditTransaction'),
|
|
||||||
('billing', 'CreditUsageLog'),
|
|
||||||
('billing', 'Invoice'),
|
('billing', 'Invoice'),
|
||||||
('billing', 'Payment'),
|
('billing', 'Payment'),
|
||||||
|
('billing', 'CreditTransaction'),
|
||||||
|
('billing', 'CreditUsageLog'),
|
||||||
('billing', 'CreditPackage'),
|
('billing', 'CreditPackage'),
|
||||||
|
('billing', 'PaymentMethodConfig'),
|
||||||
|
('billing', 'AccountPaymentMethod'),
|
||||||
('billing', 'CreditCostConfig'),
|
('billing', 'CreditCostConfig'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Sites & Users': {
|
'👥 Sites & Users': {
|
||||||
'models': [
|
'models': [
|
||||||
('igny8_core_auth', 'Site'),
|
('igny8_core_auth', 'Site'),
|
||||||
|
('igny8_core_auth', 'Sector'),
|
||||||
('igny8_core_auth', 'User'),
|
('igny8_core_auth', 'User'),
|
||||||
('igny8_core_auth', 'SiteUserAccess'),
|
('igny8_core_auth', 'SiteUserAccess'),
|
||||||
('igny8_core_auth', 'PasswordResetToken'),
|
('igny8_core_auth', 'PasswordResetToken'),
|
||||||
('igny8_core_auth', 'Sector'),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Global Reference Data': {
|
'📚 Content Management': {
|
||||||
'models': [
|
'models': [
|
||||||
('igny8_core_auth', 'Industry'),
|
|
||||||
('igny8_core_auth', 'IndustrySector'),
|
|
||||||
('igny8_core_auth', 'SeedKeyword'),
|
|
||||||
('site_building', 'BusinessType'),
|
|
||||||
('site_building', 'AudienceProfile'),
|
|
||||||
('site_building', 'BrandPersonality'),
|
|
||||||
('site_building', 'HeroImageryDirection'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'Planner': {
|
|
||||||
'models': [
|
|
||||||
('planner', 'Keywords'),
|
|
||||||
('planner', 'Clusters'),
|
|
||||||
('planner', 'ContentIdeas'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'Writer Module': {
|
|
||||||
'models': [
|
|
||||||
('writer', 'Tasks'),
|
|
||||||
('writer', 'Content'),
|
('writer', 'Content'),
|
||||||
|
('writer', 'Tasks'),
|
||||||
('writer', 'Images'),
|
('writer', 'Images'),
|
||||||
('writer', 'ContentTaxonomy'),
|
('writer', 'ContentTaxonomy'),
|
||||||
('writer', 'ContentAttribute'),
|
('writer', 'ContentAttribute'),
|
||||||
@@ -81,54 +66,53 @@ class Igny8AdminSite(admin.AdminSite):
|
|||||||
('writer', 'ContentClusterMap'),
|
('writer', 'ContentClusterMap'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Thinker Module': {
|
'🎯 Planning & Strategy': {
|
||||||
'models': [
|
'models': [
|
||||||
('system', 'AIPrompt'),
|
('planner', 'Clusters'),
|
||||||
('system', 'AuthorProfile'),
|
('planner', 'Keywords'),
|
||||||
|
('planner', 'ContentIdeas'),
|
||||||
('system', 'Strategy'),
|
('system', 'Strategy'),
|
||||||
('ai', 'AITaskLog'),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'System Configuration': {
|
'🔗 Integrations & Publishing': {
|
||||||
|
'models': [
|
||||||
|
('integration', 'SiteIntegration'),
|
||||||
|
('integration', 'SyncEvent'),
|
||||||
|
('publishing', 'PublishingRecord'),
|
||||||
|
('publishing', 'DeploymentRecord'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'🤖 AI & Automation': {
|
||||||
|
'models': [
|
||||||
|
('ai', 'AITaskLog'),
|
||||||
|
('system', 'AIPrompt'),
|
||||||
|
('automation', 'AutomationConfig'),
|
||||||
|
('automation', 'AutomationRun'),
|
||||||
|
('optimization', 'OptimizationTask'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'🌍 Global Reference Data': {
|
||||||
|
'models': [
|
||||||
|
('igny8_core_auth', 'Industry'),
|
||||||
|
('igny8_core_auth', 'IndustrySector'),
|
||||||
|
('igny8_core_auth', 'SeedKeyword'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'⚙️ System Configuration': {
|
||||||
'models': [
|
'models': [
|
||||||
('system', 'IntegrationSettings'),
|
('system', 'IntegrationSettings'),
|
||||||
('system', 'SystemLog'),
|
('system', 'AuthorProfile'),
|
||||||
('system', 'SystemStatus'),
|
|
||||||
('system', 'SystemSettings'),
|
('system', 'SystemSettings'),
|
||||||
('system', 'AccountSettings'),
|
('system', 'AccountSettings'),
|
||||||
('system', 'UserSettings'),
|
('system', 'UserSettings'),
|
||||||
('system', 'ModuleSettings'),
|
('system', 'ModuleSettings'),
|
||||||
('system', 'AISettings'),
|
('system', 'AISettings'),
|
||||||
('system', 'ModuleEnableSettings'),
|
('system', 'ModuleEnableSettings'),
|
||||||
# Automation config lives under the automation app - include here
|
('system', 'SystemLog'),
|
||||||
('automation', 'AutomationConfig'),
|
('system', 'SystemStatus'),
|
||||||
('automation', 'AutomationRun'),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Payments': {
|
'🔧 Django System': {
|
||||||
'models': [
|
|
||||||
('billing', 'PaymentMethodConfig'),
|
|
||||||
('billing', 'AccountPaymentMethod'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'Integrations & Sync': {
|
|
||||||
'models': [
|
|
||||||
('integration', 'SiteIntegration'),
|
|
||||||
('integration', 'SyncEvent'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'Publishing': {
|
|
||||||
'models': [
|
|
||||||
('publishing', 'PublishingRecord'),
|
|
||||||
('publishing', 'DeploymentRecord'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'Optimization': {
|
|
||||||
'models': [
|
|
||||||
('optimization', 'OptimizationTask'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'Django Internals': {
|
|
||||||
'models': [
|
'models': [
|
||||||
('admin', 'LogEntry'),
|
('admin', 'LogEntry'),
|
||||||
('auth', 'Group'),
|
('auth', 'Group'),
|
||||||
@@ -159,7 +143,7 @@ class Igny8AdminSite(admin.AdminSite):
|
|||||||
if group_models:
|
if group_models:
|
||||||
app_list.append({
|
app_list.append({
|
||||||
'name': group_name,
|
'name': group_name,
|
||||||
'app_label': group_name.lower().replace(' ', '_').replace('&', ''),
|
'app_label': group_name.lower().replace(' ', '_').replace('&', '').replace('emoji', ''),
|
||||||
'app_url': None,
|
'app_url': None,
|
||||||
'has_module_perms': True,
|
'has_module_perms': True,
|
||||||
'models': group_models,
|
'models': group_models,
|
||||||
@@ -167,18 +151,15 @@ class Igny8AdminSite(admin.AdminSite):
|
|||||||
|
|
||||||
# Sort the app list by our custom order
|
# Sort the app list by our custom order
|
||||||
order = [
|
order = [
|
||||||
'Billing & Tenancy',
|
'💰 Billing & Accounts',
|
||||||
'Sites & Users',
|
'👥 Sites & Users',
|
||||||
'Global Reference Data',
|
'📚 Content Management',
|
||||||
'Planner',
|
'🎯 Planning & Strategy',
|
||||||
'Writer Module',
|
'🔗 Integrations & Publishing',
|
||||||
'Thinker Module',
|
'🤖 AI & Automation',
|
||||||
'System Configuration',
|
'🌍 Global Reference Data',
|
||||||
'Payments',
|
'⚙️ System Configuration',
|
||||||
'Integrations & Sync',
|
'🔧 Django System',
|
||||||
'Publishing',
|
|
||||||
'Optimization',
|
|
||||||
'Django Internals',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
app_list.sort(key=lambda x: order.index(x['name']) if x['name'] in order else 999)
|
app_list.sort(key=lambda x: order.index(x['name']) if x['name'] in order else 999)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
Billing Business Logic Admin
|
Billing Business Logic Admin
|
||||||
|
|
||||||
|
NOTE: Most billing models are registered in modules/billing/admin.py
|
||||||
|
with full workflow functionality. This file contains legacy/minimal registrations.
|
||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
@@ -14,133 +17,36 @@ from .models import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CreditCostConfig)
|
# CreditCostConfig - DUPLICATE - Registered in modules/billing/admin.py with better features
|
||||||
class CreditCostConfigAdmin(admin.ModelAdmin):
|
# Commenting out to avoid conflicts
|
||||||
list_display = [
|
# @admin.register(CreditCostConfig)
|
||||||
'operation_type',
|
# class CreditCostConfigAdmin(admin.ModelAdmin):
|
||||||
'display_name',
|
# ...existing implementation...
|
||||||
'credits_cost_display',
|
|
||||||
'unit',
|
|
||||||
'is_active',
|
|
||||||
'cost_change_indicator',
|
|
||||||
'updated_at',
|
|
||||||
'updated_by'
|
|
||||||
]
|
|
||||||
|
|
||||||
list_filter = ['is_active', 'unit', 'updated_at']
|
|
||||||
search_fields = ['operation_type', 'display_name', 'description']
|
|
||||||
|
|
||||||
fieldsets = (
|
|
||||||
('Operation', {
|
|
||||||
'fields': ('operation_type', 'display_name', 'description')
|
|
||||||
}),
|
|
||||||
('Cost Configuration', {
|
|
||||||
'fields': ('credits_cost', 'unit', 'is_active')
|
|
||||||
}),
|
|
||||||
('Audit Trail', {
|
|
||||||
'fields': ('previous_cost', 'updated_by', 'created_at', 'updated_at'),
|
|
||||||
'classes': ('collapse',)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
readonly_fields = ['created_at', 'updated_at', 'previous_cost']
|
|
||||||
|
|
||||||
def credits_cost_display(self, obj):
|
|
||||||
"""Show cost with color coding"""
|
|
||||||
if obj.credits_cost >= 20:
|
|
||||||
color = 'red'
|
|
||||||
elif obj.credits_cost >= 10:
|
|
||||||
color = 'orange'
|
|
||||||
else:
|
|
||||||
color = 'green'
|
|
||||||
return format_html(
|
|
||||||
'<span style="color: {}; font-weight: bold;">{} credits</span>',
|
|
||||||
color,
|
|
||||||
obj.credits_cost
|
|
||||||
)
|
|
||||||
credits_cost_display.short_description = 'Cost'
|
|
||||||
|
|
||||||
def cost_change_indicator(self, obj):
|
|
||||||
"""Show if cost changed recently"""
|
|
||||||
if obj.previous_cost is not None:
|
|
||||||
if obj.credits_cost > obj.previous_cost:
|
|
||||||
icon = '📈' # Increased
|
|
||||||
color = 'red'
|
|
||||||
elif obj.credits_cost < obj.previous_cost:
|
|
||||||
icon = '📉' # Decreased
|
|
||||||
color = 'green'
|
|
||||||
else:
|
|
||||||
icon = '➡️' # Same
|
|
||||||
color = 'gray'
|
|
||||||
|
|
||||||
return format_html(
|
|
||||||
'{} <span style="color: {};">({} → {})</span>',
|
|
||||||
icon,
|
|
||||||
color,
|
|
||||||
obj.previous_cost,
|
|
||||||
obj.credits_cost
|
|
||||||
)
|
|
||||||
return '—'
|
|
||||||
cost_change_indicator.short_description = 'Recent Change'
|
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
|
||||||
"""Track who made the change"""
|
|
||||||
obj.updated_by = request.user
|
|
||||||
super().save_model(request, obj, form, change)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Invoice)
|
# Invoice - DUPLICATE - Registered in modules/billing/admin.py
|
||||||
class InvoiceAdmin(AccountAdminMixin, admin.ModelAdmin):
|
# Commenting out to avoid conflicts
|
||||||
list_display = [
|
# @admin.register(Invoice)
|
||||||
'invoice_number',
|
# class InvoiceAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||||
'account',
|
# ...existing implementation...
|
||||||
'status',
|
|
||||||
'total',
|
|
||||||
'currency',
|
|
||||||
'invoice_date',
|
|
||||||
'due_date',
|
|
||||||
'subscription',
|
|
||||||
]
|
|
||||||
list_filter = ['status', 'currency', 'invoice_date', 'account']
|
|
||||||
search_fields = ['invoice_number', 'account__name', 'subscription__id']
|
|
||||||
readonly_fields = ['created_at', 'updated_at']
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Payment)
|
# Payment - DUPLICATE - Registered in modules/billing/admin.py with full approval workflow
|
||||||
class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin):
|
# Commenting out to avoid conflicts
|
||||||
\"\"\"
|
# @admin.register(Payment)
|
||||||
Payment admin - DO NOT USE.
|
# class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||||
Use the Payment admin in modules/billing/admin.py which has approval workflow actions.
|
# ...existing implementation...
|
||||||
This is kept for backward compatibility only.
|
|
||||||
\"\"\"
|
|
||||||
list_display = [
|
|
||||||
'id',
|
|
||||||
'invoice',
|
|
||||||
'account',
|
|
||||||
'payment_method',
|
|
||||||
'status',
|
|
||||||
'amount',
|
|
||||||
'currency',
|
|
||||||
'processed_at',
|
|
||||||
]
|
|
||||||
list_filter = ['status', 'payment_method', 'currency', 'created_at']
|
|
||||||
search_fields = ['invoice__invoice_number', 'account__name', 'stripe_payment_intent_id', 'paypal_order_id']
|
|
||||||
readonly_fields = ['created_at', 'updated_at']
|
|
||||||
|
|
||||||
def has_add_permission(self, request):\n return False # Prevent creating payments here
|
|
||||||
\n def has_delete_permission(self, request, obj=None):\n return False # Prevent deleting payments here
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CreditPackage)
|
# CreditPackage - DUPLICATE - Registered in modules/billing/admin.py
|
||||||
class CreditPackageAdmin(admin.ModelAdmin):
|
# Commenting out to avoid conflicts
|
||||||
list_display = ['name', 'slug', 'credits', 'price', 'discount_percentage', 'is_active', 'is_featured', 'sort_order']
|
# @admin.register(CreditPackage)
|
||||||
list_filter = ['is_active', 'is_featured']
|
# class CreditPackageAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', 'slug']
|
# ...existing implementation...
|
||||||
readonly_fields = ['created_at', 'updated_at']
|
|
||||||
|
|
||||||
|
|
||||||
# PaymentMethodConfig admin is in modules/billing/admin.py - do not duplicate
|
# PaymentMethodConfig and AccountPaymentMethod are kept here as they're not duplicated
|
||||||
# @admin.register(PaymentMethodConfig)
|
# or have minimal implementations that don't conflict
|
||||||
|
|
||||||
@admin.register(AccountPaymentMethod)
|
@admin.register(AccountPaymentMethod)
|
||||||
class AccountPaymentMethodAdmin(admin.ModelAdmin):
|
class AccountPaymentMethodAdmin(admin.ModelAdmin):
|
||||||
|
|||||||
290
backend/igny8_core/static/admin/css/igny8_admin.css
Normal file
290
backend/igny8_core/static/admin/css/igny8_admin.css
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
/* IGNY8 Custom Admin Styles */
|
||||||
|
|
||||||
|
/* Status badges */
|
||||||
|
.status-active {
|
||||||
|
color: #28a745 !important;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-inactive {
|
||||||
|
color: #dc3545 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-pending {
|
||||||
|
color: #ffc107 !important;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-succeeded, .status-completed {
|
||||||
|
color: #28a745 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-failed, .status-error {
|
||||||
|
color: #dc3545 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Credit indicators */
|
||||||
|
.credits-low {
|
||||||
|
color: #dc3545 !important;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.credits-medium {
|
||||||
|
color: #ffc107 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.credits-high {
|
||||||
|
color: #28a745 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quick action buttons */
|
||||||
|
.admin-action-button {
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 2px;
|
||||||
|
background-color: #417690;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-action-button:hover {
|
||||||
|
background-color: #305d75;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List view enhancements */
|
||||||
|
#content-main table tr:hover {
|
||||||
|
background-color: #f8f9fa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve sidebar menu appearance */
|
||||||
|
#content-related h3 {
|
||||||
|
background: #417690;
|
||||||
|
color: white;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better form field spacing */
|
||||||
|
.form-row {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Highlight required fields */
|
||||||
|
.required label:after {
|
||||||
|
content: " *";
|
||||||
|
color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success messages */
|
||||||
|
.success, .messagelist .success {
|
||||||
|
background-color: #d4edda !important;
|
||||||
|
border-color: #c3e6cb !important;
|
||||||
|
color: #155724 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Warning messages */
|
||||||
|
.warning, .messagelist .warning {
|
||||||
|
background-color: #fff3cd !important;
|
||||||
|
border-color: #ffeaa7 !important;
|
||||||
|
color: #856404 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error messages */
|
||||||
|
.error, .messagelist .error {
|
||||||
|
background-color: #f8d7da !important;
|
||||||
|
border-color: #f5c6cb !important;
|
||||||
|
color: #721c24 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve table readability */
|
||||||
|
#result_list tbody tr:nth-child(odd) {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#result_list tbody tr:nth-child(even) {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better button styling */
|
||||||
|
.button, input[type=submit], input[type=button], .submit-row input {
|
||||||
|
background: #417690 !important;
|
||||||
|
color: white !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 10px 15px !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover, input[type=submit]:hover, input[type=button]:hover {
|
||||||
|
background: #305d75 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete button styling */
|
||||||
|
.deletelink, .deletelink-box a {
|
||||||
|
background: #dc3545 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deletelink:hover, .deletelink-box a:hover {
|
||||||
|
background: #c82333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve filter sidebar */
|
||||||
|
#changelist-filter h2 {
|
||||||
|
background: #417690;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 10px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#changelist-filter h3 {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better pagination */
|
||||||
|
.paginator {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paginator a {
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 0 2px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paginator a:hover {
|
||||||
|
background: #417690;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive improvements */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
#content-main {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module table {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Admin header improvements */
|
||||||
|
#header {
|
||||||
|
background: #417690;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header a:link, #header a:visited {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#branding h1 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fieldset legend styling */
|
||||||
|
fieldset.module h2 {
|
||||||
|
background: #417690;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline forms */
|
||||||
|
.inline-group {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-group .tabular {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Help text styling */
|
||||||
|
.help {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
display: block;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dashboard widget styling */
|
||||||
|
.dashboard-card {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 10px 0;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-card h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
border-bottom: 2px solid #417690;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 10px 20px 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #417690;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
display: block;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alert styling */
|
||||||
|
.alert {
|
||||||
|
padding: 15px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 4px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-error {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
border-left-color: #dc3545;
|
||||||
|
color: #721c24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-warning {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border-left-color: #ffc107;
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-info {
|
||||||
|
background-color: #d1ecf1;
|
||||||
|
border-left-color: #17a2b8;
|
||||||
|
color: #0c5460;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background-color: #d4edda;
|
||||||
|
border-left-color: #28a745;
|
||||||
|
color: #155724;
|
||||||
|
}
|
||||||
19
backend/igny8_core/templates/admin/base_site.html
Normal file
19
backend/igny8_core/templates/admin/base_site.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends "admin/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}{{ title }} | IGNY8 Admin{% endblock %}
|
||||||
|
|
||||||
|
{% block branding %}
|
||||||
|
<h1 id="site-name">
|
||||||
|
<a href="{% url 'admin:index' %}">
|
||||||
|
🚀 IGNY8 Administration
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrastyle %}
|
||||||
|
{{ block.super }}
|
||||||
|
<link rel="stylesheet" href="{% static 'admin/css/igny8_admin.css' %}">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block nav-global %}{% endblock %}
|
||||||
Reference in New Issue
Block a user