# Package structure

> A UI extension is a Python package on the appliance

---

Site [llms.txt](/llms.txt)

---

The package layout tells Cloud Management Platform (CMP) where to find your views, templates, and static files.

Packages live in `/var/opt/cloudbolt/proserv/xui/`, one folder per extension, named after the extension's **Name**. A single package can register several extensions at different points in the UI: a dashboard card, a report, and a detail view tab can all come from the same folder.

## Files in a package

| Path | What it holds |
| --- | --- |
| `__init__.py` | Required by Python, and where you set `ALLOWED_XUI_EXTENSIONS` to change which file types the package exports. |
| `views.py` | Django views. Each is registered as an extension by the decorator above it. |
| `urls.py` | Optional URLs for buttons, links, and dialogs that call back into your views. |
| `templates/` | Django templates your views render. Template paths start with the package folder name. |
| `static/` | CSS, JavaScript, and images that ship with the extension. |

Creating a package from **Admin** > **Manage UI Extensions** writes `__init__.py`, `views.py`, and a stub function for each selected extension type. Add the rest as needed.

## Custom URLs

An extension with buttons, links, or a dialog that has to reach a custom view needs a `urls.py`. Declare the patterns in a variable called `xui_urlpatterns`, not the `urlpatterns` a Django app would use.

```python
from django.urls import re_path

from . import views

xui_urlpatterns = [
    re_path(
        r"^a-sample-url-with-obj-id/(?P<obj_id>\d+)/$",
        views.sample_method_1,
        name="sample_method_1",
    ),
    re_path(
        r"^some-other-sample-url/$",
        views.sample_method_2,
        name="sample_method_2",
    ),
]
```

CMP appends these patterns to the site's root URL configuration, so reference them in a template by their root-relative path rather than with the `url` template tag.

```html
{# sample template #}

<a href="/a-sample-url-with-obj-id/{{ obj.id }}/">Call method 1</a>

<a href="/some-other-sample-url/">Call method 2</a>
```

If `urls.py` cannot be imported, CMP logs a warning and continues. Check the application log if a link that should reach your view returns a 404.

## Package and install an extension

Extensions travel as zip files. Download one using the download icon on its row on the Extensions Management page, or build the zip yourself from the package folder.

An export includes any `README` plus these file types: `.py`, `.html`, `.png`, `.svg`, `.jpg`, `.js`, `.css`, `.json`, `.yaml`, `.yml`, `.rst`, `.md`, and `.xml`. To include other file types, define them in `__init__.py`:

```python
# Replace the default list of exported file types.
ALLOWED_XUI_EXTENSIONS = [".py", ".html", ".png"]
```

To install a package, select **Upload** on the Extensions Management page. To start a new one, select **Add** > **Create a package**.

A package copied straight onto the filesystem is registered when someone opens the Extensions Management page, or when you select **Sync Static Assets**.

## Related

- [UI extensions](/docs/cmp/developer-resources/ui-extensions/): Creating, importing, and troubleshooting an extension.
- [UI elements that support extensions](/docs/cmp/developer-resources/ui-extensions/supported-elements/): The decorator and arguments for each type.
- [Front-end assets and tools](/docs/cmp/developer-resources/ui-extensions/front-end-assets-and-tools/): Available JavaScript and CSS libraries for your templates.
