Style the Admin Panel with a modern theme and Khoj branding (#999)
Some checks failed
dockerize / Publish Khoj Docker Images (push) Waiting to run
build and deploy github pages for documentation / deploy (push) Waiting to run
pypi / Publish Python Package to PyPI (push) Waiting to run
pre-commit / Setup Application and Lint (push) Has been cancelled
test / Run Tests (push) Has been cancelled

Overview
- The default django admin panel UI looks pretty dated and didn't
  have any Khoj specific branding
- Used the Unfold Django admin panel theme for a modern look
- Used the Khoj logo and name in Admin panel title, headings, favicons

Details:
All models shown on Admin panel need to inherit from unfold's
ModelAdmin to get styling applied. So

- Make all models on Admin panel inherit from unfold's ModelAdmin
- Subclassed UserAdmin to inherit from unfold's ModelAdmin
- Deregistered the unused Auth Group model from the Admin panel
  We can add it back when its actually used. Avoid confusion for now
- Explicitly register DjangoJobExecution on admin panel and again make
  it inherit from the unfold.admin.ModelAdmin
This commit is contained in:
Debanjum 2024-12-04 23:53:43 -08:00 committed by GitHub
parent 9cc79c0fb7
commit 354dc12b3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 66 additions and 27 deletions

View file

@ -64,6 +64,7 @@ dependencies = [
"anyio == 3.7.1", "anyio == 3.7.1",
"pymupdf == 1.24.11", "pymupdf == 1.24.11",
"django == 5.0.9", "django == 5.0.9",
"django-unfold == 0.42.0",
"authlib == 1.2.1", "authlib == 1.2.1",
"llama-cpp-python == 0.2.88", "llama-cpp-python == 0.2.88",
"itsdangerous == 2.1.2", "itsdangerous == 2.1.2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -13,6 +13,8 @@ https://docs.djangoproject.com/en/4.2/ref/settings/
import os import os
from pathlib import Path from pathlib import Path
from django.templatetags.static import static
from khoj.utils.helpers import in_debug_mode, is_env_var_true from khoj.utils.helpers import in_debug_mode, is_env_var_true
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
@ -72,6 +74,7 @@ INSTALLED_APPS = [
"django.contrib.auth", "django.contrib.auth",
"django.contrib.contenttypes", "django.contrib.contenttypes",
"khoj.database.apps.DatabaseConfig", "khoj.database.apps.DatabaseConfig",
"unfold",
"django.contrib.admin", "django.contrib.admin",
"django.contrib.sessions", "django.contrib.sessions",
"django.contrib.messages", "django.contrib.messages",
@ -195,3 +198,21 @@ APSCHEDULER_DATETIME_FORMAT = "N j, Y, f:s a"
# that supports multiple background worker processes instead (e.g. Dramatiq, Celery, Django-RQ, # that supports multiple background worker processes instead (e.g. Dramatiq, Celery, Django-RQ,
# etc. See: https://djangopackages.org/grids/g/workers-queues-tasks/ for popular options). # etc. See: https://djangopackages.org/grids/g/workers-queues-tasks/ for popular options).
APSCHEDULER_RUN_NOW_TIMEOUT = 240 # Seconds APSCHEDULER_RUN_NOW_TIMEOUT = 240 # Seconds
UNFOLD = {
"SITE_TITLE": "Khoj Admin Panel",
"SITE_HEADER": "Khoj Admin Panel",
"SITE_URL": "/",
"SITE_ICON": {
"light": lambda request: static("assets/icons/khoj_lantern_128x128.png"),
"dark": lambda request: static("assets/icons/khoj_lantern_128x128_dark.png"),
},
"SITE_FAVICONS": [
{
"rel": "icon",
"sizes": "32x32",
"type": "image/svg+xml",
"href": lambda request: static("assets/icons/khoj_lantern.svg"),
},
],
}

View file

@ -4,11 +4,14 @@ from datetime import date, datetime, timedelta, timezone
from apscheduler.job import Job from apscheduler.job import Job
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import Group
from django.http import HttpResponse from django.http import HttpResponse
from django_apscheduler.admin import DjangoJobAdmin from django_apscheduler.admin import DjangoJobAdmin, DjangoJobExecutionAdmin
from django_apscheduler.jobstores import DjangoJobStore from django_apscheduler.jobstores import DjangoJobStore
from django_apscheduler.models import DjangoJob from django_apscheduler.models import DjangoJob, DjangoJobExecution
from unfold import admin as unfold_admin
from khoj.database.models import ( from khoj.database.models import (
Agent, Agent,
@ -35,10 +38,8 @@ from khoj.database.models import (
) )
from khoj.utils.helpers import ImageIntentType from khoj.utils.helpers import ImageIntentType
admin.site.unregister(DjangoJob)
class KhojDjangoJobAdmin(DjangoJobAdmin, unfold_admin.ModelAdmin):
class KhojDjangoJobAdmin(DjangoJobAdmin):
list_display = ( list_display = (
"id", "id",
"next_run_time", "next_run_time",
@ -62,10 +63,25 @@ class KhojDjangoJobAdmin(DjangoJobAdmin):
return queryset, use_distinct return queryset, use_distinct
class KhojDjangoJobExecutionAdmin(DjangoJobExecutionAdmin, unfold_admin.ModelAdmin):
pass
admin.site.unregister(DjangoJob)
admin.site.register(DjangoJob, KhojDjangoJobAdmin) admin.site.register(DjangoJob, KhojDjangoJobAdmin)
admin.site.unregister(DjangoJobExecution)
admin.site.register(DjangoJobExecution, KhojDjangoJobExecutionAdmin)
class KhojUserAdmin(UserAdmin): class GroupAdmin(BaseGroupAdmin, unfold_admin.ModelAdmin):
pass
class UserAdmin(BaseUserAdmin, unfold_admin.ModelAdmin):
pass
class KhojUserAdmin(UserAdmin, unfold_admin.ModelAdmin):
class DateJoinedAfterFilter(admin.SimpleListFilter): class DateJoinedAfterFilter(admin.SimpleListFilter):
title = "Joined after" title = "Joined after"
parameter_name = "joined_after" parameter_name = "joined_after"
@ -137,21 +153,22 @@ class KhojUserAdmin(UserAdmin):
get_email_login_url.short_description = "Get email login URL" # type: ignore get_email_login_url.short_description = "Get email login URL" # type: ignore
admin.site.unregister(Group)
admin.site.register(KhojUser, KhojUserAdmin) admin.site.register(KhojUser, KhojUserAdmin)
admin.site.register(ProcessLock) admin.site.register(ProcessLock, unfold_admin.ModelAdmin)
admin.site.register(SpeechToTextModelOptions) admin.site.register(SpeechToTextModelOptions, unfold_admin.ModelAdmin)
admin.site.register(ReflectiveQuestion) admin.site.register(ReflectiveQuestion, unfold_admin.ModelAdmin)
admin.site.register(ClientApplication) admin.site.register(ClientApplication, unfold_admin.ModelAdmin)
admin.site.register(GithubConfig) admin.site.register(GithubConfig, unfold_admin.ModelAdmin)
admin.site.register(NotionConfig) admin.site.register(NotionConfig, unfold_admin.ModelAdmin)
admin.site.register(UserVoiceModelConfig) admin.site.register(UserVoiceModelConfig, unfold_admin.ModelAdmin)
admin.site.register(VoiceModelOption) admin.site.register(VoiceModelOption, unfold_admin.ModelAdmin)
admin.site.register(UserRequests) admin.site.register(UserRequests, unfold_admin.ModelAdmin)
@admin.register(Agent) @admin.register(Agent)
class AgentAdmin(admin.ModelAdmin): class AgentAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"name", "name",
@ -161,7 +178,7 @@ class AgentAdmin(admin.ModelAdmin):
@admin.register(Entry) @admin.register(Entry)
class EntryAdmin(admin.ModelAdmin): class EntryAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"created_at", "created_at",
@ -183,7 +200,7 @@ class EntryAdmin(admin.ModelAdmin):
@admin.register(Subscription) @admin.register(Subscription)
class KhojUserSubscription(admin.ModelAdmin): class KhojUserSubscription(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"user", "user",
@ -195,7 +212,7 @@ class KhojUserSubscription(admin.ModelAdmin):
@admin.register(ChatModelOptions) @admin.register(ChatModelOptions)
class ChatModelOptionsAdmin(admin.ModelAdmin): class ChatModelOptionsAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"chat_model", "chat_model",
@ -206,7 +223,7 @@ class ChatModelOptionsAdmin(admin.ModelAdmin):
@admin.register(TextToImageModelConfig) @admin.register(TextToImageModelConfig)
class TextToImageModelOptionsAdmin(admin.ModelAdmin): class TextToImageModelOptionsAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"model_name", "model_name",
@ -216,7 +233,7 @@ class TextToImageModelOptionsAdmin(admin.ModelAdmin):
@admin.register(OpenAIProcessorConversationConfig) @admin.register(OpenAIProcessorConversationConfig)
class OpenAIProcessorConversationConfigAdmin(admin.ModelAdmin): class OpenAIProcessorConversationConfigAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"name", "name",
@ -227,7 +244,7 @@ class OpenAIProcessorConversationConfigAdmin(admin.ModelAdmin):
@admin.register(SearchModelConfig) @admin.register(SearchModelConfig)
class SearchModelConfigAdmin(admin.ModelAdmin): class SearchModelConfigAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"name", "name",
@ -238,7 +255,7 @@ class SearchModelConfigAdmin(admin.ModelAdmin):
@admin.register(ServerChatSettings) @admin.register(ServerChatSettings)
class ServerChatSettingsAdmin(admin.ModelAdmin): class ServerChatSettingsAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"chat_default", "chat_default",
"chat_advanced", "chat_advanced",
@ -247,7 +264,7 @@ class ServerChatSettingsAdmin(admin.ModelAdmin):
@admin.register(WebScraper) @admin.register(WebScraper)
class WebScraperAdmin(admin.ModelAdmin): class WebScraperAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"priority", "priority",
"name", "name",
@ -261,7 +278,7 @@ class WebScraperAdmin(admin.ModelAdmin):
@admin.register(Conversation) @admin.register(Conversation)
class ConversationAdmin(admin.ModelAdmin): class ConversationAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"user", "user",
@ -367,7 +384,7 @@ class ConversationAdmin(admin.ModelAdmin):
@admin.register(UserConversationConfig) @admin.register(UserConversationConfig)
class UserConversationConfigAdmin(admin.ModelAdmin): class UserConversationConfigAdmin(unfold_admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"get_user_email", "get_user_email",