mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-17 21:18:16 -06:00
Merge branch 'feature' into 14438-script-model
This commit is contained in:
commit
6cb176a36d
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## v4.0.0 (FUTURE)
|
## v4.0.0 (FUTURE)
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The deprecated `device_role` & `device_role_id` filters for devices have been removed. (Use `role` and `role_id` instead.)
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
||||||
#### Complete UI Refresh ([#12128](https://github.com/netbox-community/netbox/issues/12128))
|
#### Complete UI Refresh ([#12128](https://github.com/netbox-community/netbox/issues/12128))
|
||||||
@ -26,3 +30,5 @@ The NetBox user interface has been completely refreshed and updated.
|
|||||||
* [#14657](https://github.com/netbox-community/netbox/issues/14657) - Remove backward compatibility for old permissions mapping under `ActionsMixin`
|
* [#14657](https://github.com/netbox-community/netbox/issues/14657) - Remove backward compatibility for old permissions mapping under `ActionsMixin`
|
||||||
* [#14658](https://github.com/netbox-community/netbox/issues/14658) - Remove backward compatibility for importing `process_webhook()` (now `extras.webhooks.send_webhook()`)
|
* [#14658](https://github.com/netbox-community/netbox/issues/14658) - Remove backward compatibility for importing `process_webhook()` (now `extras.webhooks.send_webhook()`)
|
||||||
* [#14740](https://github.com/netbox-community/netbox/issues/14740) - Remove the obsolete `BootstrapMixin` form mixin class
|
* [#14740](https://github.com/netbox-community/netbox/issues/14740) - Remove the obsolete `BootstrapMixin` form mixin class
|
||||||
|
* [#15099](https://github.com/netbox-community/netbox/issues/15099) - Remove obsolete `device_role` and `device_role_id` filters for devices
|
||||||
|
* [#15100](https://github.com/netbox-community/netbox/issues/15100) - Remove obsolete `NullableCharField` class
|
||||||
|
@ -1288,18 +1288,6 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label=_('Virtual Chassis'),
|
label=_('Virtual Chassis'),
|
||||||
)
|
)
|
||||||
# TODO: Remove in v4.0
|
|
||||||
device_role_id = django_filters.ModelMultipleChoiceFilter(
|
|
||||||
field_name='device__role',
|
|
||||||
queryset=DeviceRole.objects.all(),
|
|
||||||
label=_('Device role (ID)'),
|
|
||||||
)
|
|
||||||
device_role = django_filters.ModelMultipleChoiceFilter(
|
|
||||||
field_name='device__role__slug',
|
|
||||||
queryset=DeviceRole.objects.all(),
|
|
||||||
to_field_name='slug',
|
|
||||||
label=_('Device role (slug)'),
|
|
||||||
)
|
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
BIN
netbox/project-static/dist/netbox.css
vendored
BIN
netbox/project-static/dist/netbox.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
@ -1,15 +0,0 @@
|
|||||||
import { isTruthy, getElements } from './util';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow any element to be made "clickable" with the use of the `data-href` attribute.
|
|
||||||
*/
|
|
||||||
export function initLinks(): void {
|
|
||||||
for (const link of getElements('*[data-href]')) {
|
|
||||||
const href = link.getAttribute('data-href');
|
|
||||||
if (isTruthy(href)) {
|
|
||||||
link.addEventListener('click', () => {
|
|
||||||
window.location.assign(href);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,7 +12,6 @@ import { initInterfaceTable } from './tables';
|
|||||||
import { initSideNav } from './sidenav';
|
import { initSideNav } from './sidenav';
|
||||||
import { initDashboard } from './dashboard';
|
import { initDashboard } from './dashboard';
|
||||||
import { initRackElevation } from './racks';
|
import { initRackElevation } from './racks';
|
||||||
import { initLinks } from './links';
|
|
||||||
import { initHtmx } from './htmx';
|
import { initHtmx } from './htmx';
|
||||||
|
|
||||||
function initDocument(): void {
|
function initDocument(): void {
|
||||||
@ -31,7 +30,6 @@ function initDocument(): void {
|
|||||||
initSideNav,
|
initSideNav,
|
||||||
initDashboard,
|
initDashboard,
|
||||||
initRackElevation,
|
initRackElevation,
|
||||||
initLinks,
|
|
||||||
initHtmx,
|
initHtmx,
|
||||||
]) {
|
]) {
|
||||||
init();
|
init();
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
@import '../node_modules/@tabler/core/src/scss/vendor/tom-select';
|
@import '../node_modules/@tabler/core/src/scss/vendor/tom-select';
|
||||||
|
|
||||||
// Overrides of external libraries
|
// Overrides of external libraries
|
||||||
@import 'overrides/slim-select';
|
|
||||||
@import 'overrides/tabler';
|
@import 'overrides/tabler';
|
||||||
|
|
||||||
// Transitional styling to ease migration of templates from NetBox v3.x
|
// Transitional styling to ease migration of templates from NetBox v3.x
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
// SlimSelect Style Overrides.
|
|
||||||
|
|
||||||
$height: $input-height;
|
|
||||||
$white: $white;
|
|
||||||
$font-color: $input-color;
|
|
||||||
$font-placeholder-color: $input-placeholder-color;
|
|
||||||
$font-disabled-color: $form-select-disabled-color;
|
|
||||||
$primary-color: $primary;
|
|
||||||
$border-color: $form-select-border-color;
|
|
||||||
$search-highlight-color: $yellow;
|
|
||||||
$border-radius: $form-select-border-radius;
|
|
||||||
$spacing-l: $input-padding-x;
|
|
||||||
$spacing-m: $input-padding-x;
|
|
||||||
$spacing-s: $input-padding-x;
|
|
||||||
|
|
||||||
:root {
|
|
||||||
// Light Mode Variables.
|
|
||||||
--nbx-select-content-bg: #{$form-select-bg};
|
|
||||||
--nbx-select-option-selected-bg: #{$gray-300};
|
|
||||||
--nbx-select-option-hover-bg: #{$blue};
|
|
||||||
--nbx-select-option-hover-color: #{$white};
|
|
||||||
--nbx-select-placeholder-color: #{$gray-500};
|
|
||||||
--nbx-select-value-color: #{$white};
|
|
||||||
&[data-netbox-color-mode='dark'] {
|
|
||||||
// Dark Mode Variables.
|
|
||||||
--nbx-select-content-bg: #{$gray-900};
|
|
||||||
--nbx-select-option-selected-bg: #{$gray-500};
|
|
||||||
--nbx-select-option-hover-bg: #{$blue-200};
|
|
||||||
--nbx-select-option-hover-color: #{color-contrast($blue-200)};
|
|
||||||
--nbx-select-placeholder-color: #{$gray-700};
|
|
||||||
--nbx-select-value-color: #{$black};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@import '../node_modules/slim-select/src/slim-select/slimselect';
|
|
||||||
|
|
||||||
.ss-main {
|
|
||||||
color: $form-select-color;
|
|
||||||
|
|
||||||
.ss-single-selected,
|
|
||||||
.ss-multi-selected {
|
|
||||||
padding: $form-select-padding-y $input-padding-x $form-select-padding-y $form-select-padding-x;
|
|
||||||
background-color: $form-select-bg;
|
|
||||||
border: $form-select-border-width solid $input-border-color;
|
|
||||||
&[disabled] {
|
|
||||||
color: $form-select-disabled-color;
|
|
||||||
background-color: $form-select-disabled-bg;
|
|
||||||
border-color: $form-select-disabled-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.ss-multi-selected .ss-values .ss-disabled,
|
|
||||||
div.ss-single-selected span.placeholder .ss-disabled {
|
|
||||||
color: var(--nbx-select-placeholder-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ss-single-selected {
|
|
||||||
span.ss-arrow {
|
|
||||||
// Inherit the arrow color from the parent (see color selector).
|
|
||||||
span.arrow-down,
|
|
||||||
span.arrow-up {
|
|
||||||
border-color: currentColor;
|
|
||||||
color: $text-muted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Don't show the depth indicator outside of the menu.
|
|
||||||
.placeholder .depth {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
span.placeholder > *,
|
|
||||||
span.placeholder {
|
|
||||||
line-height: $input-line-height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ss-multi-selected {
|
|
||||||
align-items: center;
|
|
||||||
padding-right: $input-padding-x;
|
|
||||||
padding-left: $input-padding-x;
|
|
||||||
|
|
||||||
.ss-values {
|
|
||||||
.ss-disabled {
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
.ss-value {
|
|
||||||
color: var(--nbx-select-value-color);
|
|
||||||
border-radius: $badge-border-radius;
|
|
||||||
|
|
||||||
// Don't show the depth indicator outside of the menu.
|
|
||||||
.depth {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ss-add {
|
|
||||||
margin: 0 0.75rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ss-content {
|
|
||||||
background-color: var(--nbx-select-content-bg);
|
|
||||||
.ss-list {
|
|
||||||
.ss-option {
|
|
||||||
&.ss-option-selected {
|
|
||||||
color: $body-color;
|
|
||||||
background-color: var(--nbx-select-option-selected-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--nbx-select-option-hover-color);
|
|
||||||
background-color: var(--nbx-select-option-hover-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom-right-radius: $form-select-border-radius;
|
|
||||||
border-bottom-left-radius: $form-select-border-radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ss-disabled {
|
|
||||||
background-color: unset;
|
|
||||||
&:hover {
|
|
||||||
color: $form-select-disabled-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.depth {
|
|
||||||
// Lighten the dash prefix on nested options.
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
right: 0;
|
|
||||||
width: 4px;
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
right: 0;
|
|
||||||
width: 2px;
|
|
||||||
background-color: var(--nbx-sidebar-scroll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
border-bottom-right-radius: $form-select-border-radius;
|
|
||||||
border-bottom-left-radius: $form-select-border-radius;
|
|
||||||
.ss-search {
|
|
||||||
padding-right: $spacer * 0.5;
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin-left: $spacer * 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='search'] {
|
|
||||||
color: $input-color;
|
|
||||||
background-color: $form-select-bg;
|
|
||||||
border: $input-border-width solid $input-border-color;
|
|
||||||
&:focus {
|
|
||||||
border-color: $form-select-focus-border-color;
|
|
||||||
outline: 0;
|
|
||||||
@if $enable-shadows {
|
|
||||||
@include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow);
|
|
||||||
} @else {
|
|
||||||
// Avoid using mixin so we can pass custom focus shadow properly
|
|
||||||
box-shadow: $form-select-focus-box-shadow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix slim-select 1.x placeholder styling
|
|
||||||
.ss-main {
|
|
||||||
.ss-single-selected {
|
|
||||||
.placeholder {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 1;
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply red border for fields inside a row with .has-errors
|
|
||||||
.has-errors {
|
|
||||||
.ss-single-selected,
|
|
||||||
.ss-multi-selected {
|
|
||||||
border-color: $red;
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,26 +12,10 @@ __all__ = (
|
|||||||
'ColorField',
|
'ColorField',
|
||||||
'CounterCacheField',
|
'CounterCacheField',
|
||||||
'NaturalOrderingField',
|
'NaturalOrderingField',
|
||||||
'NullableCharField',
|
|
||||||
'RestrictedGenericForeignKey',
|
'RestrictedGenericForeignKey',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Deprecated: Retained only to ensure successful migration from early releases
|
|
||||||
# Use models.CharField(null=True) instead
|
|
||||||
# TODO: Remove in v4.0
|
|
||||||
class NullableCharField(models.CharField):
|
|
||||||
description = "Stores empty values as NULL rather than ''"
|
|
||||||
|
|
||||||
def to_python(self, value):
|
|
||||||
if isinstance(value, models.CharField):
|
|
||||||
return value
|
|
||||||
return value or ''
|
|
||||||
|
|
||||||
def get_prep_value(self, value):
|
|
||||||
return value or None
|
|
||||||
|
|
||||||
|
|
||||||
class ColorField(models.CharField):
|
class ColorField(models.CharField):
|
||||||
default_validators = [ColorValidator]
|
default_validators = [ColorValidator]
|
||||||
description = "A hexadecimal RGB color code"
|
description = "A hexadecimal RGB color code"
|
||||||
|
Loading…
Reference in New Issue
Block a user