Skip to content

Conversation

@kdmccormick
Copy link
Member

@kdmccormick kdmccormick commented Jun 25, 2025

Description

This adds several admin pages which were previously missing or barebones: Section, Subsection, Unit, Container, and EntityList. The Container and EntityList pages have inlines tables to display their related ContainerVersions and EntityListsRows. This enables developers/operators to browse up and down the content hierarchies that are stored in Learning Core.

Testing Instructions

Using edx-platform master:

  • From Studio, go to Libraries (Beta) and create a new library.
  • Populate it with some mix of components, units, subsections, and sections
  • Go to http://studio.local.openedx.io:8001/admin/oel_sections/section/. You should see a list of Sections.
  • Click a Section's KEY to dive into its associated Container model.
    • Sanity-check the metadata and the list of ContainerVersions
    • Click into one of the EntityLists under CHILDREN
      • Confirm that at least one of the CONTAINER VERSIONS THAT REFERENCE THIS ENTITY LIST points back at the Container model you were just looking at.
      • Check that the ENITY LIST ROWS have Containers linked to Subsections, and click into one of them.
        • Continue sanity-checking down the hiearchy (Section->Subseciton->Unit->Component) until you hit the bottom.
      • Traverse back up the hierarchy by clicking "Most recent parent entity list" from any EntityList admin page.

Screenshots

Admin page for a Subsection

Just points you to the admin page for that associated Container, since that's where the interesting info is.

Screenshot 2025-06-26 at 3 22 19 PM

Admin page for that Subsection's associated Container

Each ContainerVersion is linked to an EntityList.

Screenshot 2025-06-16 at 3 57 51 PM

Admin page for the EntityList of a Subsection

Each row is a Container linked to a Unit, with a child EntityList of its own

Screenshot 2025-06-16 at 4 00 04 PM

Entity list of a Unit

Each row is a Component

Screenshot 2025-06-16 at 3 54 41 PM

@kdmccormick kdmccormick mentioned this pull request Jun 25, 2025
@kdmccormick kdmccormick force-pushed the kdmccormick/admin branch 2 times, most recently from 61f8fac to 80aa3a2 Compare June 26, 2025 19:35
@kdmccormick kdmccormick marked this pull request as ready for review June 26, 2025 19:35
@kdmccormick
Copy link
Member Author

@ormsbee @bradenmacdonald Low priority, but I pulled the admin pages in from the prototype branch. Could be nice to have merged before people who see our talk start poking around in Learning Core.

Copy link
Contributor

@bradenmacdonald bradenmacdonald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is great! I had some feedback but it's super minor - consider it all optional.

list_display = ["section_id", "key"]
fields = ["see"]
readonly_fields = ["see"]
inlines = [SectionVersionInline]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these inlines are very useful. The one you see when you click on the "See" link to view the Container admin has way more data and is much more useful. So I think it's better to just remove this so people don't waste their time reviewing the data on this page, and click through to the Container page.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had initially omitted this inline, but I ended up needing to add it in order to diagnose an bug where the modulestore_migrator was creating ContainerVersions but not their connected subclasses (SectionVersion, etc.). As long as it's possible to create a section's ContainerVersion but not its SectionVersion, I'd like to keep this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, that makes sense. Maybe mention that in a comment so others don't have the same question as me in the future?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, done



@admin.register(Section)
class SectionAdmin(ReadOnlyModelAdmin):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think the default title used in the admin interface isn't great, and it looks nicer if we override __str__ on the model to pull the title from the latest draft.

with __str__
Screenshot 2025-07-16 at 3 01 06 PM Screenshot 2025-07-16 at 3 00 35 PM

Copy link
Member Author

@kdmccormick kdmccormick Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Counterproposal... given that PEs already stringify to their key:

class PublishableEntity(models.Model):
    ...
    def __str__(self):
        return f"{self.key}"

how about I make PEVs stringify like this:

class PublishableEntityVersion(models.Model):
    ...
    def __str__(self):
        return f"{self.entity.key} @ v{self.version_num}"

and then make it so their mixin models default to the same behavior?

class PublishableEntityMixin(models.Model):
    ...
    def __str__(self) -> str:
        return str(self.publishable_entity) 

class PublishableEntityVersionMixin(models.Model):
    ...
    def __str__(self) -> str:
        return str(self.publishable_entity_version)

I know that the titles are nicer sometimes, but I feel that the keys and version nums better represent the models.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe have the title at the end?

    # <bikeshed>
    def __str__(self):
        return f"{self.entity.key} @ v{self.version_num} - {self.title}"
    # </bikeshed>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it makes the inline a little busy, but that's fine
Screenshot 2025-07-21 at 1 22 00 PM

Very minimal interface... just direct the admin user's attention towards the related Container model admin.
"""
list_display = ["section_id", "key"]
fields = ["see"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I found "See" to be a bit ambiguous at first.

Screenshot 2025-07-16 at 3 13 40 PM

I think this would be more clear:

Screenshot 2025-07-16 at 3 12 31 PM

Which can be accomplished by overriding get_form on the Section/Subsection/Unit admin class.

    def get_form(self, request, obj=None, change=False, **kwargs):
        help_texts = {'container': 'To see details of this section, click above to see its container view.'}
        kwargs.update({'help_texts': help_texts})
        return super().get_form(request, obj, **kwargs)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I applied this to each core container type, with some tweaks to ensure that it doesn't seem like "Container" refers to some container that holds this as a child.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2025-07-21 at 1 25 12 PM

"""
if draft := obj.versioning.draft:
return format_html(
"Version {} ({})", draft.version_num, _entity_list_detail_link(draft.entity_list)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit/optional: I think the uuid is not very useful, and the title is, so I suggest taking out the former and adding the latter.

Suggested change
"Version {} ({})", draft.version_num, _entity_list_detail_link(draft.entity_list)
'Version {} "{}" ({})', draft.version_num, draft.title, _entity_list_detail_link(draft.entity_list)

Screenshot:

Screenshot 2025-07-16 at 3 19 36 PM

vs.

Screenshot 2025-07-16 at 3 20 07 PM

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Changed for both Draft and Published.

I also removed all other occurrences of UUID from the various container-related admin lists, detail views, and inlines. We're not using the UUIDs for anything right now, so I'd rather it not clutter up the useful information with something irrelevant. If an operator really needs to know something's UUID, it is available on the linked PublishableEntity detail view.

@ormsbee
Copy link
Contributor

ormsbee commented Jul 21, 2025

Nothing to add to @bradenmacdonald's review. It looks great. 😄

This adds several admin pages which were previously missing or barebones:
Section, Subsection, Unit, Container, and EntityList. The Container and
EntityList pages have inlines tables to display their related ContainerVersions
and EntityListsRows. This enables developers/operators to browse up and down
the content hierarchies that are stored in Learning Core.
@kdmccormick kdmccormick merged commit a347d40 into openedx:main Jul 21, 2025
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants