from django.contrib import admin from apps.core.admin_video import video_admin_preview from apps.core.video import VIDEO_ADMIN_FIELDSET from .models import Article, ArticleCitation, ArticleSection, MainProduct, ProductVideo, SubProduct, SubProductVersion class ArticleCitationInline(admin.TabularInline): model = ArticleCitation extra = 1 fields = ("text", "url", "order") ordering = ("order",) class ArticleSectionInline(admin.TabularInline): model = ArticleSection extra = 1 fields = ("title", "value_format", "value", "order") ordering = ("order",) class SubProductArticleInline(admin.StackedInline): model = Article fk_name = "sub_product" extra = 0 fields = ("badge", "title", "description", "order") ordering = ("order",) show_change_link = True class MainProductArticleInline(admin.StackedInline): model = Article fk_name = "main_product" extra = 0 fields = ("badge", "title", "description", "order") ordering = ("order",) show_change_link = True RELEASE_VERSION_INLINE_FIELDS = ( "version", "release_channel", "channel_label", "is_featured", "show_on_product_page", "windows_download_url", "macos_download_url", "linux_download_url", "source_code_url", "package_resource_url", "release_notes", "is_active", "order", ) class SubProductVersionInline(admin.TabularInline): model = SubProductVersion fk_name = "sub_product" extra = 0 ordering = ("order", "version") fields = RELEASE_VERSION_INLINE_FIELDS show_change_link = True class MainProductVersionInline(admin.TabularInline): model = SubProductVersion fk_name = "main_product" extra = 0 ordering = ("order", "version") fields = RELEASE_VERSION_INLINE_FIELDS show_change_link = True class ProductVideoInline(admin.StackedInline): model = ProductVideo fk_name = "main_product" extra = 0 fields = ( "badge", "title", "description_format", "description", "video_source", "video_url", "video_file", "video_poster", "video_size", "video_aspect_ratio", "video_styled_background", "order", "is_active", ) ordering = ("order",) class SubProductInline(admin.StackedInline): model = SubProduct extra = 0 fields = ("name", "slug", "distribution", "short_description", "image", "logo", "show_on_homepage", "homepage_order", "order", "is_active") ordering = ("order",) show_change_link = True prepopulated_fields = {"slug": ("name",)} @admin.register(MainProduct) class MainProductAdmin(admin.ModelAdmin): list_display = ("name", "show_on_homepage", "homepage_order", "order", "is_active", "created_at") list_filter = ("is_active", "show_on_homepage") search_fields = ("name", "description") prepopulated_fields = {"slug": ("name",)} list_editable = ("order", "is_active", "show_on_homepage", "homepage_order") inlines = [MainProductArticleInline, ProductVideoInline, MainProductVersionInline, SubProductInline] fieldsets = ( ( None, { "fields": ( "name", "slug", "short_description", "distribution", "package_resource_button_text", "package_source_button_text", "downloads_section_link_text", "downloads_section_link_url", ) }, ), ("Description", {"fields": ("description_format", "description")}), ("Media", {"fields": ("image",)}), ("Homepage", {"fields": ("show_on_homepage", "homepage_order")}), ("Settings", {"fields": ("order", "is_active")}), ) class SubProductVideoInline(admin.StackedInline): model = ProductVideo fk_name = "sub_product" extra = 0 fields = ( "badge", "title", "description_format", "description", "video_source", "video_url", "video_file", "video_poster", "video_size", "video_aspect_ratio", "video_styled_background", "order", "is_active", ) ordering = ("order",) @admin.register(SubProduct) class SubProductAdmin(admin.ModelAdmin): list_display = ( "name", "main_product", "distribution", "show_on_homepage", "homepage_order", "order", "is_active", "created_at", ) list_filter = ("is_active", "distribution", "main_product", "show_on_homepage") search_fields = ("name", "description", "main_product__name") prepopulated_fields = {"slug": ("name",)} list_editable = ("order", "is_active", "show_on_homepage", "homepage_order") raw_id_fields = ("main_product",) inlines = [SubProductArticleInline, SubProductVideoInline, SubProductVersionInline] fieldsets = ( ( None, { "fields": ( "main_product", "name", "slug", "distribution", "short_description", "package_resource_button_text", "package_source_button_text", "downloads_section_link_text", "downloads_section_link_url", ) }, ), ("Description", {"fields": ("description_format", "description")}), ("Media", {"fields": ("image", "logo")}), ("Homepage", {"fields": ("show_on_homepage", "homepage_order")}), ("Settings", {"fields": ("order", "is_active")}), ) @admin.register(Article) class ArticleAdmin(admin.ModelAdmin): list_display = ("title", "parent", "order", "created_at") list_filter = ("main_product", "sub_product__main_product") search_fields = ("title", "description", "main_product__name", "sub_product__name") list_editable = ("order",) raw_id_fields = ("main_product", "sub_product") inlines = [ArticleSectionInline, ArticleCitationInline] fieldsets = ( (None, {"fields": ("main_product", "sub_product", "badge", "title")}), ("Description", {"fields": ("description_format", "description")}), ("Citation Badge", {"fields": ("citation_count_display", "citation_count_label"), "description": "Number and optional label for the dashed citation circle badge. Both are optional — a label without a number shows an empty circle with the label; neither hides the badge entirely."}), ("Settings", {"fields": ("order",)}), ) @admin.display(description="Parent") def parent(self, obj): if obj.main_product_id: return obj.main_product if obj.sub_product_id: return obj.sub_product return "—" @admin.register(ProductVideo) class ProductVideoAdmin(admin.ModelAdmin): list_display = ("title", "parent", "video_source", "video_size", "order", "is_active") list_filter = ("video_source", "is_active", "main_product", "sub_product__main_product") list_editable = ("order", "is_active") search_fields = ("title", "description", "video_url", "main_product__name", "sub_product__name") raw_id_fields = ("main_product", "sub_product") readonly_fields = ("video_preview",) fieldsets = ( (None, {"fields": ("main_product", "sub_product", "badge", "title", "description_format", "description")}), VIDEO_ADMIN_FIELDSET, ("Settings", {"fields": ("order", "is_active")}), ) @admin.display(description="Parent") def parent(self, obj): if obj.main_product_id: return obj.main_product if obj.sub_product_id: return obj.sub_product return "—" @admin.display(description="Preview") def video_preview(self, obj): return video_admin_preview(obj) @admin.register(ArticleSection) class ArticleSectionAdmin(admin.ModelAdmin): list_display = ("title", "article", "value_format", "order") search_fields = ("title", "value", "article__title") list_editable = ("order",) raw_id_fields = ("article",) fieldsets = ( (None, {"fields": ("article", "title")}), ("Content", {"fields": ("value_format", "value")}), ("Settings", {"fields": ("order",)}), ) @admin.register(SubProductVersion) class SubProductVersionAdmin(admin.ModelAdmin): list_display = ( "parent", "version", "release_channel", "channel_label", "is_featured", "show_on_product_page", "is_active", "order", ) list_filter = ("is_active", "release_channel", "is_featured", "show_on_product_page", "main_product", "sub_product__main_product") search_fields = ("main_product__name", "sub_product__name", "version") list_editable = ("is_active", "order") raw_id_fields = ("main_product", "sub_product") fieldsets = ( ( None, { "description": ( "Set a preset channel badge (Stable, Beta, Previous, etc.) or write a custom " "label. Mark one release as Primary (featured) for the main download block. " "Enable “Show on product page” for additional inline channels such as beta or " "previous versions." ), "fields": ( "main_product", "sub_product", "version", "release_channel", "channel_label", "is_featured", "show_on_product_page", ) }, ), ( "Installable downloads", { "description": ( "For each platform, set an external URL, upload a file, both, or neither. " "When a URL is set it is used on the site; otherwise an uploaded file is served. " "To delete an uploaded file from the server, open this release, check Clear next to the file, and Save." ), "fields": ( "windows_download_url", "windows_download_file", "macos_download_url", "macos_download_file", "linux_download_url", "linux_download_file", "source_code_url", "source_code_file", ), }, ), ("Package link", {"fields": ("package_resource_url",)}), ("Details", {"fields": ("release_notes",)}), ("Settings", {"fields": ("is_active", "order")}), ) @admin.display(description="Parent") def parent(self, obj): if obj.main_product_id: return obj.main_product if obj.sub_product_id: return obj.sub_product return "—"