.. _migrate_3_to_4: ********************************* Migrating Apps from Tethys 3 to 4 ********************************* **Last Updated:** December 2022 This guide describes how to migrate Tethys 3 apps to work in Tethys 4. There are several "breaking" changes that were introduced in Tethys 4 that may cause apps developed in Tethys 3 to not load or function properly. Use the tips below to help you make the changes necessary for the app to function properly in Tethys 4. .. note:: To migrate an app developed for Tethys 2 to Tethys 4, you will need to first complete the steps found in the :ref:`migrate_2_to_3` guide. Index Controller ================ The ``index`` property of the :term:`app class` is used to tell Tethys which controller should be used for the home page of the app. In Tethys 4, the app namespace portion (the part before the ``:``) should be dropped. For example, a Tethys app with an ``index`` property looking like this: .. code-block:: python :emphasize-lines: 2 class MyFirstApp(TethysAppBase): index = "my_first_app:home" should be changed to this: .. code-block:: python :emphasize-lines: 2 class MyFirstApp(TethysAppBase): index = "home" Controller Decorators ===================== The ``url_maps()`` method is being deprecated in favor of the simpler ``controller`` decorator method introduced in Tethys 4. The ``url_maps`` method is temporarily available in Tethys 4 to allow for easier app migration, but **support for the ``url_maps`` method will be dropped in Tethys 4.1.0**. It is strongly recommended to migrate apps to use the new ``controller`` decorator approach and remove the ``url_maps()`` method from the :file:`app.py`. If you still wish to declare ``UrlMaps`` in the :file:`app.py`, use the new ``register_url_maps()`` method and then remove the ``url_maps()`` method (see: :ref:`register-url-maps-method`). The console will display warnings for apps still using the ``url_maps`` method in Tethys 4 to encourage migration to one of the new methods described above as soon as possible. **Don't wait for Tethys 4.1 to migrate**. Use the following tips to help you migrate: 1. Review the :ref:`routing_api` documentation to become familiar with the ``controller`` decorator. 2. If your app has a lot of controllers, use the ``url_maps()`` in :file:`app.py` to make a list of them. There should be one controller function or class for each ``UrlMap`` listed. 3. Add the ``controller`` decorator to each controller function or class in your app. 4. If the default URL or name generated by the ``controller`` decorator don't match what is set in the ``UrlMap``, override it by setting the ``url`` and ``name`` arguments of the controller decorator. 5. If your controller uses any other decorators, remove them and use the appropriate arguments in the ``controller`` decorator instead. 6. Remove the ``url_maps()`` method from the :file:`app.py`. .. note:: Tethys 4 also introduces the ``consumer`` and ``handler`` decorators that function equivalently for consumers and handler functions. See the :ref:`routing_api` documentation for more details. Search Path ----------- Tethys will only search for the ``controller``, ``consumer``, and ``handler`` decorators in modules named ``controllers.py`` or ``consumers.py`` or any module located in packages named ``controllers`` and ``consumers``. If your app has controllers located in modules with different names than these defaults, the **recommended migration** is to move the modules into a package named either ``controllers`` or ``consumers``. However, you may also use the ``controller_modules`` property of the :term:`app class` to define addtiional search locations. For example: .. code-block:: python class MyFirstApp(TethysAppBase): ... controller_modules = [ 'custom_controllers', # For a module named custom_controller.py in the same directory as app.py 'rest', # For a package named "rest" in the same directory as app.py containing modules with controllers ] Workspaces ========== It is recommended that you use the ``app_workspace`` and ``user_workspace`` arguments of the ``controller`` decorator to acquire workspaces in Tethys 4. For example, the following controllers: .. code-block:: python from tethys_sdk.workspaces import app_workspace from .app import App def controller_a(request): """Gets user workspace from old app class method.""" user_workspace = App.get_user_workspace(request.user) uw_path = user_workspace.path ... @app_workspace def controller_b(request, app_workspace): """Gets app workspace from the app_workspace decorator.""" aw_path = app_workspace.path ... should be refactored to use the ``controller`` decorator as follows: .. code-block:: python from tethys_sdk.routing import controller @controller(user_workspace=True) def controller_a(request, user_workspace): """Gets user workspace from the controller decorator.""" uw_path = user_workspace.path ... @controller(app_workspace=True) def controller_b(request, app_workspace): """Gets app workspace from the controller decorator.""" aw_path = app_workspace.path ... .. note:: In rare cases when the ``controller`` decorator cannot be used to acquire workspaces, you may use the ``get_app_workspace()`` and ``get_user_workspace()`` methods of the app class. These methods are no longer deprecated. However, they will raise an exception if the quotas feature is enabled and the user or app workspace is out of storage space. The ``controller`` decorator automatically handles these exceptions, but when using the ``get_app_workspace()`` and ``get_user_workspace()`` directly, you will need to handle those exceptions. Templates ========= In Tethys 4, the ``staticfiles`` template library needs to be changed to ``static``: For example, the following ``load`` statement: .. code-block:: html+django {% load staticfiles %} needs to be changed to this: .. code-block:: html+django {% load static %} Theme and Styles ================ The frontend CSS framework, Bootstrap, was upgraded from version 3 to version 5 in Tethys Platform 4. As a result, any Boostrap components that are used in templates will need to be updated to use the `Bootstrap 5 `_ syntax so they function and look as expected. This section describes how to update the most common Bootstrap components that are used in Tethys Apps. .. note:: The app base templates and Template Gizmos have all been updated to use Bootstrap 5. You should only need to upgrade Bootstrap code that is contained in your app. The Gizmos that are used by your app will be automatically upgraded. Bootstrap Icons --------------- The glyphicons that were included in Bootstrap 3 were moved to a separate library called `Bootstrap Icons `_. The Bootstrap Icons use a different syntax than glyphicons, so any glyphicons that are used in your app will not show up in Tethys Platform 4. However, Tethys Platform 4 includes the Boostrap Icons library in the base template for apps, so the only change that you should need to make is to update the icon to an equivalent Bootstrap Icon: .. code-block:: html The Bootstrap Icons library has many more icons than the Bootstrap 3 glyphicon library, however the names of many icons have changed. For example ``glyphicon-pencil`` featured a *filled* pencil icon, but ``bi-pencil`` is an *outlined* pencil icon. To use the equivalent Bootstrap Icon, you will need to use the ``bi-pencil-fill`` icon. Fortunately, the `Bootstrap Icons `_ website has an excellent search capability that makes it easy to find equivalent icons. For example, if your app had the following glyphicons: .. code-block:: html you could update them to use the following equivalent Bootstrap Icons: .. code-block:: html App Navigation -------------- The navigation items that are used in the ``app_navigation_items`` block of your templates (usually in the :file:`base.html`) need to have slight changes made to work properly. To update the navigation elements do the following: 1. Add a ``nav-item`` class on each ``
  • `` element. 2. Add a class ``nav-link`` on each ```` element. 3. Move the ``active`` class (if applicable) from the ``
  • `` element to the ```` element. For example, an old ``app_navigation_items`` block like this: .. code-block:: html+django {% block app_navigation_items %}
  • App Navigation
  • Home
  • Jobs
  • Get Started
  • {% endblock %} should be changed to this: .. code-block:: html+django {% block app_navigation_items %} {% endblock %} .. _app_migration_bs5_data_attrs: Data Attributes --------------- All Boostrap related data attributes on HTML elements now include a ``bs`` namespace. For example, ``data-target`` needs to be changed to ``data-bs-target``. Use the following tips to help you migrate data attributes appropriately: 1. Perform a project-wide search on your app source code for ``data-`` to find instances of data attributes. 2. Review the tips below for Tooltips, Dropdowns, and Modals. 3. Review the `Bootstrap 5 documentation `_ for details about changes to other components that your app uses that are not listed below. Buttons ------- The ``btn-default`` class no longer exists in Bootstrap 5. Change it to ``btn-outline-secondary`` for a similar looking button. Alternatively, choose from several new styles of buttons that can be found here: `Boostrap Buttons `_. Tooltips -------- Bootstrap Tooltip components have the following data attributes that need to be updated: * ``data-toggle``: ``data-bs-toggle`` * ``data-placement``: ``data-bs-placement`` For example, this button with an old-style tooltip: .. code-block:: html :emphasize-lines: 1 needs to be updated to this: .. code-block:: html :emphasize-lines: 1 Dropdowns --------- Bootstrap Dropdown components have the following data attributes that need to be updated: * ``data-toggle``: ``data-bs-toggle`` In addition, the `` element with class `carot` should be removed. For example, this old-style dropdown: .. code-block:: html :emphasize-lines: 2,4 needs to be updated to this: .. code-block:: html :emphasize-lines: 2 Modals ------ Bootstrap Modal components have the following data attributes that need to be updated: * ``data-dismiss``: ``data-bs-dismiss`` * ``data-toggle``: ``data-bs-toggle`` * ``data-target``: ``data-bs-target`` In addition the class of the close button should be changed from ``close`` to ``btn-close`` and the ``×`` should be removed. The modal title and close button also need to be reordered (title first, button second). For example, the following old-style modal: .. code-block:: html :emphasize-lines: 2,11,12,18 needs to be updated to this: .. code-block:: html :emphasize-lines: 2,11,12,18 Hidden Class ------------ The ``hidden`` class was changed to ``d-none`` Bootstrap 5 (short for display none). Replace all instances of ``hidden`` with ``d-none``. Be sure to check for use in your JavaScript as this class is often used to hide elements dynamically. References in Gizmos -------------------- Although Gizmos have been updated to use Bootstrap 5, some arguments passed to them may include Bootstrap 3 values. For example, the ``Button`` and ``TextInput`` Gizmos have arguments that accept the names of icons to be displayed on them that need to be updated to Boostrap Icons values. Other arguments to check are ``attributes``, ``classes``, and ``style`` that may have old Bootstrap 3 values that need to be updated to use Bootstrap 5 values. Use the following tips to help you migrate: 1. Do a project-wide search for ``"glphyicon"`` and update any icon arguments for Gizmos to the name of equivalent Bootstrap Icons (without the ``bi``). 2. Check for old Bootstrap data attributes in the ``attributes`` arguments of Gizmos (see: :ref:`app_migration_bs5_data_attrs`). 3. Check for old Bootstrap classes in the ``classes`` arguments of Gizmos (e.g. ``btn-default``). 4. Check for old Bootstrap values in the ``style`` arguments of some Gizmos (e.g.: ``default``). For example, to update this Button Gizmo to have the equivalent style and icon: .. code-block:: python :emphasize-lines: 3 add_button = Button( display_text='Add', icon='glyphicon glyphicon-plus', style='success', ) change the value of ``icon`` (without the ``bi`` portion) of the Bootstrap Icon: .. code-block:: python :emphasize-lines: 3 add_button = Button( display_text='Add', icon='plus-circle-fill', style='success', ) Gizmos ====== Static Dependencies ------------------- Most of the static dependencies of Gizmos, the CSS and JavaScript libraries they depend on, have been updated. As a result, some funtionality may have changed. If your app interacts with Gizmos using JavaScript, you may need to make some minor changes to the code to work with the new versions. This will be enirely dependent on what functionality you use. For example, the MapView gizmo depends on the OpenLayers JavaScript library. If your app uses the ``getMap()`` JavaScript API method of the MapView Gizmo and then manipulates the map object (add layers, change map settings, etc), it is likely using the OpenLayers API to do so. If your app doesn't seem to be functioning correctly, check the developer console in your web browser for errors. .. note:: This suggestion only applies to your custom JavaScript code. The Gizmos have been updated to work with the new versions of the libraries. If you use Gizmos and don't use JavaScript to manipulate them, then this likely doesn't apply to you. MapView Gizmo ------------- The ``basemap`` argument of the ``MapView`` Gizmo needs to be specified as a list, even if only one basemap is listed. For example a ``MapView`` Gizmo specifing only ``'OpenStreetMap'`` basemap like this: .. code-block:: python :emphasize-lines: 6 map_view_options = MapView( height='500px', width='100%', layers=[...], view=view_options, basemap='OpenStreetMap', ) should be updated to this: .. code-block:: python :emphasize-lines: 6 map_view_options = MapView( height='500px', width='100%', layers=[...], view=view_options, basemap=['OpenStreetMap'], ) WebSockets ========== The URLs Tethys generates for WebSockets now begin with ``/apps/`` to be consistent with the other URLs generated by Tethys. Update any JavaScript that uses these URLs to connect to WebSockets. For example, the following code in a Tethys 3 app: .. code-block:: javascript let websocket = new WebSocket('ws://' + window.location.host + '/dam-inventory/dams/notifications/ws/'); needs to be updated to this in Tethys 4: .. code-block:: javascript let websocket = new WebSocket('ws://' + window.location.host + '/apps/dam-inventory/dams/notifications/ws/'); Schedulers ========== In Tethys 4, job :ref:`jobs_api_schedulers` should be assigned to apps using :ref:`Scheduler app settings `. If your app uses job schedulers: 1. Create a Scheduler app setting by defining the ``scheduler_settings()`` method on the app class. See :ref:`app_settings_scheduler_settings`. 2. Define a Scheduler Service and assign it to the app setting. See :ref:`Scheduler Service `. 3. Use the ``get_scheduler()`` app class method to get the Scheduler from the setting. See :ref:`app_settings_get_scheduler`. Other Resources =============== It is not possible to anticipate every migration step that will be needed. The suggestions are for the cases that will be most commonly encountered. The following resources may provide additional guidance for migrating your app(s). * Tethys is powered by Django. If your app makes uses of Django features directly, you may need to perform additional migration steps. See `Upgrading Django to a newer version `_ and `Django 3.2 Release Notes `_. * Apps are styled using Bootstrap, a frontend CSS framework. If your app uses Bootstrap components other than those described above, use these links to help you migrate: `Migrating to v4 | Bootstrap `_ and `Migrating to v5 | Bootstrap `_. .. _app_migration_older_apps: Upgrade Older Apps ================== To upgrade apps that are several versions behind, complete the app migration process for each version in order. For example, to upgrade an app developed in Tethys 2 to Tethys 4, first complete the "2 to 3" migration instructions and then complete the "3 to 4" instructions. .. toctree:: app_migration/app_migration_2_to_3