.. _customize-htmx-frontend:
=============================
Customizing the HTMx frontend
=============================
If you add more pages and endpoints you will have to write your own root
urls.py and set ROOT_URLCONF appropriately.
Adding additional apps
======================
If you have some other apps you want installed and configured, you could either
add the necessary settings to your ``localsettings.py`` or use the extra-apps
machinery. The later is especially useful during the development phase when you
haven't settled on which apps to use yet.
With extra-apps machinery
-------------------------
You make a JSON-file which is read into your settings via one of two
environment variables.
In order to add apps and settings that *extend* ``argus-server`` and this
``app`` you use the environment variable ``ARGUS_EXTRA_APPS``::
export ARGUS_EXTRA_APPS=`cat extra.json`
If you want to *override* existing apps the environment variable to use is
``ARGUS_OVERRIDING_APPS``::
export ARGUS_OVERRIDING_APPS=`cat overriding.json`
Have a look at the contents of ``argus.htmx.appconfig._app_settings`` for an
example of what you can set this way.
You can merge your urlpatterns with the apps' urlpatterns via the
``argus.site.utils.get_urlpatterns`` function, see ``argus.htmx.urls`` for an
example.
.. _themes-and-styling:
Themes and styling
==================
How to choose which themes are available
----------------------------------------
This is controlled by the setting :setting:`DAISYUI_THEMES`. You need to run
``make tailwind-config tailwind`` afterwards.
How to add additional themes
----------------------------
See the `Daisy UI 5 theme generator `_
for the themes that are shipped with Argus. You can also generate new themes
there. To add a pre-configured theme just add the name to the
:setting:`DAISYUI_THEMES` setting and run ``make tailwind-config tailwind`` as usual.
If generating a new theme:
1. Make sure the browser is in light mode if making a light theme, or dark mode
if making a dark theme.
2. Choose a name that is pure ASCII, and don't reuse any of the names that
come pre-configured. Save the generated CSS to a file.
The ``argus`` theme is included in the file ``argus/htmx/tailwindtheme/themes/argus.css``. The format is::
@plugin "daisyui/theme" {
name: "argus";
color-scheme: "light";
--color-primary: #006d91;
--color-primary-content: #d1e1e9;
--color-secondary: #f3b61f;
--color-secondary-content: #140c00;
--color-accent: #c84700;
--color-accent-content: #f8dbd1;
--color-neutral: #006d91;
--color-neutral-content: #d1e1e9;
--color-base-100: #edfaff;
--color-base-200: #ced9de;
--color-base-300: #b0babd;
--color-base-content: #141516;
--color-info: #0073e5;
--color-info-content: #000512;
--color-success: #008700;
--color-success-content: #d3e7d1;
--color-warning: #ee4900;
--color-warning-content: #140200;
--color-error: #e5545a;
--color-error-content: #120203;
/* border radius */
--radius-selector: 2rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
/* base sizes */
--size-selector: 0.25rem;
--size-field: 0.25rem;
/* border size */
--border: 1px;
/* effects */
--depth: 1;
--noise: 0;
}
The lines starting with ``--`` are css-variables.
There are two different methods to install generated themes:
1. Via :setting:`DAISYUI_THEMES`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of adding the name of a theme to the :setting:`DAISYUI_THEMES` setting
you can add an entire theme instead. Given the example theme above, it needs to
be converted to Python like so::
DAISYUI_THEMES = [
"light",
"dark",
{
"argus": {
"name": "argus",
"color-scheme": "light",
"--color-primary": "#006d91",
"--color-primary-content": "#d1e1e9",
"--color-secondary": "#f3b61f",
"--color-secondary-content": "#140c00",
"--color-accent": "#c84700",
"--color-accent-content": "#f8dbd1",
"--color-neutral": "#006d91",
"--color-neutral-content": "#d1e1e9",
"--color-base-100": "#edfaff",
"--color-base-200": "#ced9de",
"--color-base-300": "#b0babd",
"--color-base-content": "#141516",
"--color-info": "#0073e5",
"--color-info-content": "#000512",
"--color-success": "#008700",
"--color-success-content": "#d3e7d1",
"--color-warning": "#ee4900",
"--color-warning-content": "#140200",
"--color-error": "#e5545a",
"--color-error-content": "#120203",
"--radius-selector": "2rem",
"--radius-field": "0.25rem",
"--radius-box": "0.5rem",
"--size-selector": "0.25rem",
"--size-field": "0.25rem",
"--border": "1px",
"--depth": "1",
"--noise": "0",
},
},
]
Then run ``make tailwind-config tailwind`` as usual.
2. Via an app and css snippet
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a Django app which has a ``themes`` directory, see
``argus.htmx.apps.HtmxFrontendConfig.tailwind_css_files`` for something to
copy.
In the themes-directory, make a new file with the theme you generated before.
We recommend naming the file ``theme-THEMENAME.css``, where THEMENAME is the
name you chose when generating the theme.
Add the app to :setting:`INSTALLED_APPS`, the name to
:setting:`DAISYUI_THEMES`, and finish with ``make tailwind-config tailwind``
as usual.
How to customize severity colors
--------------------------------
The incident severity column uses color-coded badges. The default colors are
defined in ``argus/htmx/tailwindtheme/snippets/11-extensions.css``::
@theme {
--color-severity-primary-1: oklch(0.74 0.19 28);
--color-severity-primary-2: oklch(0.74 0.18 55);
--color-severity-primary-3: oklch(0.88 0.17 93);
--color-severity-primary-4: oklch(0.74 0.15 170);
--color-severity-primary-5: oklch(0.73 0.14 245);
--color-severity-secondary-1: #1a1a1a;
--color-severity-secondary-2: #1a1a1a;
--color-severity-secondary-3: #1a1a1a;
--color-severity-secondary-4: #1a1a1a;
--color-severity-secondary-5: #1a1a1a;
}
The ``severity-primary`` colors are used for background and border, while
``severity-secondary`` colors are used for text.
To override these colors, add the variables to your custom theme definition.
For example, in a theme CSS file or via :setting:`DAISYUI_THEMES`::
@plugin "daisyui/theme" {
name: "mytheme";
color-scheme: "dark";
/* ... other theme colors ... */
--color-severity-primary-1: #dc2626;
--color-severity-secondary-1: #fef2f2;
/* ... etc ... */
}
How to customize the look without switching themes
--------------------------------------------------
Tailwind v4 uses CSS-based configuration via ``@theme`` blocks. To extend or
override Tailwind's default theme values, create a CSS file in your app's
``themes`` directory (see "Via an app and css snippet" above for setup).
For example, to add custom border radius values::
/* myapp/tailwindtheme/themes/override.css */
@theme {
--radius-4xl: 2rem;
}
Or to override default values::
@theme {
--default-border-width: 1px;
}
After adding your theme overrides, run ``make tailwind-config tailwind`` as
usual.
Some links that may be relevant for customization:
* `daisyUI themes`_
* `list of daisyUI color names`_
* `Tailwind CSS theme customization`_
Other customization options:
* Override the default main stylesheet path by setting
``ARGUS_STYLESHEET_PATH`` in the environment. The path is under
``STATIC_URL``. This depends on the context processor
``argus.htmx.context_processors.path_to_stylesheet``.
* Include additional styles/stylesheets using the ``head`` block in your templates.
Incident table column customization
===================================
The :setting:`INCIDENT_TABLE_COLUMN_LAYOUTS` setting controls which columns are
shown in the incident table. This setting takes a dictionary where the key is
the name of a layout and the value is a list of ``str`` or
``argus.htmx.incidents.customization.IncidentTableColumn`` instances. when
given a ``str``, this key must be available in the
``argus.htmx.incidents.customization.BUILTIN_COLUMNS`` dictionary. For
example::
from argus.htmx.incident.columns import BUILTIN_COLUMNS, IncidentTableColumn
INCIDENT_TABLE_COLUMN_LAYOUTS = {
"default": [
"id",
"start_time",
BUILTIN_COLUMNS["description"], # equivalent to just "description"
IncidentTableColumn( # a new column definition
name="name",
label="Custom",
cell_template="/path/to/template.html", # contents of cell
),
]
}
The settings :setting:`INCIDENT_TABLE_COLUMNS` took a single list and is
deprecated. If it exists it is interpreted as a layout named "default".
.. py:class:: IncidentTableColumn
.. py:attribute:: name
:type: str
The identifier for the column
.. py:attribute:: label
:type: str
The column header, put inside ``
| ``
.. py:attribute:: cell_template
:type: str
Template to use when rendering a cell for this column.
For the contents of a cell, put inside `` | ``
.. py:attribute:: cell_wrapper_template
:type: str
:value: htmx/incident/_incident_table_cell_wrapper_default.html
A template that by default includes the ``cell_template`` and wraps it in
a ````-tag. This makes it possible to add attributes to the
`` | ``-tag or skip including the ``cell_template`` altogether.
Deprecated: see ``detail_link``
Replacing the default with
``htmx/incident/_incident_table_cell_wrapper_link_to_details.html`` will
result in the ``cell_template`` being wrapped in a link (````) to the
details page.
.. py:attribute::detail_link
:type: bool
:value: False
Setting ``detail_link`` to ``True`` will wrap the contents of the cell
with a link (````) to the details page.
.. py:attribute:: column_classes
:type: str
:value: ""
Additional classes to set on `` | ``, handy for controlling width.
.. py:attribute:: context
:type: Optional[dict]
:value: None
Additional context to pass to the rendering cell.
.. py:attribute:: filter_field
:type: Optional[str]
When given, this column is considered filterable and a filter input is
attached to the column header that can provide a query param with
``filter_field`` as the key. The key must match a text input form field
that is recognized by ``incident_list_filter()``.
Adds a pop-up-able free text search field in the `` | ``.
.. py:attribute:: header_template
:type: Optional[str]
:value: None
A template overriding the default `` | `` for the column.
For inbuilt support for other types of columns see the
:ref:`HTMX HowTos`.
.. _django-htmx: https://github.com/adamchainz/django-htmx
.. _argus-server: https://github.com/Uninett/Argus
.. _documentation for django-htmx: https://django-htmx.readthedocs.io/en/latest/
.. _daisyUI themes: https://daisyui.com/docs/themes/
.. _list of daisyUI color names: https://daisyui.com/docs/colors/#-2
.. _tailwind-cli-extra: https://github.com/dobicinaitis/tailwind-cli-extra
.. _Tailwind CSS theme customization: https://tailwindcss.com/docs/theme
Custom widget
=============
Argus supports showing an extra widget next to the menubar in the incidents listing. This box can
take the width of 1/3 of the window. You can add the widget by creating a context processor that
injects an ``incidents_extra_widget`` variable that points to an html template::
def extra_widget(request):
return {
"incidents_extra_widget": "path/to/_extra_widget.html",
}
*note* Don't forget to include the context processor in your settings
You could then create ``path/to/_extra_widget.html`` as following::
My custom widget
Toast messages
==============
``argus_htmx`` uses the `Django Messages`_ framework to dynamically display notifications toast
messages to the user. Some of these messages stay on screen until the user refreshes, while others
automatically close (disappear) after a certain time. This can be customized by modifying or
overriding the ``NOTIFICATION_TOAST_AUTOCLOSE_SECONDS`` setting. The default value for this setting
is::
NOTIFICATION_TOAST_AUTOCLOSE_SECONDS = {
"success": 10,
"autoclose": 10,
}
This means that any message that has either the `tag`_ ``"success"`` or ``"autoclose"`` will
automatically close after 10 seconds. You can update this dictionary with existing tags such as
``"warning"`` or ``"error"``, or make up your own.
.. _Django Messages: https://docs.djangoproject.com/en/5.1/ref/contrib/messages
.. _tag: https://docs.djangoproject.com/en/5.1/ref/contrib/messages/#message-tags
|