Database
diff --git a/workbench/test/test_scenarios.py b/workbench/test/test_scenarios.py
index 0bcdb96f..f6a52daf 100644
--- a/workbench/test/test_scenarios.py
+++ b/workbench/test/test_scenarios.py
@@ -62,6 +62,7 @@ def test_scenario(self):
it forces database access, which pytest_django doesn't like.
"""
scenario_ids = list(scenarios.get_scenarios().keys())
+ views_seen = set()
for scenario_id in scenario_ids:
url = reverse('workbench_show_scenario', kwargs={'scenario_id': scenario_id})
@@ -77,3 +78,9 @@ def test_scenario(self):
for vertical_tag in html.xpath('//div[@class="vertical"]'):
# No vertical tag should be empty.
assert list(vertical_tag), f"Scenario {scenario_id}: Empty shouldn't happen!"
+ # Default view for scenario should be the student view.
+ indicator = html.xpath('//div[@class="current-view-indicator"]')[0]
+ assert "Current view: student_view" in indicator.text
+ views_seen |= set(el.text.strip() for el in html.xpath('//a[@class="block-view-link"]'))
+ # At least one of our test blocks should have the studio view available, or else we need to add one which does.
+ assert "studio_view" in views_seen
diff --git a/workbench/views.py b/workbench/views.py
index 57c99073..15292fa3 100644
--- a/workbench/views.py
+++ b/workbench/views.py
@@ -26,6 +26,7 @@
log = logging.getLogger(__name__)
+KNOWN_BLOCK_VIEWS = ['student_view', 'author_view', 'studio_view']
# We don't really have authentication and multiple students, just accept their
# id on the URL.
@@ -35,6 +36,24 @@ def get_student_id(request):
return student_id
+def can_render_view(block, view_name, root=False) -> bool:
+ """
+ Verifies that a view can be rendered by a block.
+ """
+ if (children := getattr(block, 'children', [])) and not root:
+ child_blocks = (block.runtime.get_block(child_id) for child_id in children)
+ return (
+ can_render_view(block, view_name, root=True) and
+ all(can_render_view(child, view_name) for child in child_blocks)
+ )
+ return getattr(block, view_name, getattr(block, "fallback_view", None)) is not None
+
+
+def get_block_views(block: XBlock) -> set[str]:
+ """Get the available views for a block."""
+ return {view_name for view_name in KNOWN_BLOCK_VIEWS if can_render_view(block, view_name)}
+
+
# ---- Views -----
def index(_request):
@@ -74,15 +93,20 @@ def show_scenario(request, scenario_id, view_name='student_view', template='work
'activate_block_id': request.GET.get('activate_block_id', None)
}
+ other_views = sorted(get_block_views(block) - {view_name})
+
frag = block.render(view_name, render_context)
log.info("End show_scenario %s", scenario_id)
return render(request, template, {
+ 'scenario_id': scenario_id,
'scenario': scenario,
'block': block,
'body': frag.body_html(),
'head_html': frag.head_html(),
'foot_html': frag.foot_html(),
'student_id': student_id,
+ 'view_name': view_name,
+ 'other_views': other_views,
})