Merge branch 'develop' into feature

This commit is contained in:
jeremystretch
2022-10-20 16:07:03 -04:00
60 changed files with 1979 additions and 2375 deletions

View File

@@ -64,6 +64,12 @@ class ProviderNetworkForm(NetBoxModelForm):
class CircuitTypeForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Circuit Type', (
'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = CircuitType
fields = [

View File

@@ -1,8 +1,9 @@
import django_tables2 as tables
from circuits.models import *
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from .columns import CommitRateColumn
__all__ = (
@@ -39,7 +40,7 @@ class CircuitTypeTable(NetBoxTable):
default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
class CircuitTable(TenancyColumnsMixin, NetBoxTable):
class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
cid = tables.Column(
linkify=True,
verbose_name='Circuit ID'
@@ -58,9 +59,6 @@ class CircuitTable(TenancyColumnsMixin, NetBoxTable):
)
commit_rate = CommitRateColumn()
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='circuits:circuit_list'
)

View File

@@ -1,7 +1,8 @@
import django_tables2 as tables
from django_tables2.utils import Accessor
from circuits.models import *
from django_tables2.utils import Accessor
from tenancy.tables import ContactsColumnMixin
from netbox.tables import NetBoxTable, columns
__all__ = (
@@ -10,7 +11,7 @@ __all__ = (
)
class ProviderTable(NetBoxTable):
class ProviderTable(ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -31,9 +32,6 @@ class ProviderTable(NetBoxTable):
verbose_name='Circuits'
)
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='circuits:provider_list'
)

View File

@@ -108,7 +108,7 @@ def get_cable_form(a_type, b_type):
label='Power Feed',
disabled_indicator='_occupied',
query_params={
'powerpanel_id': f'$termination_{cable_end}_powerpanel',
'power_panel_id': f'$termination_{cable_end}_powerpanel',
}
)

View File

@@ -78,6 +78,12 @@ class RegionForm(NetBoxModelForm):
)
slug = SlugField()
fieldsets = (
('Region', (
'parent', 'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = Region
fields = (
@@ -92,6 +98,12 @@ class SiteGroupForm(NetBoxModelForm):
)
slug = SlugField()
fieldsets = (
('Site Group', (
'parent', 'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = SiteGroup
fields = (
@@ -213,6 +225,12 @@ class LocationForm(TenancyForm, NetBoxModelForm):
class RackRoleForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Rack Role', (
'name', 'slug', 'color', 'description', 'tags',
)),
)
class Meta:
model = RackRole
fields = [
@@ -341,6 +359,12 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
class ManufacturerForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Manufacturer', (
'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = Manufacturer
fields = [
@@ -413,6 +437,12 @@ class ModuleTypeForm(NetBoxModelForm):
class DeviceRoleForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Device Role', (
'name', 'slug', 'color', 'vm_role', 'description', 'tags',
)),
)
class Meta:
model = DeviceRole
fields = [
@@ -429,6 +459,13 @@ class PlatformForm(NetBoxModelForm):
max_length=64
)
fieldsets = (
('Platform', (
'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description', 'tags',
)),
)
class Meta:
model = Platform
fields = [
@@ -1584,6 +1621,12 @@ class InventoryItemForm(DeviceComponentForm):
class InventoryItemRoleForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Inventory Item Role', (
'name', 'slug', 'color', 'description', 'tags',
)),
)
class Meta:
model = InventoryItemRole
fields = [

View File

@@ -1,12 +1,26 @@
import django_tables2 as tables
from django_tables2.utils import Accessor
from dcim.models import (
ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, FrontPort, Interface, InventoryItem,
InventoryItemRole, ModuleBay, Platform, PowerOutlet, PowerPort, RearPort, VirtualChassis,
ConsolePort,
ConsoleServerPort,
Device,
DeviceBay,
DeviceRole,
FrontPort,
Interface,
InventoryItem,
InventoryItemRole,
ModuleBay,
Platform,
PowerOutlet,
PowerPort,
RearPort,
VirtualChassis,
)
from django_tables2.utils import Accessor
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from .template_code import *
__all__ = (
@@ -137,7 +151,7 @@ class PlatformTable(NetBoxTable):
# Devices
#
class DeviceTable(TenancyColumnsMixin, NetBoxTable):
class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.TemplateColumn(
order_by=('_name',),
template_code=DEVICE_LINK
@@ -201,9 +215,6 @@ class DeviceTable(TenancyColumnsMixin, NetBoxTable):
verbose_name='VC Priority'
)
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:device_list'
)

View File

@@ -1,10 +1,21 @@
import django_tables2 as tables
from dcim.models import (
ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, DeviceType, FrontPortTemplate, InterfaceTemplate,
InventoryItemTemplate, Manufacturer, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate, RearPortTemplate,
ConsolePortTemplate,
ConsoleServerPortTemplate,
DeviceBayTemplate,
DeviceType,
FrontPortTemplate,
InterfaceTemplate,
InventoryItemTemplate,
Manufacturer,
ModuleBayTemplate,
PowerOutletTemplate,
PowerPortTemplate,
RearPortTemplate,
)
from netbox.tables import NetBoxTable, columns
from tenancy.tables import ContactsColumnMixin
from .template_code import MODULAR_COMPONENT_TEMPLATE_BUTTONS, DEVICE_WEIGHT
__all__ = (
@@ -27,7 +38,7 @@ __all__ = (
# Manufacturers
#
class ManufacturerTable(NetBoxTable):
class ManufacturerTable(ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -43,9 +54,6 @@ class ManufacturerTable(NetBoxTable):
verbose_name='Platforms'
)
slug = tables.Column()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:manufacturer_list'
)

View File

@@ -1,7 +1,9 @@
import django_tables2 as tables
from dcim.models import PowerFeed, PowerPanel
from tenancy.tables import ContactsColumnMixin
from netbox.tables import NetBoxTable, columns
from .devices import CableTerminationTable
__all__ = (
@@ -14,7 +16,7 @@ __all__ = (
# Power panels
#
class PowerPanelTable(NetBoxTable):
class PowerPanelTable(ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -29,9 +31,6 @@ class PowerPanelTable(NetBoxTable):
url_params={'power_panel_id': 'pk'},
verbose_name='Feeds'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:powerpanel_list'
)

View File

@@ -3,7 +3,7 @@ from django_tables2.utils import Accessor
from dcim.models import Rack, RackReservation, RackRole
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from .template_code import DEVICE_WEIGHT
__all__ = (
@@ -38,7 +38,7 @@ class RackRoleTable(NetBoxTable):
# Racks
#
class RackTable(TenancyColumnsMixin, NetBoxTable):
class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column(
order_by=('_name',),
linkify=True
@@ -69,9 +69,6 @@ class RackTable(TenancyColumnsMixin, NetBoxTable):
orderable=False,
verbose_name='Power'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:rack_list'
)

View File

@@ -1,8 +1,9 @@
import django_tables2 as tables
from dcim.models import Location, Region, Site, SiteGroup
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from .template_code import LOCATION_BUTTONS
__all__ = (
@@ -17,7 +18,7 @@ __all__ = (
# Regions
#
class RegionTable(NetBoxTable):
class RegionTable(ContactsColumnMixin, NetBoxTable):
name = columns.MPTTColumn(
linkify=True
)
@@ -26,9 +27,6 @@ class RegionTable(NetBoxTable):
url_params={'region_id': 'pk'},
verbose_name='Sites'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:region_list'
)
@@ -46,7 +44,7 @@ class RegionTable(NetBoxTable):
# Site groups
#
class SiteGroupTable(NetBoxTable):
class SiteGroupTable(ContactsColumnMixin, NetBoxTable):
name = columns.MPTTColumn(
linkify=True
)
@@ -55,9 +53,6 @@ class SiteGroupTable(NetBoxTable):
url_params={'group_id': 'pk'},
verbose_name='Sites'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:sitegroup_list'
)
@@ -75,7 +70,7 @@ class SiteGroupTable(NetBoxTable):
# Sites
#
class SiteTable(TenancyColumnsMixin, NetBoxTable):
class SiteTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -97,9 +92,6 @@ class SiteTable(TenancyColumnsMixin, NetBoxTable):
verbose_name='ASN Count'
)
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:site_list'
)
@@ -118,7 +110,7 @@ class SiteTable(TenancyColumnsMixin, NetBoxTable):
# Locations
#
class LocationTable(TenancyColumnsMixin, NetBoxTable):
class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = columns.MPTTColumn(
linkify=True
)
@@ -136,9 +128,6 @@ class LocationTable(TenancyColumnsMixin, NetBoxTable):
url_params={'location_id': 'pk'},
verbose_name='Devices'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='dcim:location_list'
)

View File

@@ -88,6 +88,12 @@ class RouteTargetForm(TenancyForm, NetBoxModelForm):
class RIRForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('RIR', (
'name', 'slug', 'is_private', 'description', 'tags',
)),
)
class Meta:
model = RIR
fields = [
@@ -164,6 +170,12 @@ class ASNForm(TenancyForm, NetBoxModelForm):
class RoleForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Role', (
'name', 'slug', 'weight', 'description', 'tags',
)),
)
class Meta:
model = Role
fields = [
@@ -784,6 +796,12 @@ class ServiceTemplateForm(NetBoxModelForm):
help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen."
)
fieldsets = (
('Service Template', (
'name', 'protocol', 'ports', 'description', 'tags',
)),
)
class Meta:
model = ServiceTemplate
fields = ('name', 'protocol', 'ports', 'description', 'tags')

View File

@@ -92,6 +92,8 @@ class Service(ServiceBase, NetBoxModel):
verbose_name='IP addresses'
)
clone_fields = ['protocol', 'ports', 'description', 'device', 'virtual_machine', 'ipaddresses', ]
class Meta:
ordering = ('protocol', 'ports', 'pk') # (protocol, port) may be non-unique

View File

@@ -351,6 +351,14 @@ class LDAPBackend:
if getattr(ldap_config, 'LDAP_IGNORE_CERT_ERRORS', False):
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
# Optionally set CA cert directory
if ca_cert_dir := getattr(ldap_config, 'LDAP_CA_CERT_DIR', None):
ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, ca_cert_dir)
# Optionally set CA cert file
if ca_cert_file := getattr(ldap_config, 'LDAP_CA_CERT_FILE', None):
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ca_cert_file)
return obj

View File

@@ -493,7 +493,7 @@ for param in dir(configuration):
# Force usage of PostgreSQL's JSONB field for extra data
SOCIAL_AUTH_JSONFIELD_ENABLED = True
SOCIAL_AUTH_CLEAN_USERNAME_FUNCTION = 'netbox.users.utils.clean_username'
#
# Django Prometheus

View File

@@ -31,8 +31,7 @@
}
},
"rules": {
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-unused-vars-experimental": "error",
"@typescript-eslint/no-unused-vars": "error",
"no-unused-vars": "off",
"no-inner-declarations": "off",
"comma-dangle": ["error", "always-multiline"],

View File

@@ -1 +1 @@
:root{--nbx-trace-color: #000;--nbx-trace-node-bg: #e9ecef;--nbx-trace-termination-bg: #f8f9fa;--nbx-trace-cable-shadow: #343a40;--nbx-trace-attachment: #ced4da}:root[data-netbox-color-mode=dark]{--nbx-trace-color: #fff;--nbx-trace-node-bg: #212529;--nbx-trace-termination-bg: #343a40;--nbx-trace-cable-shadow: #e9ecef;--nbx-trace-attachment: #6c757d}*{font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:.875rem}text{text-anchor:middle;dominant-baseline:middle}text:not([fill]){fill:var(--nbx-trace-color)}text.bold{font-weight:700}svg rect{fill:var(--nbx-trace-node-bg);stroke:#606060;stroke-width:1}svg rect .termination{fill:var(--nbx-trace-termination-bg)}svg .connector text{text-anchor:start}svg line{stroke-width:5px}svg polyline{fill:none;stroke-width:5px}svg .cable-shadow{stroke:var(--nbx-trace-cable-shadow);stroke-width:7px}svg line.wireless-link{stroke:var(--nbx-trace-attachment);stroke-dasharray:4px 12px;stroke-linecap:round}svg line.attachment{stroke:var(--nbx-trace-attachment);stroke-dasharray:5px}
:root{--nbx-trace-color: #000;--nbx-trace-node-bg: #e9ecef;--nbx-trace-termination-bg: #f8f9fa;--nbx-trace-cable-shadow: #343a40;--nbx-trace-attachment: #ced4da}:root[data-netbox-color-mode=dark]{--nbx-trace-color: #fff;--nbx-trace-node-bg: #212529;--nbx-trace-termination-bg: #343a40;--nbx-trace-cable-shadow: #e9ecef;--nbx-trace-attachment: #6c757d}*{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-size:.875rem}text{text-anchor:middle;dominant-baseline:middle}text:not([fill]){fill:var(--nbx-trace-color)}text.bold{font-weight:700}svg rect{fill:var(--nbx-trace-node-bg);stroke:#606060;stroke-width:1}svg rect .termination{fill:var(--nbx-trace-termination-bg)}svg .connector text{text-anchor:start}svg line{stroke-width:5px}svg polyline{fill:none;stroke-width:5px}svg .cable-shadow{stroke:var(--nbx-trace-cable-shadow);stroke-width:7px}svg line.wireless-link{stroke:var(--nbx-trace-attachment);stroke-dasharray:4px 12px;stroke-linecap:round}svg line.attachment{stroke:var(--nbx-trace-attachment);stroke-dasharray:5px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
svg{--nbx-rack-bg: #e9ecef;--nbx-rack-border: #000;--nbx-rack-slot-bg: #e9ecef;--nbx-rack-slot-border: #adb5bd;--nbx-rack-slot-hover-bg: #ced4da;--nbx-rack-link-color: #0d6efd;--nbx-rack-unit-color: #6c757d}svg[data-netbox-color-mode=dark]{--nbx-rack-bg: #343a40;--nbx-rack-border: #6c757d;--nbx-rack-slot-bg: #343a40;--nbx-rack-slot-border: #495057;--nbx-rack-slot-hover-bg: #212529;--nbx-rack-link-color: #9ec5fe;--nbx-rack-unit-color: #6c757d}*{font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:.875rem}rect{box-sizing:border-box}text{text-anchor:middle;dominant-baseline:middle}svg .unit{margin:0;padding:5px 0;fill:var(--nbx-rack-unit-color)}svg .hidden{visibility:hidden}svg rect.shaded,svg image.shaded{opacity:25%}svg text.shaded{opacity:50%}svg .rack{fill:none;stroke-width:2px;stroke:var(--nbx-rack-border);background-color:var(--nbx-rack-bg)}svg .slot{fill:var(--nbx-rack-slot-bg);stroke:var(--nbx-rack-slot-border)}svg .slot:hover{fill:var(--nbx-rack-slot-hover-bg)}svg .slot+.add-device{fill:var(--nbx-rack-link-color);opacity:0;pointer-events:none}svg .slot:hover+.add-device{opacity:1}svg .slot.occupied[class],svg .slot.occupied:hover[class]{fill:url(#occupied)}svg .slot.blocked[class],svg .slot.blocked:hover[class]{fill:url(#blocked)}svg .slot.blocked:hover+.add-device{opacity:0}svg .reservation[class]{fill:url(#reserved)}
svg{--nbx-rack-bg: #e9ecef;--nbx-rack-border: #000;--nbx-rack-slot-bg: #e9ecef;--nbx-rack-slot-border: #adb5bd;--nbx-rack-slot-hover-bg: #ced4da;--nbx-rack-link-color: #0d6efd;--nbx-rack-unit-color: #6c757d}svg[data-netbox-color-mode=dark]{--nbx-rack-bg: #343a40;--nbx-rack-border: #6c757d;--nbx-rack-slot-bg: #343a40;--nbx-rack-slot-border: #495057;--nbx-rack-slot-hover-bg: #212529;--nbx-rack-link-color: #9ec5fe;--nbx-rack-unit-color: #6c757d}*{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-size:.875rem}rect{box-sizing:border-box}text{text-anchor:middle;dominant-baseline:middle}svg .unit{margin:0;padding:5px 0;fill:var(--nbx-rack-unit-color)}svg .hidden{visibility:hidden}svg rect.shaded,svg image.shaded{opacity:25%}svg text.shaded{opacity:50%}svg .rack{fill:none;stroke-width:2px;stroke:var(--nbx-rack-border);background-color:var(--nbx-rack-bg)}svg .slot{fill:var(--nbx-rack-slot-bg);stroke:var(--nbx-rack-slot-border)}svg .slot:hover{fill:var(--nbx-rack-slot-hover-bg)}svg .slot+.add-device{fill:var(--nbx-rack-link-color);opacity:0;pointer-events:none}svg .slot:hover+.add-device{opacity:1}svg .slot.occupied[class],svg .slot.occupied:hover[class]{fill:url(#occupied)}svg .slot.blocked[class],svg .slot.blocked:hover[class]{fill:url(#blocked)}svg .slot.blocked:hover+.add-device{opacity:0}svg .reservation[class]{fill:url(#reserved)}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -22,43 +22,38 @@
"validate:formatting:scripts": "prettier -c src/**/*.ts"
},
"dependencies": {
"@mdi/font": "^5.9.55",
"@popperjs/core": "^2.9.2",
"@mdi/font": "^7.0.96",
"@popperjs/core": "^2.11.6",
"bootstrap": "~5.0.2",
"clipboard": "^2.0.8",
"color2k": "^1.2.4",
"dayjs": "^1.10.4",
"flatpickr": "4.6.3",
"htmx.org": "^1.6.1",
"just-debounce-it": "^1.4.0",
"clipboard": "^2.0.11",
"color2k": "^2.0.0",
"dayjs": "^1.11.5",
"flatpickr": "4.6.13",
"htmx.org": "^1.8.0",
"just-debounce-it": "^3.1.1",
"masonry-layout": "^4.2.2",
"query-string": "^6.14.1",
"sass": "^1.32.8",
"simplebar": "^5.3.4",
"slim-select": "^1.27.0"
"query-string": "^7.1.1",
"sass": "^1.55.0",
"simplebar": "^5.3.9",
"slim-select": "^1.27.1"
},
"devDependencies": {
"@types/bootstrap": "^5.0.12",
"@types/cookie": "^0.4.0",
"@types/masonry-layout": "^4.2.2",
"@typescript-eslint/eslint-plugin": "^4.29.3",
"@typescript-eslint/parser": "^4.29.3",
"esbuild": "^0.12.24",
"esbuild-sass-plugin": "^1.5.2",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-prettier": "^3.4.1",
"prettier": "^2.3.2",
"typescript": "~4.3.5"
"@types/bootstrap": "^5.0.17",
"@types/cookie": "^0.5.1",
"@types/masonry-layout": "^4.2.5",
"@typescript-eslint/eslint-plugin": "^5.39.0",
"@typescript-eslint/parser": "^5.39.0",
"esbuild": "^0.13.15",
"esbuild-sass-plugin": "^2.3.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.5.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.7.1",
"typescript": "~4.8.4"
},
"resolutions": {
"eslint-import-resolver-typescript/**/path-parse": "^1.0.7",
"slim-select/**/trim-newlines": "^3.0.1",
"eslint/glob-parent": "^5.1.2",
"esbuild-sass-plugin/**/glob-parent": "^5.1.2",
"@typescript-eslint/**/glob-parent": "^5.1.2",
"eslint-plugin-import/**/hosted-git-info": "^2.8.9"
"@types/bootstrap/**/@popperjs/core": "^2.11.6"
}
}
}

View File

@@ -37,14 +37,12 @@ function initDocument(): void {
}
function initWindow(): void {
const documentForms = document.forms
for (var documentForm of documentForms) {
const documentForms = document.forms;
for (const documentForm of documentForms) {
if (documentForm.method.toUpperCase() == 'GET') {
// @ts-ignore: Our version of typescript seems to be too old for FormDataEvent
documentForm.addEventListener('formdata', function(event: FormDataEvent) {
let formData: FormData = event.formData;
for (let [name, value] of Array.from(formData.entries())) {
documentForm.addEventListener('formdata', function (event: FormDataEvent) {
const formData: FormData = event.formData;
for (const [name, value] of Array.from(formData.entries())) {
if (value === '') formData.delete(name);
}
});

View File

@@ -32,7 +32,7 @@ $spacing-s: $input-padding-x;
}
}
@import './node_modules/slim-select/src/slim-select/slimselect';
@import '../node_modules/slim-select/src/slim-select/slimselect';
.ss-main {
color: $form-select-color;

File diff suppressed because it is too large Load Diff

View File

@@ -60,23 +60,17 @@
</div>
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">
{% include 'inc/panels/comments.html' %}
{% include 'circuits/inc/circuit_termination.html' with termination=object.termination_a side='A' %}
{% include 'circuits/inc/circuit_termination.html' with termination=object.termination_z side='Z' %}
{% include 'inc/panels/contacts.html' %}
{% include 'inc/panels/image_attachments.html' %}
{% plugin_right_page object %}
</div>
</div>
<div class="row">
<div class="col col-md-6">
{% include 'circuits/inc/circuit_termination.html' with termination=object.termination_a side='A' %}
</div>
<div class="col col-md-6">
{% include 'circuits/inc/circuit_termination.html' with termination=object.termination_z side='Z' %}
</div>
</div>
<div class="row">
<div class="col col-md-12">
{% plugin_full_width_page object %}

View File

@@ -77,10 +77,10 @@
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.powerportport&a_terminations={{ object.pk }}&termination_b_type=dcim.poweroutlet&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-link">Power Outlet</a>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.powerportport&a_terminations={{ object.pk }}&termination_b_type=dcim.poweroutlet&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-item">Power Outlet</a>
</li>
<li>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.powerportport&a_terminations={{ object.pk }}&termination_b_type=dcim.powerfeed&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-link">Power Feed</a>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.powerportport&a_terminations={{ object.pk }}&termination_b_type=dcim.powerfeed&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-item">Power Feed</a>
</li>
</ul>
</span>

View File

@@ -105,16 +105,16 @@
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-link" href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=dcim.interface&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}">Interface</a>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=dcim.interface&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-item">Interface</a>
</li>
<li>
<a class="dropdown-link" href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=dcim.frontport&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}">Front Port</a>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=dcim.frontport&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-item">Front Port</a>
</li>
<li>
<a class="dropdown-link" href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=dcim.rearport&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}">Rear Port</a>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=dcim.rearport&termination_b_site={{ object.device.site.pk }}&termination_b_rack={{ object.device.rack.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-item">Rear Port</a>
</li>
<li>
<a class="dropdown-link" href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=circuits.circuittermination&termination_b_site={{ object.device.site.pk }}&return_url={{ object.get_absolute_url }}">Circuit Termination</a>
<a href="{% url 'dcim:cable_add' %}?a_terminations_type=dcim.rearport&a_terminations={{ object.pk }}&b_terminations_type=circuits.circuittermination&termination_b_site={{ object.device.site.pk }}&return_url={{ object.get_absolute_url }}" class="dropdown-item">Circuit Termination</a>
</li>
</ul>
</span>

View File

@@ -27,6 +27,12 @@ class TenantGroupForm(NetBoxModelForm):
)
slug = SlugField()
fieldsets = (
('Tenant Group', (
'parent', 'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = TenantGroup
fields = [
@@ -64,6 +70,12 @@ class ContactGroupForm(NetBoxModelForm):
)
slug = SlugField()
fieldsets = (
('Contact Group', (
'parent', 'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = ContactGroup
fields = ('parent', 'name', 'slug', 'description', 'tags')
@@ -72,6 +84,12 @@ class ContactGroupForm(NetBoxModelForm):
class ContactRoleForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Contact Role', (
'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = ContactRole
fields = ('name', 'slug', 'description', 'tags')

View File

@@ -1,6 +1,9 @@
import django_tables2 as tables
from netbox.tables import columns
__all__ = (
'ContactsColumnMixin',
'TenantColumn',
'TenantGroupColumn',
'TenancyColumnsMixin',
@@ -55,3 +58,10 @@ class TenantGroupColumn(tables.TemplateColumn):
class TenancyColumnsMixin(tables.Table):
tenant_group = TenantGroupColumn()
tenant = TenantColumn()
class ContactsColumnMixin(tables.Table):
contacts = columns.ManyToManyColumn(
linkify_item=True,
transform=lambda obj: obj.contact.name
)

View File

@@ -1,7 +1,8 @@
import django_tables2 as tables
from tenancy.models import *
from tenancy.tables import ContactsColumnMixin
from netbox.tables import NetBoxTable, columns
from tenancy.models import *
__all__ = (
'TenantGroupTable',
@@ -30,7 +31,7 @@ class TenantGroupTable(NetBoxTable):
default_columns = ('pk', 'name', 'tenant_count', 'description')
class TenantTable(NetBoxTable):
class TenantTable(ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -38,9 +39,6 @@ class TenantTable(NetBoxTable):
linkify=True
)
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='tenancy:contact_list'
)

9
netbox/users/utils.py Normal file
View File

@@ -0,0 +1,9 @@
from social_core.storage import NO_ASCII_REGEX, NO_SPECIAL_REGEX
def clean_username(value):
"""Clean username removing any unsupported character"""
value = NO_ASCII_REGEX.sub('', value)
value = NO_SPECIAL_REGEX.sub('', value)
value = value.replace(':', '')
return value

View File

@@ -28,6 +28,12 @@ __all__ = (
class ClusterTypeForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Cluster Type', (
'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = ClusterType
fields = (
@@ -38,6 +44,12 @@ class ClusterTypeForm(NetBoxModelForm):
class ClusterGroupForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Cluster Group', (
'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = ClusterGroup
fields = (

View File

@@ -1,8 +1,8 @@
import django_tables2 as tables
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from virtualization.models import Cluster, ClusterGroup, ClusterType
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from virtualization.models import Cluster, ClusterGroup, ClusterType
__all__ = (
'ClusterTable',
@@ -32,7 +32,7 @@ class ClusterTypeTable(NetBoxTable):
default_columns = ('pk', 'name', 'cluster_count', 'description')
class ClusterGroupTable(NetBoxTable):
class ClusterGroupTable(ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -41,9 +41,6 @@ class ClusterGroupTable(NetBoxTable):
url_params={'group_id': 'pk'},
verbose_name='Clusters'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='virtualization:clustergroup_list'
)
@@ -57,7 +54,7 @@ class ClusterGroupTable(NetBoxTable):
default_columns = ('pk', 'name', 'cluster_count', 'description')
class ClusterTable(TenancyColumnsMixin, NetBoxTable):
class ClusterTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -81,9 +78,6 @@ class ClusterTable(TenancyColumnsMixin, NetBoxTable):
verbose_name='VMs'
)
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='virtualization:cluster_list'
)

View File

@@ -1,10 +1,10 @@
import django_tables2 as tables
from dcim.tables.devices import BaseInterfaceTable
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from virtualization.models import VirtualMachine, VMInterface
from netbox.tables import NetBoxTable, columns
__all__ = (
'VirtualMachineTable',
'VirtualMachineVMInterfaceTable',
@@ -37,7 +37,7 @@ VMINTERFACE_BUTTONS = """
# Virtual machines
#
class VirtualMachineTable(TenancyColumnsMixin, NetBoxTable):
class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column(
order_by=('_name',),
linkify=True
@@ -67,9 +67,6 @@ class VirtualMachineTable(TenancyColumnsMixin, NetBoxTable):
order_by=('primary_ip4', 'primary_ip6'),
verbose_name='IP Address'
)
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='virtualization:virtualmachine_list'
)

View File

@@ -19,6 +19,12 @@ class WirelessLANGroupForm(NetBoxModelForm):
)
slug = SlugField()
fieldsets = (
('Wireless LAN Group', (
'parent', 'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = WirelessLANGroup
fields = [