Skip to content

Commit

Permalink
feat: Initial implementation of the accordion XBlock
Browse files Browse the repository at this point in the history
Initial working Accordion XBlock
  • Loading branch information
xitij2000 committed Jul 31, 2024
1 parent 2104226 commit dfa5a5f
Show file tree
Hide file tree
Showing 63 changed files with 98,517 additions and 410 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/ci-frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Frontend CI

on:
push:
branches:
- main
pull_request:

jobs:
tests:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend
strategy:
matrix:
npm-test:
# - i18n_extract
- lint
- test
steps:
- uses: actions/checkout@v4
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
- uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VER }}
- run: npm ci
- run: npm run lint
- run: npm run test
- name: upload coverage
uses: codecov/codecov-action@v3
with:
fail_ci_if_error: false
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
python-version: ['3.8']
toxenv: [quality, docs, django32, django40]
python-version: ['3.11', '3.12']
toxenv: [quality, docs, django42]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: setup python
uses: actions/setup-python@v2
with:
Expand All @@ -37,7 +37,7 @@ jobs:
run: tox

- name: Run coverage
if: matrix.python-version == '3.8' && matrix.toxenv == 'django32'
if: matrix.python-version == '3.11' && matrix.toxenv == 'django42'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pip-log.txt
.tox
coverage.xml
htmlcov/
coverage/

# Virtual environments
/venv/
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM openedx/xblock-sdk
RUN mkdir -p /usr/local/src/xblock-accordion
VOLUME ["/usr/local/src/xblock-accordion"]
RUN apt-get update && apt-get install -y gettext
RUN echo "pip install -r /usr/local/src/xblock-accordion/requirements.txt" >> /usr/local/src/xblock-sdk/install_and_run_xblock.sh
RUN echo "pip install -r /usr/local/src/xblock-accordion/requirements/dev.txt" >> /usr/local/src/xblock-sdk/install_and_run_xblock.sh
RUN echo "pip install -e /usr/local/src/xblock-accordion" >> /usr/local/src/xblock-sdk/install_and_run_xblock.sh
RUN echo "cd /usr/local/src/xblock-accordion && make compile_translations && cd /usr/local/src/xblock-sdk" >> /usr/local/src/xblock-sdk/install_and_run_xblock.sh
RUN echo "exec python /usr/local/src/xblock-sdk/manage.py \"\$@\"" >> /usr/local/src/xblock-sdk/install_and_run_xblock.sh
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ dev.build:
docker build -t $(REPO_NAME)-dev $(CURDIR)

dev.run: dev.clean dev.build ## Clean, build and run test image
docker run -p 8000:8000 -v $(CURDIR):/usr/local/src/$(REPO_NAME) --name $(REPO_NAME)-dev $(REPO_NAME)-dev
docker run -p 8200:8000 -v $(CURDIR):/usr/local/src/$(REPO_NAME) --name $(REPO_NAME)-dev $(REPO_NAME)-dev

## Localization targets

Expand Down
2 changes: 1 addition & 1 deletion accordion/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

from .accordion import AccordionXBlock

__version__ = '0.1.0'
__version__ = "0.1.0"
134 changes: 60 additions & 74 deletions accordion/accordion.py
Original file line number Diff line number Diff line change
@@ -1,107 +1,93 @@
"""TO-DO: Write a description of what this XBlock is."""
"""
An XBlock for creating and accordion component with multiple panels with rich content.
"""

from importlib import resources

import pkg_resources
from django.utils import translation
from web_fragments.fragment import Fragment
from xblock.core import XBlock
from xblock.fields import Integer, Scope
from xblockutils.resources import ResourceLoader
from xblock.fields import Dict, List, Scope, String


class AccordionXBlock(XBlock):
"""
TO-DO: document what your XBlock does.
Accordion XBlock.
"""

# Fields are defined on the class. You can access them in your code as
# self.<fieldname>.

# TO-DO: delete count, and define your own fields.
count = Integer(
default=0, scope=Scope.user_state,
help="A simple counter, to show something happening",
display_name = String(default=translation.gettext_noop("Accordion"))
panels = List(help="Accordion entries", default=[], scope=Scope.content)
styling = Dict(help="Accordion styling", default=[], scope=Scope.content)
border_style = String(
help="Accordion border style", default="", scope=Scope.content
)

def resource_string(self, path):
"""Handy helper for getting resources from our kit."""
data = pkg_resources.resource_string(__name__, path)
return data.decode("utf8")
data = resources.files("accordion").joinpath(path).read_text("utf8")
return data

# TO-DO: change this view to display your data your own way.
def student_view(self, context=None):
def student_view(self, context=None): # pylint: disable=unused-argument
"""
Create primary view of the AccordionXBlock, shown to students when viewing courses.
"""
if context:
pass # TO-DO: do something based on the context.
html = self.resource_string("static/html/accordion.html")
frag = Fragment(html.format(self=self))
frag.add_css(self.resource_string("static/css/accordion.css"))

# Add i18n js
statici18n_js_url = self._get_statici18n_js_url()
if statici18n_js_url:
frag.add_javascript_url(self.runtime.local_resource_url(self, statici18n_js_url))

frag.add_javascript(self.resource_string("static/js/src/accordion.js"))
frag.initialize_js('AccordionXBlock')
frag = Fragment()
frag.add_javascript(self.resource_string("static/student.js"))
frag.add_css_url(self.runtime.local_resource_url(self, "public/student-ui.css"))
frag.initialize_js(
"AccordionBlock",
{
"url": self.runtime.local_resource_url(self, "public/student-ui.js"),
"panels": self.panels,
"styling": self.styling,
},
)
return frag

# TO-DO: change this handler to perform your own actions. You may need more
# than one handler, or you may not need any handlers at all.
@XBlock.json_handler
def increment_count(self, data, suffix=''):
def studio_save(self, data, suffix=""): # pylint: disable=unused-argument
"""Save config and data based on data received at this API endpoint."""
panels = data.get("panels", None)
styling = data.get("styling", None)

Check warning on line 51 in accordion/accordion.py

View check run for this annotation

Codecov / codecov/patch

accordion/accordion.py#L50-L51

Added lines #L50 - L51 were not covered by tests
if panels:
self.panels = panels

Check warning on line 53 in accordion/accordion.py

View check run for this annotation

Codecov / codecov/patch

accordion/accordion.py#L53

Added line #L53 was not covered by tests
if styling:
self.styling = styling

Check warning on line 55 in accordion/accordion.py

View check run for this annotation

Codecov / codecov/patch

accordion/accordion.py#L55

Added line #L55 was not covered by tests

def studio_view(self, context=None): # pylint: disable=unused-argument
"""
Increments data. An example handler.
Create primary view of the AccordionXBlock, shown to students when viewing courses.
"""
if suffix:
pass # TO-DO: Use the suffix when storing data.
# Just to show data coming in...
assert data['hello'] == 'world'

self.count += 1
return {"count": self.count}
html = self.resource_string("static/html/accordion.html")
frag = Fragment(html)
frag.add_javascript(self.resource_string("static/studio.js"))
frag.add_css_url(self.runtime.local_resource_url(self, "public/studio-ui.css"))
frag.initialize_js(
"AccordionEditor",
{
"url": self.runtime.local_resource_url(self, "public/studio-ui.js"),
"panels": self.panels,
"styling": self.styling,
},
)
return frag

# TO-DO: change this to create the scenarios you'd like to see in the
# workbench while developing your XBlock.
@staticmethod
def workbench_scenarios():
"""Create canned scenario for display in the workbench."""
return [
("AccordionXBlock",
"""<accordion/>
"""),
("Multiple AccordionXBlock",
"""<vertical_demo>
(
"AccordionXBlock",
"""<accordion/>
""",
),
(
"Multiple AccordionXBlock",
"""<vertical_demo>
<accordion/>
<accordion/>
<accordion/>
</vertical_demo>
"""),
""",
),
]

@staticmethod
def _get_statici18n_js_url():
"""
Return the Javascript translation file for the currently selected language, if any.
Defaults to English if available.
"""
locale_code = translation.get_language()
if locale_code is None:
return None
text_js = 'public/js/translations/{locale_code}/text.js'
lang_code = locale_code.split('-')[0]
for code in (locale_code, lang_code, 'en'):
loader = ResourceLoader(__name__)
if pkg_resources.resource_exists(
loader.module_name, text_js.format(locale_code=code)):
return text_js.format(locale_code=code)
return None

@staticmethod
def get_dummy():
"""
Generate initial i18n with dummy method.
"""
return translation.gettext_noop('Dummy')
1 change: 1 addition & 0 deletions accordion/public/student-ui.css

Large diffs are not rendered by default.

Loading

0 comments on commit dfa5a5f

Please sign in to comment.