mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-04 13:30:04 +01:00
Compare commits
1 Commits
21566-user
...
21518-cf-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50d1d0a023 |
@@ -2,7 +2,6 @@ import re
|
||||
import typing
|
||||
from collections import OrderedDict
|
||||
|
||||
from drf_spectacular.contrib.django_filters import DjangoFilterExtension
|
||||
from drf_spectacular.extensions import OpenApiSerializerExtension, OpenApiSerializerFieldExtension, _SchemaType
|
||||
from drf_spectacular.openapi import AutoSchema
|
||||
from drf_spectacular.plumbing import (
|
||||
@@ -10,7 +9,6 @@ from drf_spectacular.plumbing import (
|
||||
build_choice_field,
|
||||
build_media_type_object,
|
||||
build_object_type,
|
||||
follow_field_source,
|
||||
get_doc,
|
||||
)
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
@@ -25,29 +23,6 @@ BULK_ACTIONS = ("bulk_destroy", "bulk_partial_update", "bulk_update")
|
||||
WRITABLE_ACTIONS = ("PATCH", "POST", "PUT")
|
||||
|
||||
|
||||
class NetBoxDjangoFilterExtension(DjangoFilterExtension):
|
||||
"""
|
||||
Overrides drf-spectacular's DjangoFilterExtension to fix a regression in v0.29.0 where
|
||||
_get_model_field() incorrectly double-appends to_field_name when field_name already ends
|
||||
with that value (e.g. field_name='tags__slug', to_field_name='slug' produces the invalid
|
||||
path ['tags', 'slug', 'slug']). This caused hundreds of spurious warnings during schema
|
||||
generation for filters such as TagFilter, TenancyFilterSet.tenant, and OwnerFilterMixin.owner.
|
||||
|
||||
See: https://github.com/netbox-community/netbox/issues/20787
|
||||
https://github.com/tfranzel/drf-spectacular/issues/1475
|
||||
"""
|
||||
priority = 1
|
||||
|
||||
def _get_model_field(self, filter_field, model):
|
||||
if not filter_field.field_name:
|
||||
return None
|
||||
path = filter_field.field_name.split('__')
|
||||
to_field_name = filter_field.extra.get('to_field_name')
|
||||
if to_field_name is not None and path[-1] != to_field_name:
|
||||
path.append(to_field_name)
|
||||
return follow_field_source(model, path, emit_warnings=False)
|
||||
|
||||
|
||||
class FixTimeZoneSerializerField(OpenApiSerializerFieldExtension):
|
||||
target_class = 'timezone_field.rest_framework.TimeZoneSerializerField'
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{% load i18n %}
|
||||
<span>
|
||||
<a href="{{ value.get_absolute_url }}"{% if name %} id="attr_{{ name }}"{% endif %}>{{ value.address.ip }}</a>
|
||||
{% if value.nat_inside %}
|
||||
({% trans "NAT for" %} <a href="{{ value.nat_inside.get_absolute_url }}">{{ value.nat_inside.address.ip }}</a>)
|
||||
{% elif value.nat_outside.exists %}
|
||||
({% trans "NAT" %}: {% for nat in value.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
|
||||
{% endif %}
|
||||
</span>
|
||||
<a href="{{ value.get_absolute_url }}"{% if name %} id="attr_{{ name }}"{% endif %}>{{ value.address.ip }}</a>
|
||||
{% if value.nat_inside %}
|
||||
({% trans "NAT for" %} <a href="{{ value.nat_inside.get_absolute_url }}">{{ value.nat_inside.address.ip }}</a>)
|
||||
{% elif value.nat_outside.exists %}
|
||||
({% trans "NAT" %}: {% for nat in value.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
|
||||
{% endif %}
|
||||
<a class="btn btn-sm btn-primary copy-content" data-clipboard-target="#attr_{{ name }}" title="{% trans "Copy to clipboard" %}">
|
||||
<i class="mdi mdi-content-copy"></i>
|
||||
</a>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{% load helpers %}{{ object.get_full_name|placeholder }}
|
||||
@@ -1 +1,60 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
{% load helpers %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block title %}{% trans "Group" %} {{ object.name }}{% endblock %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Group" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Users" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for user in object.users.all %}
|
||||
<a href="{% url 'users:user' pk=user.pk %}" class="list-group-item list-group-item-action">{{ user }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Assigned Permissions" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for perm in object.object_permissions.all %}
|
||||
<a href="{% url 'users:objectpermission' pk=perm.pk %}" class="list-group-item list-group-item-action">{{ perm }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Owner Membership" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for owner in object.owners.all %}
|
||||
<a href="{% url 'users:owner' pk=owner.pk %}" class="list-group-item list-group-item-action">{{ owner }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1 +1,93 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
{% load helpers %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block title %}{% trans "Permission" %} {{ object.name }}{% endblock %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Permission" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Enabled" %}</th>
|
||||
<td>{% checkmark object.enabled %}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Actions" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "View" %}</th>
|
||||
<td>{% checkmark object.can_view %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Add" %}</th>
|
||||
<td>{% checkmark object.can_add %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Change" %}</th>
|
||||
<td>{% checkmark object.can_change %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Delete" %}</th>
|
||||
<td>{% checkmark object.can_delete %}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Constraints" %}</h2>
|
||||
<div class="card-body">
|
||||
{% if object.constraints %}
|
||||
<pre>{{ object.constraints|json }}</pre>
|
||||
{% else %}
|
||||
<span class="text-muted">None</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Object Types" %}</h2>
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for user in object.object_types.all %}
|
||||
<li class="list-group-item">{{ user }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Assigned Users" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for user in object.users.all %}
|
||||
<a href="{% url 'users:user' pk=user.pk %}" class="list-group-item list-group-item-action">{{ user }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Assigned Groups" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for group in object.groups.all %}
|
||||
<a href="{% url 'users:group' pk=group.pk %}" class="list-group-item list-group-item-action">{{ group }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1 +1,60 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ block.super }}
|
||||
{% if object.group %}
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'users:owner_list' %}?group_id={{ object.group_id }}">{{ object.group }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Owner" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Group" %}</th>
|
||||
<td>{{ object.group|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Groups" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for group in object.user_groups.all %}
|
||||
<a href="{% url 'users:group' pk=group.pk %}" class="list-group-item list-group-item-action">{{ group }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Users" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for user in object.users.all %}
|
||||
<a href="{% url 'users:user' pk=user.pk %}" class="list-group-item list-group-item-action">{{ user }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/panels/related_objects.html' with filter_name='owner_id' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1 +1,46 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
{% load helpers %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block extra_controls %}
|
||||
{% if perms.users.add_owner %}
|
||||
<a href="{% url 'users:owner_add' %}?group={{ object.pk }}" class="btn btn-primary">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Owner" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Group" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Members" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for owner in object.members.all %}
|
||||
<a href="{% url 'users:owner' pk=owner.pk %}" class="list-group-item list-group-item-action">{{ owner }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{% load i18n %}
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Object Types" %}</h2>
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for object_type in object.object_types.all %}
|
||||
<li class="list-group-item">{{ object_type }}</li>
|
||||
{% empty %}
|
||||
<li class="list-group-item text-muted">{% trans "None" %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1 +1,4 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Token" %} {{ object }}{% endblock %}
|
||||
|
||||
@@ -1 +1,85 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "User" %} {{ object.username }}{% endblock %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "User" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Username" %}</th>
|
||||
<td>{{ object.username }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Full Name" %}</th>
|
||||
<td>{{ object.get_full_name|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Email" %}</th>
|
||||
<td>{{ object.email|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Account Created" %}</th>
|
||||
<td>{{ object.date_joined|isodate }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Last Login" %}</th>
|
||||
<td>{{ object.last_login|isodatetime:"minutes"|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Active" %}</th>
|
||||
<td>{% checkmark object.is_active %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Superuser" %}</th>
|
||||
<td>{% checkmark object.is_superuser %}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Assigned Groups" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for group in object.groups.all %}
|
||||
<a href="{% url 'users:group' pk=group.pk %}" class="list-group-item list-group-item-action">{{ group }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Assigned Permissions" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for perm in object.object_permissions.all %}
|
||||
<a href="{% url 'users:objectpermission' pk=perm.pk %}" class="list-group-item list-group-item-action">{{ perm }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Owner Membership" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for owner in object.owners.all %}
|
||||
<a href="{% url 'users:owner' pk=owner.pk %}" class="list-group-item list-group-item-action">{{ owner }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.core.view_objectchange %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% include 'users/inc/user_activity.html' with user=object table=changelog_table %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-28 05:11+0000\n"
|
||||
"POT-Creation-Date: 2026-02-21 05:16+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -41,9 +41,9 @@ msgstr ""
|
||||
|
||||
#: netbox/circuits/choices.py:21 netbox/dcim/choices.py:20
|
||||
#: netbox/dcim/choices.py:102 netbox/dcim/choices.py:204
|
||||
#: netbox/dcim/choices.py:257 netbox/dcim/choices.py:1933
|
||||
#: netbox/dcim/choices.py:1991 netbox/dcim/choices.py:2058
|
||||
#: netbox/dcim/choices.py:2080 netbox/virtualization/choices.py:20
|
||||
#: netbox/dcim/choices.py:257 netbox/dcim/choices.py:1929
|
||||
#: netbox/dcim/choices.py:1987 netbox/dcim/choices.py:2054
|
||||
#: netbox/dcim/choices.py:2076 netbox/virtualization/choices.py:20
|
||||
#: netbox/virtualization/choices.py:46 netbox/vpn/choices.py:18
|
||||
#: netbox/vpn/choices.py:281
|
||||
msgid "Planned"
|
||||
@@ -57,8 +57,8 @@ msgstr ""
|
||||
#: netbox/core/tables/tasks.py:23 netbox/dcim/choices.py:22
|
||||
#: netbox/dcim/choices.py:103 netbox/dcim/choices.py:155
|
||||
#: netbox/dcim/choices.py:203 netbox/dcim/choices.py:256
|
||||
#: netbox/dcim/choices.py:1990 netbox/dcim/choices.py:2057
|
||||
#: netbox/dcim/choices.py:2079 netbox/extras/tables/tables.py:642
|
||||
#: netbox/dcim/choices.py:1986 netbox/dcim/choices.py:2053
|
||||
#: netbox/dcim/choices.py:2075 netbox/extras/tables/tables.py:642
|
||||
#: netbox/ipam/choices.py:31 netbox/ipam/choices.py:49
|
||||
#: netbox/ipam/choices.py:69 netbox/ipam/choices.py:154
|
||||
#: netbox/templates/extras/configcontext.html:29
|
||||
@@ -70,8 +70,8 @@ msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/circuits/choices.py:24 netbox/dcim/choices.py:202
|
||||
#: netbox/dcim/choices.py:255 netbox/dcim/choices.py:1989
|
||||
#: netbox/dcim/choices.py:2059 netbox/dcim/choices.py:2078
|
||||
#: netbox/dcim/choices.py:255 netbox/dcim/choices.py:1985
|
||||
#: netbox/dcim/choices.py:2055 netbox/dcim/choices.py:2074
|
||||
#: netbox/virtualization/choices.py:24 netbox/virtualization/choices.py:44
|
||||
msgid "Offline"
|
||||
msgstr ""
|
||||
@@ -84,7 +84,7 @@ msgstr ""
|
||||
msgid "Decommissioned"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/circuits/choices.py:90 netbox/dcim/choices.py:2002
|
||||
#: netbox/circuits/choices.py:90 netbox/dcim/choices.py:1998
|
||||
#: netbox/dcim/tables/devices.py:1208 netbox/templates/dcim/interface.html:148
|
||||
#: netbox/tenancy/choices.py:17
|
||||
msgid "Primary"
|
||||
@@ -1995,7 +1995,7 @@ msgstr ""
|
||||
#: netbox/core/choices.py:22 netbox/core/choices.py:59
|
||||
#: netbox/core/constants.py:21 netbox/core/tables/tasks.py:35
|
||||
#: netbox/dcim/choices.py:206 netbox/dcim/choices.py:259
|
||||
#: netbox/dcim/choices.py:1992 netbox/dcim/choices.py:2082
|
||||
#: netbox/dcim/choices.py:1988 netbox/dcim/choices.py:2078
|
||||
#: netbox/virtualization/choices.py:48
|
||||
msgid "Failed"
|
||||
msgstr ""
|
||||
@@ -2181,7 +2181,7 @@ msgid "User name"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/core/forms/bulk_edit.py:25 netbox/core/forms/filtersets.py:47
|
||||
#: netbox/core/tables/data.py:28 netbox/dcim/choices.py:2040
|
||||
#: netbox/core/tables/data.py:28 netbox/dcim/choices.py:2036
|
||||
#: netbox/dcim/forms/bulk_edit.py:1105 netbox/dcim/forms/bulk_edit.py:1386
|
||||
#: netbox/dcim/forms/filtersets.py:1619 netbox/dcim/forms/filtersets.py:1712
|
||||
#: netbox/dcim/tables/devices.py:581 netbox/dcim/tables/devicetypes.py:233
|
||||
@@ -2375,7 +2375,7 @@ msgstr ""
|
||||
msgid "Rack Elevations"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/core/forms/model_forms.py:160 netbox/dcim/choices.py:1911
|
||||
#: netbox/core/forms/model_forms.py:160 netbox/dcim/choices.py:1907
|
||||
#: netbox/dcim/forms/bulk_edit.py:944 netbox/dcim/forms/bulk_edit.py:1340
|
||||
#: netbox/dcim/forms/bulk_edit.py:1361 netbox/dcim/tables/racks.py:144
|
||||
#: netbox/netbox/navigation/menu.py:316 netbox/netbox/navigation/menu.py:320
|
||||
@@ -3041,8 +3041,8 @@ msgid "Staging"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:23 netbox/dcim/choices.py:208
|
||||
#: netbox/dcim/choices.py:260 netbox/dcim/choices.py:1934
|
||||
#: netbox/dcim/choices.py:2083 netbox/virtualization/choices.py:23
|
||||
#: netbox/dcim/choices.py:260 netbox/dcim/choices.py:1930
|
||||
#: netbox/dcim/choices.py:2079 netbox/virtualization/choices.py:23
|
||||
#: netbox/virtualization/choices.py:49 netbox/vpn/choices.py:282
|
||||
msgid "Decommissioning"
|
||||
msgstr ""
|
||||
@@ -3108,7 +3108,7 @@ msgstr ""
|
||||
msgid "Millimeters"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:115 netbox/dcim/choices.py:1956
|
||||
#: netbox/dcim/choices.py:115 netbox/dcim/choices.py:1952
|
||||
msgid "Inches"
|
||||
msgstr ""
|
||||
|
||||
@@ -3186,7 +3186,7 @@ msgid "Rear"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:205 netbox/dcim/choices.py:258
|
||||
#: netbox/dcim/choices.py:2081 netbox/virtualization/choices.py:47
|
||||
#: netbox/dcim/choices.py:2077 netbox/virtualization/choices.py:47
|
||||
msgid "Staged"
|
||||
msgstr ""
|
||||
|
||||
@@ -3219,7 +3219,7 @@ msgid "Top to bottom"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:235 netbox/dcim/choices.py:280
|
||||
#: netbox/dcim/choices.py:1566
|
||||
#: netbox/dcim/choices.py:1562
|
||||
msgid "Passive"
|
||||
msgstr ""
|
||||
|
||||
@@ -3248,8 +3248,8 @@ msgid "Proprietary"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:606 netbox/dcim/choices.py:853
|
||||
#: netbox/dcim/choices.py:1478 netbox/dcim/choices.py:1480
|
||||
#: netbox/dcim/choices.py:1716 netbox/dcim/choices.py:1718
|
||||
#: netbox/dcim/choices.py:1474 netbox/dcim/choices.py:1476
|
||||
#: netbox/dcim/choices.py:1712 netbox/dcim/choices.py:1714
|
||||
#: netbox/netbox/navigation/menu.py:212
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
@@ -3262,11 +3262,11 @@ msgstr ""
|
||||
msgid "Physical"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:884 netbox/dcim/choices.py:1153
|
||||
#: netbox/dcim/choices.py:884 netbox/dcim/choices.py:1151
|
||||
msgid "Virtual"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:885 netbox/dcim/choices.py:1355
|
||||
#: netbox/dcim/choices.py:885 netbox/dcim/choices.py:1351
|
||||
#: netbox/dcim/forms/bulk_edit.py:1546 netbox/dcim/forms/filtersets.py:1577
|
||||
#: netbox/dcim/forms/filtersets.py:1703 netbox/dcim/forms/model_forms.py:1125
|
||||
#: netbox/dcim/forms/model_forms.py:1589 netbox/netbox/navigation/menu.py:150
|
||||
@@ -3275,11 +3275,11 @@ msgstr ""
|
||||
msgid "Wireless"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1151
|
||||
#: netbox/dcim/choices.py:1149
|
||||
msgid "Virtual interfaces"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1154 netbox/dcim/forms/bulk_edit.py:1399
|
||||
#: netbox/dcim/choices.py:1152 netbox/dcim/forms/bulk_edit.py:1399
|
||||
#: netbox/dcim/forms/bulk_import.py:949 netbox/dcim/forms/model_forms.py:1107
|
||||
#: netbox/dcim/tables/devices.py:741 netbox/templates/dcim/interface.html:112
|
||||
#: netbox/virtualization/forms/bulk_edit.py:177
|
||||
@@ -3288,67 +3288,67 @@ msgstr ""
|
||||
msgid "Bridge"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1155
|
||||
#: netbox/dcim/choices.py:1153
|
||||
msgid "Link Aggregation Group (LAG)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1159
|
||||
#: netbox/dcim/choices.py:1157
|
||||
msgid "FastEthernet (100 Mbps)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1168
|
||||
#: netbox/dcim/choices.py:1166
|
||||
msgid "GigabitEthernet (1 Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1186
|
||||
#: netbox/dcim/choices.py:1184
|
||||
msgid "2.5/5 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1193
|
||||
#: netbox/dcim/choices.py:1191
|
||||
msgid "10 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1209
|
||||
#: netbox/dcim/choices.py:1206
|
||||
msgid "25 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1219
|
||||
#: netbox/dcim/choices.py:1216
|
||||
msgid "40 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1230
|
||||
#: netbox/dcim/choices.py:1226
|
||||
msgid "50 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1240
|
||||
#: netbox/dcim/choices.py:1236
|
||||
msgid "100 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1261
|
||||
#: netbox/dcim/choices.py:1257
|
||||
msgid "200 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1275
|
||||
#: netbox/dcim/choices.py:1271
|
||||
msgid "400 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1293
|
||||
#: netbox/dcim/choices.py:1289
|
||||
msgid "800 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1302
|
||||
#: netbox/dcim/choices.py:1298
|
||||
msgid "Pluggable transceivers"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1339
|
||||
#: netbox/dcim/choices.py:1335
|
||||
msgid "Backplane Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1371
|
||||
#: netbox/dcim/choices.py:1367
|
||||
msgid "Cellular"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1423 netbox/dcim/forms/filtersets.py:425
|
||||
#: netbox/dcim/choices.py:1419 netbox/dcim/forms/filtersets.py:425
|
||||
#: netbox/dcim/forms/filtersets.py:911 netbox/dcim/forms/filtersets.py:1112
|
||||
#: netbox/dcim/forms/filtersets.py:1910
|
||||
#: netbox/templates/dcim/inventoryitem.html:56
|
||||
@@ -3356,255 +3356,255 @@ msgstr ""
|
||||
msgid "Serial"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1438
|
||||
#: netbox/dcim/choices.py:1434
|
||||
msgid "Coaxial"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1459
|
||||
#: netbox/dcim/choices.py:1455
|
||||
msgid "Stacking"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1511
|
||||
#: netbox/dcim/choices.py:1507
|
||||
msgid "Half"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1512
|
||||
#: netbox/dcim/choices.py:1508
|
||||
msgid "Full"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1513 netbox/netbox/preferences.py:32
|
||||
#: netbox/dcim/choices.py:1509 netbox/netbox/preferences.py:32
|
||||
#: netbox/wireless/choices.py:480
|
||||
msgid "Auto"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1525
|
||||
#: netbox/dcim/choices.py:1521
|
||||
msgid "Access"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1526 netbox/ipam/tables/vlans.py:150
|
||||
#: netbox/dcim/choices.py:1522 netbox/ipam/tables/vlans.py:150
|
||||
#: netbox/ipam/tables/vlans.py:210
|
||||
#: netbox/templates/dcim/inc/interface_vlans_table.html:7
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1527
|
||||
#: netbox/dcim/choices.py:1523
|
||||
msgid "Tagged (All)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1528 netbox/templates/ipam/vlan_edit.html:26
|
||||
#: netbox/dcim/choices.py:1524 netbox/templates/ipam/vlan_edit.html:26
|
||||
msgid "Q-in-Q (802.1ad)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1557
|
||||
#: netbox/dcim/choices.py:1553
|
||||
msgid "IEEE Standard"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1568
|
||||
#: netbox/dcim/choices.py:1564
|
||||
msgid "Passive 24V (2-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1569
|
||||
#: netbox/dcim/choices.py:1565
|
||||
msgid "Passive 24V (4-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1570
|
||||
#: netbox/dcim/choices.py:1566
|
||||
msgid "Passive 48V (2-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1571
|
||||
#: netbox/dcim/choices.py:1567
|
||||
msgid "Passive 48V (4-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1644
|
||||
#: netbox/dcim/choices.py:1640
|
||||
msgid "Copper"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1667
|
||||
#: netbox/dcim/choices.py:1663
|
||||
msgid "Fiber Optic"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1703 netbox/dcim/choices.py:1917
|
||||
#: netbox/dcim/choices.py:1699 netbox/dcim/choices.py:1913
|
||||
msgid "USB"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1759
|
||||
#: netbox/dcim/choices.py:1755
|
||||
msgid "Single"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1761
|
||||
#: netbox/dcim/choices.py:1757
|
||||
msgid "1C1P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1762
|
||||
#: netbox/dcim/choices.py:1758
|
||||
msgid "1C2P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1763
|
||||
#: netbox/dcim/choices.py:1759
|
||||
msgid "1C4P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1764
|
||||
#: netbox/dcim/choices.py:1760
|
||||
msgid "1C6P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1765
|
||||
#: netbox/dcim/choices.py:1761
|
||||
msgid "1C8P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1766
|
||||
#: netbox/dcim/choices.py:1762
|
||||
msgid "1C12P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1767
|
||||
#: netbox/dcim/choices.py:1763
|
||||
msgid "1C16P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1771
|
||||
#: netbox/dcim/choices.py:1767
|
||||
msgid "Trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1773
|
||||
#: netbox/dcim/choices.py:1769
|
||||
msgid "2C1P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1774
|
||||
#: netbox/dcim/choices.py:1770
|
||||
msgid "2C2P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1775
|
||||
#: netbox/dcim/choices.py:1771
|
||||
msgid "2C4P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1776
|
||||
#: netbox/dcim/choices.py:1772
|
||||
msgid "2C4P trunk (shuffle)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1777
|
||||
#: netbox/dcim/choices.py:1773
|
||||
msgid "2C6P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1778
|
||||
#: netbox/dcim/choices.py:1774
|
||||
msgid "2C8P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1779
|
||||
#: netbox/dcim/choices.py:1775
|
||||
msgid "2C12P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1780
|
||||
#: netbox/dcim/choices.py:1776
|
||||
msgid "4C1P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1781
|
||||
#: netbox/dcim/choices.py:1777
|
||||
msgid "4C2P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1782
|
||||
#: netbox/dcim/choices.py:1778
|
||||
msgid "4C4P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1783
|
||||
#: netbox/dcim/choices.py:1779
|
||||
msgid "4C4P trunk (shuffle)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1784
|
||||
#: netbox/dcim/choices.py:1780
|
||||
msgid "4C6P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1785
|
||||
#: netbox/dcim/choices.py:1781
|
||||
msgid "4C8P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1786
|
||||
#: netbox/dcim/choices.py:1782
|
||||
msgid "8C4P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1790
|
||||
#: netbox/dcim/choices.py:1786
|
||||
msgid "Breakout"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1792
|
||||
#: netbox/dcim/choices.py:1788
|
||||
msgid "1C4P:4C1P breakout"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1793
|
||||
#: netbox/dcim/choices.py:1789
|
||||
msgid "1C6P:6C1P breakout"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1794
|
||||
#: netbox/dcim/choices.py:1790
|
||||
msgid "2C4P:8C1P breakout (shuffle)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1852
|
||||
#: netbox/dcim/choices.py:1848
|
||||
msgid "Copper - Twisted Pair (UTP/STP)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1866
|
||||
#: netbox/dcim/choices.py:1862
|
||||
msgid "Copper - Twinax (DAC)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1873
|
||||
#: netbox/dcim/choices.py:1869
|
||||
msgid "Copper - Coaxial"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1888
|
||||
#: netbox/dcim/choices.py:1884
|
||||
msgid "Fiber - Multimode"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1899
|
||||
#: netbox/dcim/choices.py:1895
|
||||
msgid "Fiber - Single-mode"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1907
|
||||
#: netbox/dcim/choices.py:1903
|
||||
msgid "Fiber - Other"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1932 netbox/dcim/forms/filtersets.py:1402
|
||||
#: netbox/dcim/choices.py:1928 netbox/dcim/forms/filtersets.py:1402
|
||||
msgid "Connected"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1951 netbox/netbox/choices.py:177
|
||||
#: netbox/dcim/choices.py:1947 netbox/netbox/choices.py:177
|
||||
msgid "Kilometers"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1952 netbox/netbox/choices.py:178
|
||||
#: netbox/dcim/choices.py:1948 netbox/netbox/choices.py:178
|
||||
#: netbox/templates/dcim/cable_trace.html:65
|
||||
msgid "Meters"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1953
|
||||
#: netbox/dcim/choices.py:1949
|
||||
msgid "Centimeters"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1954 netbox/netbox/choices.py:179
|
||||
#: netbox/dcim/choices.py:1950 netbox/netbox/choices.py:179
|
||||
msgid "Miles"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1955 netbox/netbox/choices.py:180
|
||||
#: netbox/dcim/choices.py:1951 netbox/netbox/choices.py:180
|
||||
#: netbox/templates/dcim/cable_trace.html:66
|
||||
msgid "Feet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2003
|
||||
#: netbox/dcim/choices.py:1999
|
||||
msgid "Redundant"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2024
|
||||
#: netbox/dcim/choices.py:2020
|
||||
msgid "Single phase"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2025
|
||||
#: netbox/dcim/choices.py:2021
|
||||
msgid "Three-phase"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2041 netbox/extras/choices.py:53
|
||||
#: netbox/dcim/choices.py:2037 netbox/extras/choices.py:53
|
||||
#: netbox/netbox/preferences.py:45 netbox/netbox/preferences.py:70
|
||||
#: netbox/templates/extras/customfield.html:78 netbox/vpn/choices.py:20
|
||||
#: netbox/wireless/choices.py:27
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2042
|
||||
#: netbox/dcim/choices.py:2038
|
||||
msgid "Faulty"
|
||||
msgstr ""
|
||||
|
||||
@@ -16677,7 +16677,7 @@ msgstr ""
|
||||
msgid "A column named {name} is already defined for table {table_name}"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/utilities/templates/builtins/customfield_value.html:32
|
||||
#: netbox/utilities/templates/builtins/customfield_value.html:30
|
||||
msgid "Not defined"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -23,38 +23,3 @@ class TokenExamplePanel(panels.Panel):
|
||||
actions = [
|
||||
actions.CopyContent('token-example')
|
||||
]
|
||||
|
||||
|
||||
class UserPanel(panels.ObjectAttributesPanel):
|
||||
username = attrs.TextAttr('username')
|
||||
full_name = attrs.TemplatedAttr(
|
||||
'get_full_name',
|
||||
label=_('Full name'),
|
||||
template_name='users/attrs/full_name.html',
|
||||
)
|
||||
email = attrs.TextAttr('email')
|
||||
date_joined = attrs.TextAttr('date_joined', label=_('Account created'))
|
||||
last_login = attrs.TextAttr('last_login', label=_('Last login'))
|
||||
is_active = attrs.BooleanAttr('is_active', label=_('Active'))
|
||||
is_superuser = attrs.BooleanAttr('is_superuser', label=_('Superuser'))
|
||||
|
||||
|
||||
class ObjectPermissionPanel(panels.ObjectAttributesPanel):
|
||||
name = attrs.TextAttr('name')
|
||||
description = attrs.TextAttr('description')
|
||||
enabled = attrs.BooleanAttr('enabled')
|
||||
|
||||
|
||||
class ObjectPermissionActionsPanel(panels.ObjectAttributesPanel):
|
||||
title = _('Actions')
|
||||
|
||||
can_view = attrs.BooleanAttr('can_view', label=_('View'))
|
||||
can_add = attrs.BooleanAttr('can_add', label=_('Add'))
|
||||
can_change = attrs.BooleanAttr('can_change', label=_('Change'))
|
||||
can_delete = attrs.BooleanAttr('can_delete', label=_('Delete'))
|
||||
|
||||
|
||||
class OwnerPanel(panels.ObjectAttributesPanel):
|
||||
name = attrs.TextAttr('name')
|
||||
group = attrs.RelatedObjectAttr('group', linkify=True)
|
||||
description = attrs.TextAttr('description')
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
from django.db.models import Count
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from core.models import ObjectChange
|
||||
from core.tables import ObjectChangeTable
|
||||
from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, BulkRename
|
||||
from netbox.ui import actions, layout
|
||||
from netbox.ui.panels import (
|
||||
ContextTablePanel,
|
||||
JSONPanel,
|
||||
ObjectsTablePanel,
|
||||
OrganizationalObjectPanel,
|
||||
RelatedObjectsPanel,
|
||||
TemplatePanel,
|
||||
)
|
||||
from netbox.ui import layout
|
||||
from netbox.views import generic
|
||||
from users.ui import panels
|
||||
from utilities.query import count_related
|
||||
@@ -95,42 +86,17 @@ class UserListView(generic.ObjectListView):
|
||||
@register_model_view(User)
|
||||
class UserView(generic.ObjectView):
|
||||
queryset = User.objects.all()
|
||||
layout = layout.SimpleLayout(
|
||||
left_panels=[
|
||||
panels.UserPanel(),
|
||||
],
|
||||
right_panels=[
|
||||
ObjectsTablePanel('users.Group', filters={'user_id': lambda ctx: ctx['object'].pk}),
|
||||
ObjectsTablePanel('users.ObjectPermission', filters={'user_id': lambda ctx: ctx['object'].pk}),
|
||||
ObjectsTablePanel('users.Owner', filters={'user_id': lambda ctx: ctx['object'].pk}),
|
||||
],
|
||||
bottom_panels=[
|
||||
ContextTablePanel(
|
||||
'changelog_table',
|
||||
title=_('Recent Activity'),
|
||||
actions=[
|
||||
actions.LinkAction(
|
||||
view_name='core:objectchange_list',
|
||||
url_params={'user_id': lambda ctx: ctx['object'].pk},
|
||||
label=_('View All'),
|
||||
button_class='ghost-primary',
|
||||
button_icon='arrow-right-thick',
|
||||
permissions=['core.view_objectchange'],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
template_name = 'users/user.html'
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
context = {}
|
||||
if request.user.has_perm('core.view_objectchange'):
|
||||
changelog = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(user=instance)[:20]
|
||||
changelog_table = ObjectChangeTable(changelog)
|
||||
changelog_table.orderable = False
|
||||
changelog_table.configure(request)
|
||||
context['changelog_table'] = changelog_table
|
||||
return context
|
||||
changelog = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(user=instance)[:20]
|
||||
changelog_table = ObjectChangeTable(changelog)
|
||||
changelog_table.orderable = False
|
||||
changelog_table.configure(request)
|
||||
|
||||
return {
|
||||
'changelog_table': changelog_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(User, 'add', detail=False)
|
||||
@@ -188,16 +154,7 @@ class GroupListView(generic.ObjectListView):
|
||||
@register_model_view(Group)
|
||||
class GroupView(generic.ObjectView):
|
||||
queryset = Group.objects.all()
|
||||
layout = layout.SimpleLayout(
|
||||
left_panels=[
|
||||
OrganizationalObjectPanel(),
|
||||
],
|
||||
right_panels=[
|
||||
ObjectsTablePanel('users.User', filters={'group_id': lambda ctx: ctx['object'].pk}),
|
||||
ObjectsTablePanel('users.ObjectPermission', filters={'group_id': lambda ctx: ctx['object'].pk}),
|
||||
ObjectsTablePanel('users.Owner', filters={'user_group_id': lambda ctx: ctx['object'].pk}),
|
||||
],
|
||||
)
|
||||
template_name = 'users/group.html'
|
||||
|
||||
|
||||
@register_model_view(Group, 'add', detail=False)
|
||||
@@ -255,18 +212,7 @@ class ObjectPermissionListView(generic.ObjectListView):
|
||||
@register_model_view(ObjectPermission)
|
||||
class ObjectPermissionView(generic.ObjectView):
|
||||
queryset = ObjectPermission.objects.all()
|
||||
layout = layout.SimpleLayout(
|
||||
left_panels=[
|
||||
panels.ObjectPermissionPanel(),
|
||||
panels.ObjectPermissionActionsPanel(),
|
||||
JSONPanel('constraints', title=_('Constraints')),
|
||||
],
|
||||
right_panels=[
|
||||
TemplatePanel('users/panels/object_types.html'),
|
||||
ObjectsTablePanel('users.User', filters={'permission_id': lambda ctx: ctx['object'].pk}),
|
||||
ObjectsTablePanel('users.Group', filters={'permission_id': lambda ctx: ctx['object'].pk}),
|
||||
],
|
||||
)
|
||||
template_name = 'users/objectpermission.html'
|
||||
|
||||
|
||||
@register_model_view(ObjectPermission, 'add', detail=False)
|
||||
@@ -319,25 +265,7 @@ class OwnerGroupListView(generic.ObjectListView):
|
||||
@register_model_view(OwnerGroup)
|
||||
class OwnerGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
layout = layout.SimpleLayout(
|
||||
left_panels=[
|
||||
OrganizationalObjectPanel(),
|
||||
],
|
||||
right_panels=[
|
||||
ObjectsTablePanel(
|
||||
'users.Owner',
|
||||
filters={'group_id': lambda ctx: ctx['object'].pk},
|
||||
title=_('Members'),
|
||||
actions=[
|
||||
actions.AddObject(
|
||||
'users.Owner',
|
||||
url_params={'group': lambda ctx: ctx['object'].pk},
|
||||
),
|
||||
],
|
||||
),
|
||||
RelatedObjectsPanel(),
|
||||
],
|
||||
)
|
||||
template_name = 'users/ownergroup.html'
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
return {
|
||||
@@ -398,16 +326,7 @@ class OwnerListView(generic.ObjectListView):
|
||||
@register_model_view(Owner)
|
||||
class OwnerView(GetRelatedModelsMixin, generic.ObjectView):
|
||||
queryset = Owner.objects.all()
|
||||
layout = layout.SimpleLayout(
|
||||
left_panels=[
|
||||
panels.OwnerPanel(),
|
||||
],
|
||||
right_panels=[
|
||||
ObjectsTablePanel('users.Group', filters={'owner_id': lambda ctx: ctx['object'].pk}),
|
||||
ObjectsTablePanel('users.User', filters={'owner_id': lambda ctx: ctx['object'].pk}),
|
||||
RelatedObjectsPanel(),
|
||||
],
|
||||
)
|
||||
template_name = 'users/owner.html'
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user