nautobot
nautobot copied to clipboard
Allow to customize CSS to differentiate multiple instances
trafficstars
As ...
Patti - Platform Admin
I want ...
to be able to customize the CSS (maybe the background-color but not just this) of a Nautobot instance
So that ...
Users (operators, developpers, ..) are able to easily distinguish the different instances (dev, test, staging, prod, ...)
I know this is done when...
- An option to input CSS is present in the admin section
- This option is overridable using settings.py (to allow copying data from an instance to another while keeping this property)
- The CSS is applied on every pages
Currently, the only option is to set a banner, but having a banner on each instance with the same blue color doesn't help to differentiate without reading the banner text.
Optional - Feature groups this request pertains to.
- [ ] Automation
- [ ] Circuits
- [ ] DCIM
- [ ] IPAM
- [ ] Misc (including Data Sources)
- [ ] Organization
- [ ] Plugins (and other Extensibility)
- [ ] Security (Secrets, etc)
- [ ] Image Management
- [X] UI/UX
- [ ] Documentation
- [ ] Other (not directly a platform feature)
Database Changes
- Add an option?
External Dependencies
None ?
This is certainly not what you'll want to implement, but here's what I'm using to add a custom style (path to the files):
patcher.py
try:
import nautobot, rest_framework
nautobot_base_path = nautobot.__path__[0]
rest_framework_base_path = rest_framework.__path__[0]
del nautobot, rest_framework
except Exception:
print('Unable to locate Nautobot or Django REST framework installation path')
raise SystemExit(1)
templates = (
(nautobot_base_path, 'core/templates/base.html'),
(nautobot_base_path, 'core/templates/admin/base.html'),
(nautobot_base_path, 'core/templates/graphene/graphiql.html'),
(rest_framework_base_path, 'templates/rest_framework/base.html'),
# Alternative: nautobot/core/templates/rest_framework/api.html
)
# Alternative: nautobot/core/templates/inc/media.html + graphql
where = '</head>'
patch = '''\
{% if settings.MY_CUSTOM_STYLE %}
<style>{{ settings.MY_CUSTOM_STYLE | safe }}</style>
{% endif %}
''' # ' {% if se..\n <styl..\n {% en..\n'
for pkg_path, template_path in templates:
with open(f'{pkg_path}/{template_path}', 'r+') as fh:
content = fh.read()
content_len = len(content)
content = content.replace(where, patch + where)
if len(content) == content_len:
print(f'Unable to patch file {fh.name!r}')
raise SystemExit(1)
fh.seek(0)
fh.truncate()
fh.write(content)
print(f'Patched {pkg_path.split("/")[-1]}{template_path!r}')
settings.py
# .navbar-default, .footer { background: linear-gradient(to right, #f8f8f8, moccasin); }
if os.getenv('MY_CUSTOM_STYLE'):
MY_CUSTOM_STYLE = os.getenv('MY_CUSTOM_STYLE').strip()
elif os.getenv('MY_CUSTOM_STYLE_FILE'):
with open(
os.getenv('MY_CUSTOM_STYLE_FILE'),
mode='r',
encoding='utf-8'
) as fh:
MY_CUSTOM_STYLE = fh.read()
Brainstorming on a feature-set and requirements here:
- Given that we'll eventually want to set a content-security-policy in nautobot that disallows unsafe-inline, we probably don't want to add a feature that directly allows for injection of JS and CSS as a string. It'd be safer to instead provide a way to easily add another .js or .css file to
inc/media.htmlandinc/javascript.html. - One way to do this would be via Apps, as any App can bundle additional static-files which we could then cleanly reference without needing to modify any content-security-policy configuration (as would be required to allow resources to load from a different domain). Different instances could install different apps (or different versions of the same app) to provide the desired differentiaion.
- A less elegant approach would be to allow the specification of arbitrary URLs to load from as a part of the settings, but that will likely run afoul of content-security-policy restrictions.