From f11dc20d4016e3c93d14878983e73b46b27635e5 Mon Sep 17 00:00:00 2001 From: farhan Date: Mon, 6 Apr 2026 18:16:24 +0500 Subject: [PATCH 1/3] chore: Adds the watcher to the assets directories of xblocks-contrib --- package.json | 1 + xblocks_contrib/discussion/assets/package.json | 1 + xblocks_contrib/problem/assets/package.json | 1 + xblocks_contrib/video/assets/package.json | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f99e852..d67957ff 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "build": "npm run build --workspaces --if-present", "build-dev": "npm run build-dev --workspaces --if-present", + "watch-build-dev": "for w in xblocks_contrib/*/assets; do npm run watch-build-dev --if-present -w \"$w\" & done; wait", "test": "npm run test --workspaces --if-present", "test-ci": "npm run test-ci --workspaces --if-present" } diff --git a/xblocks_contrib/discussion/assets/package.json b/xblocks_contrib/discussion/assets/package.json index 8c586785..2352211d 100644 --- a/xblocks_contrib/discussion/assets/package.json +++ b/xblocks_contrib/discussion/assets/package.json @@ -3,6 +3,7 @@ "scripts": { "build": "webpack --config webpack.prod.config.js", "build-dev": "webpack --config webpack.dev.config.js", + "watch-build-dev": "npm run build-dev -- --watch", "test": "karma start karma.conf.js", "test-ci": "xvfb-run --auto-servernum karma start karma.conf.js" }, diff --git a/xblocks_contrib/problem/assets/package.json b/xblocks_contrib/problem/assets/package.json index 73e091c9..bef2e809 100644 --- a/xblocks_contrib/problem/assets/package.json +++ b/xblocks_contrib/problem/assets/package.json @@ -5,6 +5,7 @@ "scripts": { "build": "webpack --config=webpack.prod.config.js", "build-dev": "webpack --config=webpack.config.js", + "watch-build-dev": "npm run build-dev -- --watch", "test": "karma start karma.conf.js", "test-ci": "xvfb-run --auto-servernum karma start karma.conf.js" }, diff --git a/xblocks_contrib/video/assets/package.json b/xblocks_contrib/video/assets/package.json index ee2ab104..2bbbe92a 100644 --- a/xblocks_contrib/video/assets/package.json +++ b/xblocks_contrib/video/assets/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "webpack --config webpack.prod.config.js", "build-dev": "webpack --config webpack.dev.config.js", - + "watch-build-dev": "npm run build-dev -- --watch", "test-ci": "xvfb-run --auto-servernum karma start karma.conf.js", "test": "karma start karma.conf.js --log-level debug" }, From 2d1132d50f7f7b61a84b77eac722722c3bf9a490 Mon Sep 17 00:00:00 2001 From: farhan Date: Tue, 7 Apr 2026 17:50:48 +0500 Subject: [PATCH 2/3] chore: removed the legacy content of readme file --- .dockerignore | 1 - Dockerfile | 23 ---- Makefile | 23 +--- README.rst | 35 +---- utils/config.yaml | 93 ------------- utils/create_xblock.sh | 298 ----------------------------------------- 6 files changed, 5 insertions(+), 468 deletions(-) delete mode 100644 .dockerignore delete mode 100644 Dockerfile delete mode 100644 utils/config.yaml delete mode 100755 utils/create_xblock.sh diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 94143827..00000000 --- a/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index da708293..00000000 --- a/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# This Dockerfile sets up an XBlock SDK environment for developing and testing XBlocks. -# The following commands in the Makefile facilitate the Docker lifecycle: -# - `make dev.clean`: Cleans up any existing Docker containers and images. -# - `make dev.build`: Builds the Docker image for the XBlock SDK environment. -# - `make dev.run`: Cleans, builds, and runs the container, mapping the local project directory. - -FROM openedx/xblock-sdk:latest - -WORKDIR /usr/local/src/xblocks-contrib -VOLUME ["/usr/local/src/xblocks-contrib"] - -RUN apt-get update && apt-get install -y \ - gettext \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -COPY . /usr/local/src/xblocks-contrib/ - -RUN pip install -r requirements/dev.txt && pip install --force-reinstall -e . -RUN make compile_translations - -ENTRYPOINT ["bash", "-c", "python /usr/local/src/xblock-sdk/manage.py migrate && exec python /usr/local/src/xblock-sdk/manage.py runserver 0.0.0.0:8000"] -EXPOSE 8000 diff --git a/Makefile b/Makefile index 1bd387d9..23f06a66 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,10 @@ .DEFAULT_GOAL := help -.PHONY: dev.clean dev.build dev.run upgrade help requirements +.PHONY: upgrade help requirements .PHONY: extract_translations compile_translations .PHONY: detect_changed_source_translations dummy_translations build_dummy_translations .PHONY: validate_translations pull_translations push_translations install_transifex_clients -REPO_NAME := xblocks-contrib PACKAGE_NAME := xblocks_contrib EXTRACT_DIR := $(PACKAGE_NAME)/conf/locale/en/LC_MESSAGES JS_TARGET := $(PACKAGE_NAME)/public/js/translations @@ -37,26 +36,6 @@ piptools: ## install pinned version of pip-compile and pip-sync requirements: piptools ## install development environment requirements pip-sync -q requirements/dev.txt requirements/private.* -dev.clean: - -docker rm $(REPO_NAME)-dev - -docker rmi $(REPO_NAME)-dev - -dev.build: - docker build --no-cache -t $(REPO_NAME)-dev $(CURDIR) - -check-log: - @if [ ! -d "$(CURDIR)/var" ]; then \ - echo "Creating var directory"; \ - mkdir -p $(CURDIR)/var; \ - fi - @if [ ! -f "$(CURDIR)/var/workbench.log" ]; then \ - echo "Creating empty workbench.log"; \ - touch $(CURDIR)/var/workbench.log; \ - fi - -dev.run: dev.clean dev.build check-log - docker run -p 8000:8000 -v $(CURDIR):/usr/local/src/$(REPO_NAME) --name $(REPO_NAME)-dev $(REPO_NAME)-dev - # XBlock directories XBLOCKS=$(shell find $(shell pwd)/$(PACKAGE_NAME) -maxdepth 2 -type d -name 'conf' -exec dirname {} \;) diff --git a/README.rst b/README.rst index 44a6bf5f..b4b6ec31 100644 --- a/README.rst +++ b/README.rst @@ -23,16 +23,15 @@ These are the XBlocks being moved here, and each of their statuses: * ``lti`` -- Ready to Use * ``pdf`` -- Done * ``html`` -- Ready to Use -* ``discussion`` -- In Development -* ``problem`` -- In Development -* ``video`` -- In Development +* ``discussion`` -- Ready to Use +* ``problem`` -- Ready to Use +* ``video`` -- Ready to Use The possible XBlock statuses are: -* Placeholder: It's just a cookiecutter thumbs-up block. * In Development: We're building and testing this block. * Ready to Use: You can try this on your site using the Waffle flag. -* Done The built-in block has been removed. The setup.py entrypoint has been removed from edx-platform and added to xblock-contrib. +* Done: The built-in block has been removed. The setup.py entrypoint has been removed from edx-platform and added to xblock-contrib. Additional XBlocks that belong here @@ -48,30 +47,6 @@ Over time, more XBlocks may be moved here. An XBlock belongs here if and only if Otherwise, perhaps the block belongs in its own repository with a separate dedicated maintainer, such as `ora2 `_. -Developing a new XBlock -======================= - -There's a handy script ``utils/create_xblock.sh`` that you can use to create XBlock here. just run :: - - $ utils/create_xblock.sh - -It will ask for XBlock name and XBlock class name that you want to use. Just enter these values and XBlock should be ready to work. - -If faced with permission or access error run:: - - $ chmod +x utils/create_xblock.sh - -and run it. - -Testing with Docker -******************** - -This XBlock comes with a Docker test environment ready to build, based on the xblock-sdk workbench. To build and run it:: - - $ make dev.run - -The XBlock SDK Workbench, including this XBlock, will be available on the list of XBlocks at http://localhost:8000 - Translating ************* @@ -184,8 +159,6 @@ transifex credentials. See `transifex documentation `_ for more details about integrating django with transiflex. - **Note:** The ``dev.run`` make target will automatically compile any translations. - **Note:** To check if the source translation files (``.po``) are up-to-date run:: $ make detect_changed_source_translations diff --git a/utils/config.yaml b/utils/config.yaml deleted file mode 100644 index 4bfb0cac..00000000 --- a/utils/config.yaml +++ /dev/null @@ -1,93 +0,0 @@ -# Configuration for i18n workflow. - -locales: - - en # English - Source Language - # - am # Amharic - - ar # Arabic - # - az # Azerbaijani - # - bg_BG # Bulgarian (Bulgaria) - # - bn_BD # Bengali (Bangladesh) - # - bn_IN # Bengali (India) - # - bs # Bosnian - # - ca # Catalan - # - ca@valencia # Catalan (Valencia) - # - cs # Czech - # - cy # Welsh - # - da # Danish - # - de_DE # German (Germany) - # - el # Greek - # - en_GB # English (United Kingdom) - # # Don't pull these until we figure out why pages randomly display in these locales, - # # when the user's browser is in English and the user is not logged in. - # #- en@lolcat # LOLCAT English - # #- en@pirate # Pirate English - - es_419 # Spanish (Latin America) - # - es_AR # Spanish (Argentina) - # - es_EC # Spanish (Ecuador) - # - es_ES # Spanish (Spain) - # - es_MX # Spanish (Mexico) - # - es_PE # Spanish (Peru) - # - et_EE # Estonian (Estonia) - # - eu_ES # Basque (Spain) - # - fa # Persian - # - fa_IR # Persian (Iran) - # - fi_FI # Finnish (Finland) - # - fil # Filipino - - fr # French - # - gl # Galician - # - gu # Gujarati - - he # Hebrew - - hi # Hindi - # - hr # Croatian - # - hu # Hungarian - # - hy_AM # Armenian (Armenia) - # - id # Indonesian - # - it_IT # Italian (Italy) - # - ja_JP # Japanese (Japan) - # - kk_KZ # Kazakh (Kazakhstan) - # - km_KH # Khmer (Cambodia) - # - kn # Kannada - - ko_KR # Korean (Korea) - # - lt_LT # Lithuanian (Lithuania) - # - ml # Malayalam - # - mn # Mongolian - # - mr # Marathi - # - ms # Malay - # - nb # Norwegian Bokmål - # - ne # Nepali - # - nl_NL # Dutch (Netherlands) - # - or # Oriya - # - pl # Polish - - pt_BR # Portuguese (Brazil) - # - pt_PT # Portuguese (Portugal) - # - ro # Romanian - - ru # Russian - # - si # Sinhala - # - sk # Slovak - # - sl # Slovenian - # - sq # Albanian - # - sr # Serbian - # - sv # Swedish - # - sw # Swahili - # - ta # Tamil - # - te # Telugu - # - th # Thai - # - tr_TR # Turkish (Turkey) - # - uk # Ukranian - # - ur # Urdu - # - uz # Uzbek - # - vi # Vietnamese - - zh_CN # Chinese (China) - # - zh_HK # Chinese (Hong Kong) - # - zh_TW # Chinese (Taiwan) - - -# The locales used for fake-accented English, for testing. -dummy_locales: - - eo - - rtl # Fake testing language for Arabic - -# Directories we don't search for strings. -ignore_dirs: - - '*/css' - - 'public/js/translations' diff --git a/utils/create_xblock.sh b/utils/create_xblock.sh deleted file mode 100755 index 26e70713..00000000 --- a/utils/create_xblock.sh +++ /dev/null @@ -1,298 +0,0 @@ -#!/bin/bash - -# Function to insert entry in alphabetical order in setup.py under "xblock.v1" -insert_in_alphabetical_order() { - local entry="$1" - local setup_file="$2" - - awk -v new_entry="$entry" ' - BEGIN { added = 0; indent = "" } - /entry_points/ { print; next } - /"xblock.v1"/ { - print; - getline; - # Determine the indentation level - if (match($0, /^[ \t]+/)) { - indent = substr($0, RSTART, RLENGTH) - } - # Iterate over the lines inside the xblock.v1 list - while (getline > 0) { - # Stop when reaching the end of the list - if ($0 ~ /^\s*\]/ && !added) { - print indent new_entry "," - added = 1 - print $0 # Print the closing bracket - next - } - # Insert the new entry if it fits alphabetically - if (!added && $0 > indent new_entry) { - print indent new_entry "," - added = 1 - } - print - } - next - } - { print } - ' "$setup_file" > temp_setup.py && mv temp_setup.py "$setup_file" -} - -# Function to insert import before __version__ variable in __init__.py -insert_import_before_version() { - local import_entry="$1" - local init_file="$2" - - awk -v new_import="$import_entry" ' - BEGIN { added = 0 } - { - if (!added && /^__version__/) { - print new_import "\n" - added = 1 - } - print - } - ' "$init_file" > temp_init.py && mv temp_init.py "$init_file" -} - -# Prompt user for XBlock name and class -read -p "Enter XBlock name e.g thumbs: " xblock_name -read -p "Enter XBlock class e.g ThumbsXBlock: " xblock_class - -# Define paths and filenames -base_dir="xblocks_contrib/$xblock_name" -init_file="$base_dir/__init__.py" -xblock_file="$base_dir/$xblock_name.py" -static_dir="$base_dir/static" -templates_dir="$base_dir/templates" -conf_locale_dir="$base_dir/conf/locale" -tests_dir="$base_dir/tests" -setup_file="setup.py" -main_init_file="xblocks_contrib/__init__.py" -utils_config_file="utils/config.yaml" - -# Create directories -mkdir -p "$base_dir" "$static_dir/css" "$static_dir/js/src" "$templates_dir" "$conf_locale_dir" "$tests_dir" - -# Create empty files -touch "$init_file" "$xblock_file" "$static_dir/css/$xblock_name.css" "$static_dir/js/src/$xblock_name.js" "$templates_dir/$xblock_name.html" "$conf_locale_dir/__init__.py" - -# Copy config.yaml to conf/locale if it exists -[ -f "$utils_config_file" ] && cp "$utils_config_file" "$conf_locale_dir/" || echo "Warning: $utils_config_file does not exist." - -# Populate XBlock file with content -cat > "$xblock_file" <. - - # 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", - ) - - # Indicates that this XBlock has been extracted from edx-platform. - is_extracted = True - - def resource_string(self, path): - """Handy helper for getting resources from our kit.""" - return files(__package__).joinpath(path).read_text(encoding="utf-8") - - # TO-DO: change this view to display your data your own way. - def student_view(self, context=None): - """ - Create primary view of the $xblock_class, shown to students when viewing courses. - """ - if context: - pass # TO-DO: do something based on the context. - - frag = Fragment() - frag.add_content( - resource_loader.render_django_template( - "templates/$xblock_name.html", - { - "count": self.count, - }, - i18n_service=self.runtime.service(self, "i18n"), - ) - ) - - frag.add_css(self.resource_string("static/css/$xblock_name.css")) - frag.add_javascript(self.resource_string("static/js/src/$xblock_name.js")) - frag.initialize_js("$xblock_class") - 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=""): - """ - Increments data. An example handler. - """ - 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} - - # 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 [ - ( - "$xblock_class", - """<$xblock_name/> - """, - ), - ( - "Multiple $xblock_class", - """ - <$xblock_name/> - <$xblock_name/> - <$xblock_name/> - - """, - ), - ] - - @staticmethod - def get_dummy(): - """ - Generate initial i18n with dummy method. - """ - return translation.gettext_noop("Dummy") -EOL - -# Populate template HTML -cat > "$templates_dir/$xblock_name.html" < -

- $xblock_class: {% trans "count is now" %} {{ count }} {% trans "click me to increment." %} -

- -EOL - -# Populate JavaScript file -cat > "$static_dir/js/src/$xblock_name.js" < { - \$('.count', element).text(result.count); - }; - - const handlerUrl = runtime.handlerUrl(element, 'increment_count'); - - \$('p', element).on('click', (eventObject) => { - \$.ajax({ - type: 'POST', - url: handlerUrl, - contentType: 'application/json', - data: JSON.stringify({hello: 'world'}), - success: updateCount - }); - }); - - \$(() => { - /* - Use \`gettext\` provided by django-statici18n for static translations - */ - - // eslint-disable-next-line no-undef - const dummyText = gettext('Hello World'); - - // Example usage of interpolation for translated strings - // eslint-disable-next-line no-undef - const message = StringUtils.interpolate( - gettext('You are enrolling in {courseName}'), - { - courseName: 'Rock & Roll 101' - } - ); - console.log(message); // This is just for demonstration purposes - }); -} -EOL - -# Populate CSS file -cat > "$static_dir/css/$xblock_name.css" < "$tests_dir/test_${xblock_name}.py" < "$init_file" < Date: Tue, 7 Apr 2026 18:01:49 +0500 Subject: [PATCH 3/3] docs: update the readme; adds development guide --- README.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b4b6ec31..c9898f8d 100644 --- a/README.rst +++ b/README.rst @@ -47,6 +47,20 @@ Over time, more XBlocks may be moved here. An XBlock belongs here if and only if Otherwise, perhaps the block belongs in its own repository with a separate dedicated maintainer, such as `ora2 `_. + +Installation and Development Guide +********************************** + +Study scripts in the ``package.json`` file to understand the available commands. + +1. Install this repository into your runtime (for example ``openedx-platform``) as an editable dependency. For Tutor, you can mount this repository for local development. +2. Run ``npm run build`` to generate production public assets for the XBlocks. +3. Run ``npm run build-dev`` to generate development public assets for the XBlocks. +4. Run ``npm run watch-build-dev`` to watch for relevant file changes and regenerate public assets. + Recommended during development. Run it in a separate terminal; you will still need to refresh the browser to pick up rebuilt assets. +5. Run ``npm run test`` to run the repository tests. + + Translating ************* @@ -63,7 +77,7 @@ The general steps to provide multilingual messages for a Python program (or an X 3. Create language specific translations for each message in the catalogs. 4. Use ``gettext`` to translate strings. -5. Mark translatable strings +1. Mark translatable strings ---------------------------- Mark translatable strings in python::