feat: admin panel enrichment
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
|
||||
from .models import ProjectBrief, ProjectBriefAttachment, ProjectInternalNote
|
||||
|
||||
|
||||
class ProjectBriefAttachmentInline(admin.TabularInline):
|
||||
model = ProjectBriefAttachment
|
||||
extra = 0
|
||||
readonly_fields = ("original_filename", "file", "uploaded_at")
|
||||
can_delete = True
|
||||
|
||||
|
||||
class ProjectInternalNoteInline(admin.TabularInline):
|
||||
model = ProjectInternalNote
|
||||
extra = 1
|
||||
fields = ("author", "note", "created_at")
|
||||
readonly_fields = ("created_at",)
|
||||
|
||||
|
||||
@admin.register(ProjectBrief)
|
||||
class ProjectBriefAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"title",
|
||||
"client",
|
||||
"category",
|
||||
"status_badge",
|
||||
"locked",
|
||||
"show_on_website",
|
||||
"budget_range",
|
||||
"submitted_at",
|
||||
)
|
||||
list_filter = (
|
||||
"status",
|
||||
"category",
|
||||
"budget_range",
|
||||
"locked",
|
||||
"show_on_website",
|
||||
"submitted_at",
|
||||
)
|
||||
search_fields = (
|
||||
"title",
|
||||
"description",
|
||||
"client__username",
|
||||
"client__email",
|
||||
"client__first_name",
|
||||
"client__last_name",
|
||||
)
|
||||
readonly_fields = ("client", "submitted_at", "updated_at")
|
||||
fieldsets = (
|
||||
(
|
||||
"Brief",
|
||||
{
|
||||
"fields": (
|
||||
"client",
|
||||
"title",
|
||||
"category",
|
||||
"description",
|
||||
"budget_range",
|
||||
"desired_deadline",
|
||||
"reference_links",
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Workflow",
|
||||
{
|
||||
"fields": (
|
||||
"status",
|
||||
"quote_text",
|
||||
"website_notes",
|
||||
"submitted_at",
|
||||
"updated_at",
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Client editing locks",
|
||||
{
|
||||
"description": (
|
||||
"Lock individual fields so the client cannot change them while "
|
||||
"the brief is still editable. 'Lock entire project' blocks all "
|
||||
"client edits regardless of status."
|
||||
),
|
||||
"fields": (
|
||||
"locked",
|
||||
"lock_title",
|
||||
"lock_category",
|
||||
"lock_description",
|
||||
"lock_budget_range",
|
||||
"lock_desired_deadline",
|
||||
"lock_reference_links",
|
||||
"lock_attachments",
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Website showcase",
|
||||
{
|
||||
"description": (
|
||||
"Control whether this project appears on the public website and "
|
||||
"which fields are visible on the website card."
|
||||
),
|
||||
"fields": (
|
||||
"show_on_website",
|
||||
"public_title",
|
||||
"public_summary",
|
||||
"public_tags",
|
||||
"public_image",
|
||||
"public_project_status",
|
||||
"public_url",
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Website field visibility",
|
||||
{
|
||||
"description": (
|
||||
"Each field can be independently shown or hidden on the website card."
|
||||
),
|
||||
"fields": (
|
||||
"show_title_on_website",
|
||||
"show_category_on_website",
|
||||
"show_description_on_website",
|
||||
"show_budget_on_website",
|
||||
"show_deadline_on_website",
|
||||
"show_references_on_website",
|
||||
"show_attachments_on_website",
|
||||
),
|
||||
"classes": ("collapse",),
|
||||
},
|
||||
),
|
||||
)
|
||||
inlines = [ProjectBriefAttachmentInline, ProjectInternalNoteInline]
|
||||
date_hierarchy = "submitted_at"
|
||||
|
||||
def save_formset(self, request, form, formset, change):
|
||||
instances = formset.save(commit=False)
|
||||
for instance in instances:
|
||||
if isinstance(instance, ProjectInternalNote) and not instance.author_id:
|
||||
instance.author = request.user
|
||||
instance.save()
|
||||
formset.save_m2m()
|
||||
for obj in formset.deleted_objects:
|
||||
obj.delete()
|
||||
|
||||
@admin.display(description="Status", boolean=False)
|
||||
def status_badge(self, obj):
|
||||
colors = {
|
||||
ProjectBrief.STATUS_SUBMITTED: "#3b82f6",
|
||||
ProjectBrief.STATUS_UNDER_REVIEW: "#8b5cf6",
|
||||
ProjectBrief.STATUS_QUOTED: "#f59e0b",
|
||||
ProjectBrief.STATUS_ACCEPTED: "#10b981",
|
||||
ProjectBrief.STATUS_DECLINED: "#ef4444",
|
||||
ProjectBrief.STATUS_IN_PROGRESS: "#06b6d4",
|
||||
ProjectBrief.STATUS_DELIVERED: "#22c55e",
|
||||
ProjectBrief.STATUS_CLOSED: "#6b7280",
|
||||
}
|
||||
color = colors.get(obj.status, "#6b7280")
|
||||
return format_html(
|
||||
'<span style="padding:2px 8px;border-radius:999px;background:{};color:#fff;font-size:12px;">{}</span>',
|
||||
color,
|
||||
obj.get_status_display(),
|
||||
)
|
||||
|
||||
|
||||
@admin.register(ProjectInternalNote)
|
||||
class ProjectInternalNoteAdmin(admin.ModelAdmin):
|
||||
list_display = ("brief", "author", "created_at")
|
||||
search_fields = ("brief__title", "note", "author__username")
|
||||
readonly_fields = ("created_at",)
|
||||
Reference in New Issue
Block a user