Commit 45bb18a6 by Tim Krones

Turn "Root block ID" field into user-friendly dropdown.

parent 3fc57163
...@@ -34,6 +34,7 @@ loader = ResourceLoader(__name__) ...@@ -34,6 +34,7 @@ loader = ResourceLoader(__name__)
PAGE_SIZE = 15 PAGE_SIZE = 15
# Make '_' a no-op so we can scrape strings # Make '_' a no-op so we can scrape strings
def _(text): def _(text):
return text return text
...@@ -128,9 +129,53 @@ class InstructorToolBlock(XBlock): ...@@ -128,9 +129,53 @@ class InstructorToolBlock(XBlock):
_('Rating Question'): 'RatingBlock', _('Rating Question'): 'RatingBlock',
_('Long Answer'): 'AnswerBlock', _('Long Answer'): 'AnswerBlock',
} }
block_types = ('pb-mcq', 'pb-rating', 'pb-answer')
flat_block_tree = []
def build_tree(block, ancestors):
"""
Build up a tree of information about the XBlocks descending from root_block
"""
block_id = block.scope_ids.usage_id.block_id
block_name = getattr(block, "display_name", None)
block_type = block.runtime.id_reader.get_block_type(block.scope_ids.def_id)
if not block_name and block_type in block_types:
block_name = block.question
eligible = block_type in block_types
if eligible:
# If this block is a question whose answers we can export,
# we mark all of its ancestors as exportable too
if ancestors and not ancestors[-1]["eligible"]:
for ancestor in ancestors:
ancestor["eligible"] = True
new_entry = {
"depth": len(ancestors),
"id": block_id,
"name": block_name,
"eligible": eligible,
}
flat_block_tree.append(new_entry)
if block.has_children and not block_type == 'pb-mcq' and not \
getattr(block, "has_dynamic_children", lambda: False)():
for child_id in block.children:
build_tree(block.runtime.get_block(child_id), ancestors=(ancestors + [new_entry]))
root_block = self
while root_block.parent:
root_block = root_block.get_parent()
root_entry = {
"depth": 0,
"id": root_block.scope_ids.usage_id.block_id,
"name": "All",
}
flat_block_tree.append(root_entry)
for child_id in root_block.children:
child_block = root_block.runtime.get_block(child_id)
build_tree(child_block, [root_entry])
html = loader.render_template( html = loader.render_template(
'templates/html/instructor_tool.html', 'templates/html/instructor_tool.html',
{'block_choices': block_choices} {'block_choices': block_choices, 'block_tree': flat_block_tree}
) )
fragment = Fragment(html) fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/instructor_tool.css')) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/instructor_tool.css'))
...@@ -212,9 +257,6 @@ class InstructorToolBlock(XBlock): ...@@ -212,9 +257,6 @@ class InstructorToolBlock(XBlock):
root_block_id = self.scope_ids.usage_id root_block_id = self.scope_ids.usage_id
# Block ID not in workbench runtime. # Block ID not in workbench runtime.
root_block_id = unicode(getattr(root_block_id, 'block_id', root_block_id)) root_block_id = unicode(getattr(root_block_id, 'block_id', root_block_id))
get_root = True
else:
get_root = False
# Launch task # Launch task
from .tasks import export_data as export_data_task # Import here since this is edX LMS specific from .tasks import export_data as export_data_task # Import here since this is edX LMS specific
...@@ -228,7 +270,6 @@ class InstructorToolBlock(XBlock): ...@@ -228,7 +270,6 @@ class InstructorToolBlock(XBlock):
block_types, block_types,
user_id, user_id,
match_string, match_string,
get_root=get_root
) )
if async_result.ready(): if async_result.ready():
# In development mode, the task may have executed synchronously. # In development mode, the task may have executed synchronously.
......
...@@ -25,6 +25,12 @@ ...@@ -25,6 +25,12 @@
display: table-cell; display: table-cell;
padding-left: 1em; padding-left: 1em;
} }
.data-export-field-container {
min-width: 45%;
}
.data-export-options .data-export-actions {
max-width: 10%;
}
.data-export-field { .data-export-field {
margin-top: .5em; margin-top: .5em;
margin-bottom: .5em; margin-bottom: .5em;
...@@ -34,7 +40,7 @@ ...@@ -34,7 +40,7 @@
vertical-align: middle; vertical-align: middle;
} }
.data-export-field input, .data-export-field select { .data-export-field input, .data-export-field select {
max-width: 60%; max-width: 55%;
float: right; float: right;
} }
.data-export-results, .data-export-download, .data-export-cancel, .data-export-delete { .data-export-results, .data-export-download, .data-export-cancel, .data-export-delete {
......
...@@ -170,7 +170,7 @@ function InstructorToolBlock(runtime, element) { ...@@ -170,7 +170,7 @@ function InstructorToolBlock(runtime, element) {
var $downloadButton = $element.find('.data-export-download'); var $downloadButton = $element.find('.data-export-download');
var $deleteButton = $element.find('.data-export-delete'); var $deleteButton = $element.find('.data-export-delete');
var $blockTypes = $element.find("select[name='block_types']"); var $blockTypes = $element.find("select[name='block_types']");
var $rootBlockId = $element.find("input[name='root_block_id']"); var $rootBlockId = $element.find("select[name='root_block_id']");
var $username = $element.find("input[name='username']"); var $username = $element.find("input[name='username']");
var $matchString = $element.find("input[name='match_string']"); var $matchString = $element.find("input[name='match_string']");
var $resultTable = $element.find('.data-export-results'); var $resultTable = $element.find('.data-export-results');
......
...@@ -20,7 +20,7 @@ logger = get_task_logger(__name__) ...@@ -20,7 +20,7 @@ logger = get_task_logger(__name__)
@task() @task()
def export_data(course_id, source_block_id_str, block_types, user_id, match_string, get_root=True): def export_data(course_id, source_block_id_str, block_types, user_id, match_string):
""" """
Exports student answers to all MCQ questions to a CSV file. Exports student answers to all MCQ questions to a CSV file.
""" """
...@@ -34,12 +34,6 @@ def export_data(course_id, source_block_id_str, block_types, user_id, match_stri ...@@ -34,12 +34,6 @@ def export_data(course_id, source_block_id_str, block_types, user_id, match_stri
raise ValueError("Could not find the specified Block ID.") raise ValueError("Could not find the specified Block ID.")
course_key_str = unicode(course_key) course_key_str = unicode(course_key)
root = src_block
if get_root:
# Get the root block for the course.
while root.parent:
root = root.get_parent()
type_map = {cls.__name__: cls for cls in [MCQBlock, RatingBlock, AnswerBlock]} type_map = {cls.__name__: cls for cls in [MCQBlock, RatingBlock, AnswerBlock]}
if not block_types: if not block_types:
...@@ -62,7 +56,7 @@ def export_data(course_id, source_block_id_str, block_types, user_id, match_stri ...@@ -62,7 +56,7 @@ def export_data(course_id, source_block_id_str, block_types, user_id, match_stri
# Blocks may refer to missing children. Don't break in this case. # Blocks may refer to missing children. Don't break in this case.
pass pass
scan_for_blocks(root) scan_for_blocks(src_block)
# Define the header row of our CSV: # Define the header row of our CSV:
rows = [] rows = []
......
...@@ -27,8 +27,16 @@ ...@@ -27,8 +27,16 @@
<div class="data-export-field-container"> <div class="data-export-field-container">
<div class="data-export-field"> <div class="data-export-field">
<label> <label>
<span>{% trans "Root block ID:" %}</span> <span>{% trans "Section/Question:" %}</span>
<input type="text" name="root_block_id" /> <select name="root_block_id">
{% for block in block_tree %}
<option value="{{ block.id }}"
{% if not block.eligible %} disabled="disabled" {% endif %}>
{% for _ in ""|ljust:block.depth %}&nbsp;&nbsp;{% endfor %}
{{ block.name }}
</option>
{% endfor %}
</select>
</label> </label>
</div> </div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment