From 0ff791f2478eb67d1884e8c265ab059a3a175415 Mon Sep 17 00:00:00 2001 From: Arslan Date: Tue, 19 Nov 2024 16:27:23 +0500 Subject: [PATCH] feat: add basic data fields and design --- src/ol_openedx_chat/block.py | 57 ++++++++++++------- src/ol_openedx_chat/constants.py | 3 + src/ol_openedx_chat/static/css/studio.css | 27 +++++++++ .../static/html/studio_view.html | 47 ++++++++------- src/ol_openedx_chat/utils.py | 8 +++ 5 files changed, 101 insertions(+), 41 deletions(-) create mode 100644 src/ol_openedx_chat/constants.py create mode 100644 src/ol_openedx_chat/static/css/studio.css create mode 100644 src/ol_openedx_chat/utils.py diff --git a/src/ol_openedx_chat/block.py b/src/ol_openedx_chat/block.py index a6f56f04..900f62ce 100644 --- a/src/ol_openedx_chat/block.py +++ b/src/ol_openedx_chat/block.py @@ -1,10 +1,11 @@ import pkg_resources from django.template import Context, Template +from django.utils.translation import gettext_lazy as _ +from ol_openedx_chat.utils import is_aside_applicable_to_block from web_fragments.fragment import Fragment from xblock.core import XBlockAside - -BLOCK_PROBLEM_CATEGORY = "problem" -MULTIPLE_CHOICE_TYPE = "multiplechoiceresponse" +from xblock.fields import Boolean, Scope, String +from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW def get_resource_bytes(path): @@ -36,22 +37,52 @@ class OLChatAside(XBlockAside): XBlock aside that enables OL AI Chat functionality for an XBlock """ - @XBlockAside.aside_for("student_view") - def student_view_aside(self, block, context=None): # noqa: ARG002 + enabled = Boolean( + display_name=_("Open Learning Chat enabled status"), + default=False, + scope=Scope.settings, + help=_("Indicates whether or not Open Learning chat is enabled for a block"), + ) + prompt_text = String( + display_name=_("Open Learning Chat Prompt text"), + default="", + scope=Scope.settings, + help=_("Saves the prompt hint text for chat in a block"), + ) + selected_gpt_model = String( + display_name=_("Open Learning Chat selected GPT model"), + default="", + scope=Scope.settings, + help=_("Saves the selected GPT model for a block"), + ) + + editable_fields = ("enabled", "prompt_text", "selected_gpt_model") + + @XBlockAside.aside_for(STUDENT_VIEW) + def student_view_aside(self, block, context=None): """ Renders the aside contents for the student view """ # noqa: D401 + + # This is a workaround for those blocks which do not have has_author_view=True + # in them in edx code because when a block does not define has_author_view=True + # in it, the only view that gets rendered is student_view in place of + # Author view. + if getattr(self.runtime, "is_author_mode", False): + return self.author_view_aside(block, context) + fragment = Fragment("") fragment.add_content(render_template("static/html/student_view.html")) return fragment - @XBlockAside.aside_for("author_view") + @XBlockAside.aside_for(AUTHOR_VIEW) def author_view_aside(self, block, context=None): # noqa: ARG002 """ Renders the aside contents for the author view """ # noqa: D401 fragment = Fragment("") fragment.add_content(render_template("static/html/studio_view.html")) + fragment.add_css(get_resource_bytes("static/css/studio.css")) return fragment @classmethod @@ -64,16 +95,4 @@ def should_apply_to_block(cls, block): instances, the problem type of the given block needs to be retrieved in different ways. """ # noqa: D401 - if getattr(block, "category", None) != BLOCK_PROBLEM_CATEGORY: - return False - block_problem_types = None - # LMS passes in the block instance with `problem_types` as a property of - # `descriptor` - if hasattr(block, "descriptor"): - block_problem_types = getattr(block.descriptor, "problem_types", None) - # Studio passes in the block instance with `problem_types` as a top-level property # noqa: E501 - elif hasattr(block, "problem_types"): - block_problem_types = block.problem_types - # We only want this aside to apply to the block if the problem is multiple - # choice AND there are not multiple problem types. - return block_problem_types == {MULTIPLE_CHOICE_TYPE} + return is_aside_applicable_to_block(block=block) diff --git a/src/ol_openedx_chat/constants.py b/src/ol_openedx_chat/constants.py new file mode 100644 index 00000000..40972a9e --- /dev/null +++ b/src/ol_openedx_chat/constants.py @@ -0,0 +1,3 @@ +# The dictionary should contain all the block types for which the chat should be +# applicable If a block has sub-blocks or sub category, that should be added in the list +CHAT_APPLICABLE_BLOCKS = ["problem", "video"] diff --git a/src/ol_openedx_chat/static/css/studio.css b/src/ol_openedx_chat/static/css/studio.css new file mode 100644 index 00000000..be4e3207 --- /dev/null +++ b/src/ol_openedx_chat/static/css/studio.css @@ -0,0 +1,27 @@ +.form-container { + max-width: 400px; + margin: 20px auto; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #f9f9f9; +} +.form-container label { + display: block; + margin: 10px 0 5px; +} +.form-container input, +.form-container select, +.form-container button { + width: 100%; + padding: 8px; + margin-bottom: 10px; + border: 1px solid #ccc; + border-radius: 4px; +} +.form-container .checkbox-container label { + display: block; +} +.form-container .checkbox-container input { + width: auto; +} diff --git a/src/ol_openedx_chat/static/html/studio_view.html b/src/ol_openedx_chat/static/html/studio_view.html index a5265085..bba2e541 100644 --- a/src/ol_openedx_chat/static/html/studio_view.html +++ b/src/ol_openedx_chat/static/html/studio_view.html @@ -1,25 +1,28 @@ -
+ -
- - -
+
+
+ + + -
- - -
+ + + -
+ +
+ +
+ + + + +
+ + diff --git a/src/ol_openedx_chat/utils.py b/src/ol_openedx_chat/utils.py new file mode 100644 index 00000000..e4c70884 --- /dev/null +++ b/src/ol_openedx_chat/utils.py @@ -0,0 +1,8 @@ +"""Utility methods for the AI chat""" + +from ol_openedx_chat.constants import CHAT_APPLICABLE_BLOCKS + + +def is_aside_applicable_to_block(block): + """Check if the xBlock should support AI Chat""" + return getattr(block, "category", None) in CHAT_APPLICABLE_BLOCKS