The functionality of the Airavata Django Portal is broken up into separate Django apps. The apps live in the django_airavata/apps
directory. When adding new functionality to the Django portal it may make sense to add it as a new separate Django app instead of adding it to an existing app. The following steps document how to do this.
For this example, assume the name of the app is myapp. The following also assumes you have sourced your virtual environment.
cd airavata-django-portal mkdir django_airavata/apps/myapp python manage.py startapp myapp django_airavata/apps/myapp
Edit the AppConfig so that it extends the AiravataAppConfig and fill in the required details:
from django_airavata.app_config import AiravataAppConfig class MyAppConfig(AiravataAppConfig): name = 'django_airavata.apps.myapp' label = 'django_airavata_myapp' verbose_name = 'My App' app_order = 10 url_home = 'django_airavata_myapp:home' fa_icon_class = 'fa-bolt' app_description = """ My app for doing stuff in the Airavata Django Portal. """ nav = [ { 'label': 'Dashboard', 'icon': 'fa fa-tachometer-alt', 'url': 'django_airavata_myapp:dashboard', 'active_prefixes': ['dashboard'] }, # ... additional entries as needed ]
Some of these are self explanatory, but here are some details on each of these properties:
urls.py
.<project_id>
” and “/myapp/new-project”. Then you would set active_prefixes to ["projects", "new-project"]
. These strings can also be regular expressions.Edit INSTALLED_APPS in settings.py:
INSTALLED_APPS = [ # ... 'django_airavata.apps.myapp.apps.MyAppConfig' ]
If the new app has Webpack built frontend, then add the following configuration to WEBPACK_LOADER in settings.py:
... 'MYAPP': { 'BUNDLE_DIR_NAME': 'django_airavata_myapp/dist/', 'STATS_FILE': os.path.join( BASE_DIR, 'django_airavata', 'apps', 'myapp', 'static', 'django_airavata_myapp', 'dist', 'webpack-stats.json'), 'TIMEOUT': 60, }, ...
Edit django_airavata/urls.py
and add the app's urls config:
urlpatterns = [ re_path(r'^djadmin/', admin.site.urls), re_path(r'^admin/', include('django_airavata.apps.admin.urls')), re_path(r'^auth/', include('django_airavata.apps.auth.urls')), re_path(r'^workspace/', include('django_airavata.apps.workspace.urls')), re_path(r'^api/', include('django_airavata.apps.api.urls')), re_path(r'^groups/', include('django_airavata.apps.groups.urls')), re_path(r'^dataparsers/', include('django_airavata.apps.dataparsers.urls')), # ... Add the app urls here re_path(r'^myapp/', include('django_airavata.apps.myapp.urls')), # ... path('sdk/', include('airavata_django_portal_sdk.urls')), re_path(r'^home$', views.home, name='home'), re_path(r'^cms/', include(wagtailadmin_urls)), re_path(r'^documents/', include(wagtaildocs_urls)), # For testing, developing error pages re_path(r'^400/', views.error400), re_path(r'^403/', views.error403), re_path(r'^404/', views.error404), re_path(r'^500/', views.error500), ]
Let's add a starter home page and urls.py config for this app. Create a urls.py
file in myapp/
:
from django.urls import path from . import views app_name = 'django_airavata_myapp' urlpatterns = [ path('home/', views.home, name='home'), ]
Add a view function called home
in views.py:
from django.shortcuts import render def home(request): return render(request, 'django_airavata_myapp/home.html')
Create a templates directory called in myapp
called templates/django_airavata_myapp/
.
Then create a base template in that directory called base.html
. We'll create this file assuming that it will load webpack bundles generated by vue-cli:
{% extends 'base.html' %} {% load static %} {% load render_bundle from webpack_loader %} {% block css %} {% render_bundle 'chunk-vendors' 'css' 'MYAPP' %} {% comment %}BUT NOTE: if you only have one entry point you won't have a 'chunk-common' bundle so you may need to comment out the next line until you have more than one entry point.{% endcomment %} {% render_bundle 'chunk-common' 'css' 'MYAPP' %} {% render_bundle bundle_name 'css' 'MYAPP' %} {% endblock %} {% block content %} <div id="{{ bundle_name }}"/> {% endblock %} {% block scripts %} {% render_bundle 'chunk-vendors' 'js' 'MYAPP' %} {% comment %}BUT NOTE: if you only have one entry point you won't have a 'chunk-common' bundle so you may need to comment out the next line until you have more than one entry point.{% endcomment %} {% render_bundle 'chunk-common' 'js' 'MYAPP' %} {% render_bundle bundle_name 'js' 'MYAPP' %} {% endblock %}
Now, create a home.html
template:
{% extends './base.html' %} {% load static %} {% block css %} {% comment %}This isn't a Vue.js app, so just turn off loading CSS.{% endcomment %} {% endblock %} {% block content %} <h1>Hello World!</h1> {% endblock content %} {% block scripts %} {% comment %}This isn't a Vue.js app, so just turn off loading JavaScript.{% endcomment %} {% endblock %}
Now if you log into the Django portal you should see “My App” in the menu at the top and clicking on it should display the home page of this app.
Now we'll add JavaScript build config to the app using Vue.js, npm and webpack.
!!! note
These instructions are likely to become outdated. You can also run `vue create` to create these configuration files. Also see the existing Django apps, like *workspace*, and compare how they are set up.
Add a package.json file to the app's directory (i.e., django_airavata/apps/myapp):
{ "name": "django-airavata-myapp-views", "description": "A Vue.js project", "version": "1.0.0", "author": "Apache Airavata <dev@airavata.apache.org>", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint", "format": "prettier --write ." }, "dependencies": { "bootstrap": "^4.3.1", "bootstrap-vue": "^2.21.2", "core-js": "^3.8.3", "django-airavata-api": "link:../api", "django-airavata-common-ui": "link:../../static/common", "vue": "^2.5.21" }, "devDependencies": { "@babel/core": "^7.12.16", "@babel/eslint-parser": "^7.12.16", "@vue/cli-plugin-babel": "~5.0.8", "@vue/cli-plugin-eslint": "~5.0.8", "@vue/cli-service": "~5.0.8", "eslint": "^7.32.0", "eslint-plugin-vue": "^8.0.3", "prettier": "^2.1.2", "vue-template-compiler": "^2.5.22", "webpack-bundle-tracker": "^0.4.2-beta" }, "eslintConfig": { "root": true, "env": { "node": true }, "extends": ["plugin:vue/essential", "eslint:recommended"], "rules": {}, "parserOptions": { "parser": "@babel/eslint-parser", "requireConfigFile": false } }, "postcss": { "plugins": { "autoprefixer": {} } }, "browserslist": ["> 1%", "last 2 versions", "not dead"] }
Run yarn
which will install these dependencies and also create a yarn.lock
file with locked dependency versions.
Add a babel.config.js
to this directory too:
module.exports = { presets: ["@vue/cli-plugin-babel/preset"], };
Now add a vue.config.js
file too:
const BundleTracker = require("webpack-bundle-tracker"); const path = require("path"); module.exports = { publicPath: process.env.NODE_ENV === "development" ? "http://localhost:9000/static/django_airavata_myapp/dist/" : "/static/django_airavata_myapp/dist/", outputDir: "./static/django_airavata_myapp/dist", pages: { home: "./static/django_airavata_myapp/js/entry-home", // additional entry points go here ... }, configureWebpack: { plugins: [ new BundleTracker({ filename: "webpack-stats.json", path: "./static/django_airavata_myapp/dist/", }), ], }, devServer: { port: 9000, headers: { "Access-Control-Allow-Origin": "*", }, hot: true, }, };
You‘ll customize pages by modifying and/or adding additional entry points and you’ll need to modify publicPath and outputDir and the BundleTracker config to correspond to your folder structure.
Now create a static folder for holding javascript code. For this example we would create static/django_airavata_myapp/js
. In this folder you can put the entry points, for example entry-home.js
.
For each entry point you‘ll create a template, extending your app’s base.html
and including that entry points generated css and js file. See Adding an entry point for further instructions.
For a complete example, see the workspace app.
In the root of the project is a master build script, build_js.sh
, that generates a production build of all of the JS frontend code in the project. Add a line in there for your Django app, like so:
... (cd $SCRIPT_DIR/django_airavata/apps/myapp && yarn && yarn run build) || exit 1
You can test it by running ./build_js.sh
in the root folder.