mirror of
https://github.com/netbox-community/netbox.git
synced 2025-09-06 14:23:36 -06:00
Closes #18984: Add status field to Rack model
This commit is contained in:
parent
032bd52dc7
commit
b0a6204a16
@ -12,6 +12,13 @@ The [rack](./rack.md) being reserved.
|
|||||||
|
|
||||||
The rack unit or units being reserved. Multiple units can be expressed using commas and/or hyphens. For example, `1,3,5-7` specifies units 1, 3, 5, 6, and 7.
|
The rack unit or units being reserved. Multiple units can be expressed using commas and/or hyphens. For example, `1,3,5-7` specifies units 1, 3, 5, 6, and 7.
|
||||||
|
|
||||||
|
### Status
|
||||||
|
|
||||||
|
The current status of the reservation. (This is for documentation only: The status of a reservation has no impact on the installation of devices within a reserved rack unit.)
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Additional statuses may be defined by setting `RackReservation.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
|
||||||
|
|
||||||
### User
|
### User
|
||||||
|
|
||||||
The NetBox user account associated with the reservation. Note that users with sufficient permission can make rack reservations for other users.
|
The NetBox user account associated with the reservation. Note that users with sufficient permission can make rack reservations for other users.
|
||||||
|
@ -137,17 +137,29 @@ class RackSerializer(RackBaseSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class RackReservationSerializer(NetBoxModelSerializer):
|
class RackReservationSerializer(NetBoxModelSerializer):
|
||||||
rack = RackSerializer(nested=True)
|
rack = RackSerializer(
|
||||||
user = UserSerializer(nested=True)
|
nested=True,
|
||||||
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
)
|
||||||
|
status = ChoiceField(
|
||||||
|
choices=RackReservationStatusChoices,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
user = UserSerializer(
|
||||||
|
nested=True,
|
||||||
|
)
|
||||||
|
tenant = TenantSerializer(
|
||||||
|
nested=True,
|
||||||
|
required=False,
|
||||||
|
allow_null=True,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display_url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant',
|
'id', 'url', 'display_url', 'display', 'rack', 'units', 'status', 'created', 'last_updated', 'user',
|
||||||
'description', 'comments', 'tags', 'custom_fields',
|
'tenant', 'description', 'comments', 'tags', 'custom_fields',
|
||||||
]
|
]
|
||||||
brief_fields = ('id', 'url', 'display', 'user', 'description', 'units')
|
brief_fields = ('id', 'url', 'display', 'status', 'user', 'description', 'units')
|
||||||
|
|
||||||
|
|
||||||
class RackElevationDetailFilterSerializer(serializers.Serializer):
|
class RackElevationDetailFilterSerializer(serializers.Serializer):
|
||||||
|
@ -139,6 +139,24 @@ class RackAirflowChoices(ChoiceSet):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Rack reservations
|
||||||
|
#
|
||||||
|
|
||||||
|
class RackReservationStatusChoices(ChoiceSet):
|
||||||
|
key = 'RackReservation.status'
|
||||||
|
|
||||||
|
STATUS_PENDING = 'pending'
|
||||||
|
STATUS_ACTIVE = 'active'
|
||||||
|
STATUS_STALE = 'stale'
|
||||||
|
|
||||||
|
CHOICES = [
|
||||||
|
(STATUS_PENDING, _('Pending'), 'cyan'),
|
||||||
|
(STATUS_ACTIVE, _('Active'), 'green'),
|
||||||
|
(STATUS_STALE, _('Stale'), 'orange'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# DeviceTypes
|
# DeviceTypes
|
||||||
#
|
#
|
||||||
|
@ -499,6 +499,10 @@ class RackReservationFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label=_('Location (slug)'),
|
label=_('Location (slug)'),
|
||||||
)
|
)
|
||||||
|
status = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=RackReservationStatusChoices,
|
||||||
|
null_value=None
|
||||||
|
)
|
||||||
user_id = django_filters.ModelMultipleChoiceFilter(
|
user_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=User.objects.all(),
|
queryset=User.objects.all(),
|
||||||
label=_('User (ID)'),
|
label=_('User (ID)'),
|
||||||
|
@ -476,6 +476,12 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
|
|
||||||
class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
|
class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
|
status = forms.ChoiceField(
|
||||||
|
label=_('Status'),
|
||||||
|
choices=add_blank_choice(RackReservationStatusChoices),
|
||||||
|
required=False,
|
||||||
|
initial=''
|
||||||
|
)
|
||||||
user = forms.ModelChoiceField(
|
user = forms.ModelChoiceField(
|
||||||
label=_('User'),
|
label=_('User'),
|
||||||
queryset=User.objects.order_by('username'),
|
queryset=User.objects.order_by('username'),
|
||||||
@ -495,7 +501,7 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
FieldSet('user', 'tenant', 'description'),
|
FieldSet('status', 'user', 'tenant', 'description'),
|
||||||
)
|
)
|
||||||
nullable_fields = ('comments',)
|
nullable_fields = ('comments',)
|
||||||
|
|
||||||
|
@ -358,6 +358,11 @@ class RackReservationImportForm(NetBoxModelImportForm):
|
|||||||
required=True,
|
required=True,
|
||||||
help_text=_('Comma-separated list of individual unit numbers')
|
help_text=_('Comma-separated list of individual unit numbers')
|
||||||
)
|
)
|
||||||
|
status = CSVChoiceField(
|
||||||
|
label=_('Status'),
|
||||||
|
choices=RackReservationStatusChoices,
|
||||||
|
help_text=_('Operational status')
|
||||||
|
)
|
||||||
tenant = CSVModelChoiceField(
|
tenant = CSVModelChoiceField(
|
||||||
label=_('Tenant'),
|
label=_('Tenant'),
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
@ -368,7 +373,7 @@ class RackReservationImportForm(NetBoxModelImportForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = ('site', 'location', 'rack', 'units', 'tenant', 'description', 'comments', 'tags')
|
fields = ('site', 'location', 'rack', 'units', 'status', 'tenant', 'description', 'comments', 'tags')
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
super().__init__(data, *args, **kwargs)
|
super().__init__(data, *args, **kwargs)
|
||||||
|
@ -417,7 +417,7 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
model = RackReservation
|
model = RackReservation
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
FieldSet('q', 'filter_id', 'tag'),
|
FieldSet('q', 'filter_id', 'tag'),
|
||||||
FieldSet('user_id', name=_('User')),
|
FieldSet('status', 'user_id', name=_('Reservation')),
|
||||||
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')),
|
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')),
|
||||||
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
|
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
|
||||||
)
|
)
|
||||||
@ -458,6 +458,11 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
},
|
},
|
||||||
label=_('Rack')
|
label=_('Rack')
|
||||||
)
|
)
|
||||||
|
status = forms.MultipleChoiceField(
|
||||||
|
label=_('Status'),
|
||||||
|
choices=RackReservationStatusChoices,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
user_id = DynamicModelMultipleChoiceField(
|
user_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=User.objects.all(),
|
queryset=User.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -336,14 +336,14 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
FieldSet('rack', 'units', 'user', 'description', 'tags', name=_('Reservation')),
|
FieldSet('rack', 'units', 'status', 'user', 'description', 'tags', name=_('Reservation')),
|
||||||
FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
|
FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = [
|
fields = [
|
||||||
'rack', 'units', 'user', 'tenant_group', 'tenant', 'description', 'comments', 'tags',
|
'rack', 'units', 'status', 'user', 'tenant_group', 'tenant', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
16
netbox/dcim/migrations/0213_rackreservation_status.py
Normal file
16
netbox/dcim/migrations/0213_rackreservation_status.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0212_platform_rebuild'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rackreservation',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(default='active', max_length=50),
|
||||||
|
),
|
||||||
|
]
|
@ -673,6 +673,12 @@ class RackReservation(PrimaryModel):
|
|||||||
verbose_name=_('units'),
|
verbose_name=_('units'),
|
||||||
base_field=models.PositiveSmallIntegerField()
|
base_field=models.PositiveSmallIntegerField()
|
||||||
)
|
)
|
||||||
|
status = models.CharField(
|
||||||
|
verbose_name=_('status'),
|
||||||
|
max_length=50,
|
||||||
|
choices=RackReservationStatusChoices,
|
||||||
|
default=RackReservationStatusChoices.STATUS_ACTIVE
|
||||||
|
)
|
||||||
tenant = models.ForeignKey(
|
tenant = models.ForeignKey(
|
||||||
to='tenancy.Tenant',
|
to='tenancy.Tenant',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
@ -733,6 +739,9 @@ class RackReservation(PrimaryModel):
|
|||||||
def unit_list(self):
|
def unit_list(self):
|
||||||
return array_to_string(self.units)
|
return array_to_string(self.units)
|
||||||
|
|
||||||
|
def get_status_color(self):
|
||||||
|
return RackReservationStatusChoices.colors.get(self.status)
|
||||||
|
|
||||||
def to_objectchange(self, action):
|
def to_objectchange(self, action):
|
||||||
objectchange = super().to_objectchange(action)
|
objectchange = super().to_objectchange(action)
|
||||||
objectchange.related_object = self.rack
|
objectchange.related_object = self.rack
|
||||||
|
@ -229,6 +229,9 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name=_('Units')
|
verbose_name=_('Units')
|
||||||
)
|
)
|
||||||
|
status = columns.ChoiceFieldColumn(
|
||||||
|
verbose_name=_('Status'),
|
||||||
|
)
|
||||||
comments = columns.MarkdownColumn(
|
comments = columns.MarkdownColumn(
|
||||||
verbose_name=_('Comments'),
|
verbose_name=_('Comments'),
|
||||||
)
|
)
|
||||||
@ -239,7 +242,7 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'user', 'created', 'tenant',
|
'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'status', 'user', 'created', 'tenant',
|
||||||
'tenant_group', 'description', 'comments', 'tags', 'actions', 'created', 'last_updated',
|
'tenant_group', 'description', 'comments', 'tags', 'actions', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description')
|
default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'status', 'user', 'description')
|
||||||
|
@ -465,7 +465,7 @@ class RackTest(APIViewTestCases.APIViewTestCase):
|
|||||||
|
|
||||||
class RackReservationTest(APIViewTestCases.APIViewTestCase):
|
class RackReservationTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
brief_fields = ['description', 'display', 'id', 'units', 'url', 'user']
|
brief_fields = ['description', 'display', 'id', 'status', 'units', 'url', 'user']
|
||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
@ -483,9 +483,24 @@ class RackReservationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
Rack.objects.bulk_create(racks)
|
Rack.objects.bulk_create(racks)
|
||||||
|
|
||||||
rack_reservations = (
|
rack_reservations = (
|
||||||
RackReservation(rack=racks[0], units=[1, 2, 3], user=user, description='Reservation #1'),
|
RackReservation(
|
||||||
RackReservation(rack=racks[0], units=[4, 5, 6], user=user, description='Reservation #2'),
|
rack=racks[0],
|
||||||
RackReservation(rack=racks[0], units=[7, 8, 9], user=user, description='Reservation #3'),
|
units=[1, 2, 3],
|
||||||
|
user=user,
|
||||||
|
description='Reservation #1',
|
||||||
|
),
|
||||||
|
RackReservation(
|
||||||
|
rack=racks[0],
|
||||||
|
units=[4, 5, 6],
|
||||||
|
user=user,
|
||||||
|
description='Reservation #2'
|
||||||
|
),
|
||||||
|
RackReservation(
|
||||||
|
rack=racks[0],
|
||||||
|
units=[7, 8, 9],
|
||||||
|
user=user,
|
||||||
|
description='Reservation #3',
|
||||||
|
),
|
||||||
)
|
)
|
||||||
RackReservation.objects.bulk_create(rack_reservations)
|
RackReservation.objects.bulk_create(rack_reservations)
|
||||||
|
|
||||||
@ -493,18 +508,21 @@ class RackReservationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
{
|
{
|
||||||
'rack': racks[1].pk,
|
'rack': racks[1].pk,
|
||||||
'units': [10, 11, 12],
|
'units': [10, 11, 12],
|
||||||
|
'status': RackReservationStatusChoices.STATUS_ACTIVE,
|
||||||
'user': user.pk,
|
'user': user.pk,
|
||||||
'description': 'Reservation #4',
|
'description': 'Reservation #4',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rack': racks[1].pk,
|
'rack': racks[1].pk,
|
||||||
'units': [13, 14, 15],
|
'units': [13, 14, 15],
|
||||||
|
'status': RackReservationStatusChoices.STATUS_PENDING,
|
||||||
'user': user.pk,
|
'user': user.pk,
|
||||||
'description': 'Reservation #5',
|
'description': 'Reservation #5',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rack': racks[1].pk,
|
'rack': racks[1].pk,
|
||||||
'units': [16, 17, 18],
|
'units': [16, 17, 18],
|
||||||
|
'status': RackReservationStatusChoices.STATUS_STALE,
|
||||||
'user': user.pk,
|
'user': user.pk,
|
||||||
'description': 'Reservation #6',
|
'description': 'Reservation #6',
|
||||||
},
|
},
|
||||||
|
@ -1141,9 +1141,30 @@ class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
Tenant.objects.bulk_create(tenants)
|
Tenant.objects.bulk_create(tenants)
|
||||||
|
|
||||||
reservations = (
|
reservations = (
|
||||||
RackReservation(rack=racks[0], units=[1, 2, 3], user=users[0], tenant=tenants[0], description='foobar1'),
|
RackReservation(
|
||||||
RackReservation(rack=racks[1], units=[4, 5, 6], user=users[1], tenant=tenants[1], description='foobar2'),
|
rack=racks[0],
|
||||||
RackReservation(rack=racks[2], units=[7, 8, 9], user=users[2], tenant=tenants[2], description='foobar3'),
|
units=[1, 2, 3],
|
||||||
|
status=RackReservationStatusChoices.STATUS_ACTIVE,
|
||||||
|
user=users[0],
|
||||||
|
tenant=tenants[0],
|
||||||
|
description='foobar1',
|
||||||
|
),
|
||||||
|
RackReservation(
|
||||||
|
rack=racks[1],
|
||||||
|
units=[4, 5, 6],
|
||||||
|
status=RackReservationStatusChoices.STATUS_PENDING,
|
||||||
|
user=users[1],
|
||||||
|
tenant=tenants[1],
|
||||||
|
description='foobar2',
|
||||||
|
),
|
||||||
|
RackReservation(
|
||||||
|
rack=racks[2],
|
||||||
|
units=[7, 8, 9],
|
||||||
|
status=RackReservationStatusChoices.STATUS_STALE,
|
||||||
|
user=users[2],
|
||||||
|
tenant=tenants[2],
|
||||||
|
description='foobar3',
|
||||||
|
),
|
||||||
)
|
)
|
||||||
RackReservation.objects.bulk_create(reservations)
|
RackReservation.objects.bulk_create(reservations)
|
||||||
|
|
||||||
@ -1179,6 +1200,10 @@ class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'location': [locations[0].slug, locations[1].slug]}
|
params = {'location': [locations[0].slug, locations[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_status(self):
|
||||||
|
params = {'status': [RackReservationStatusChoices.STATUS_ACTIVE, RackReservationStatusChoices.STATUS_PENDING]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_user(self):
|
def test_user(self):
|
||||||
users = User.objects.all()[:2]
|
users = User.objects.all()[:2]
|
||||||
params = {'user_id': [users[0].pk, users[1].pk]}
|
params = {'user_id': [users[0].pk, users[1].pk]}
|
||||||
|
@ -337,6 +337,7 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
cls.form_data = {
|
cls.form_data = {
|
||||||
'rack': rack.pk,
|
'rack': rack.pk,
|
||||||
'units': "10,11,12",
|
'units': "10,11,12",
|
||||||
|
'status': RackReservationStatusChoices.STATUS_PENDING,
|
||||||
'user': user3.pk,
|
'user': user3.pk,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
'description': 'Rack reservation',
|
'description': 'Rack reservation',
|
||||||
@ -344,10 +345,10 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
cls.csv_data = (
|
cls.csv_data = (
|
||||||
'site,location,rack,units,description',
|
'site,location,rack,units,status,description',
|
||||||
'Site 1,Location 1,Rack 1,"10,11,12",Reservation 1',
|
'Site 1,Location 1,Rack 1,"10,11,12",active,Reservation 1',
|
||||||
'Site 1,Location 1,Rack 1,"13,14,15",Reservation 2',
|
'Site 1,Location 1,Rack 1,"13,14,15",pending,Reservation 2',
|
||||||
'Site 1,Location 1,Rack 1,"16,17,18",Reservation 3',
|
'Site 1,Location 1,Rack 1,"16,17,18",stale,Reservation 3',
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.csv_update_data = (
|
cls.csv_update_data = (
|
||||||
@ -358,6 +359,7 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
|
'status': RackReservationStatusChoices.STATUS_STALE,
|
||||||
'user': user3.pk,
|
'user': user3.pk,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
|
@ -13,83 +13,87 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col col-12 col-xl-5">
|
<div class="col col-12 col-xl-5">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2 class="card-header">{% trans "Rack" %}</h2>
|
<h2 class="card-header">{% trans "Rack" %}</h2>
|
||||||
<table class="table table-hover attr-table">
|
<table class="table table-hover attr-table">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Region" %}</th>
|
<th scope="row">{% trans "Region" %}</th>
|
||||||
<td>
|
<td>
|
||||||
{% nested_tree object.rack.site.region %}
|
{% nested_tree object.rack.site.region %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Site" %}</th>
|
<th scope="row">{% trans "Site" %}</th>
|
||||||
<td>{{ object.rack.site|linkify }}</td>
|
<td>{{ object.rack.site|linkify }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Location" %}</th>
|
<th scope="row">{% trans "Location" %}</th>
|
||||||
<td>{{ object.rack.location|linkify|placeholder }}</td>
|
<td>{{ object.rack.location|linkify|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Rack" %}</th>
|
<th scope="row">{% trans "Rack" %}</th>
|
||||||
<td>{{ object.rack|linkify }}</td>
|
<td>{{ object.rack|linkify }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2 class="card-header">{% trans "Reservation Details" %}</h2>
|
<h2 class="card-header">{% trans "Reservation Details" %}</h2>
|
||||||
<table class="table table-hover attr-table">
|
<table class="table table-hover attr-table">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Units" %}</th>
|
<th scope="row">{% trans "Units" %}</th>
|
||||||
<td>{{ object.unit_list }}</td>
|
<td>{{ object.unit_list }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
<th scope="row">{% trans "Status" %}</th>
|
||||||
<td>
|
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
||||||
{% if object.tenant.group %}
|
</tr>
|
||||||
{{ object.tenant.group|linkify }} /
|
<tr>
|
||||||
{% endif %}
|
<th scope="row">{% trans "Tenant" %}</th>
|
||||||
{{ object.tenant|linkify|placeholder }}
|
<td>
|
||||||
</td>
|
{% if object.tenant.group %}
|
||||||
</tr>
|
{{ object.tenant.group|linkify }} /
|
||||||
<tr>
|
{% endif %}
|
||||||
<th scope="row">{% trans "User" %}</th>
|
{{ object.tenant|linkify|placeholder }}
|
||||||
<td>{{ object.user }}</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
<th scope="row">{% trans "User" %}</th>
|
||||||
<td>{{ object.description }}</td>
|
<td>{{ object.user }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
<tr>
|
||||||
</div>
|
<th scope="row">{% trans "Description" %}</th>
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
<td>{{ object.description }}</td>
|
||||||
{% include 'inc/panels/tags.html' %}
|
</tr>
|
||||||
{% include 'inc/panels/comments.html' %}
|
</table>
|
||||||
{% plugin_left_page object %}
|
</div>
|
||||||
</div>
|
{% include 'inc/panels/custom_fields.html' %}
|
||||||
<div class="col col-12 col-xl-7">
|
{% include 'inc/panels/tags.html' %}
|
||||||
|
{% include 'inc/panels/comments.html' %}
|
||||||
|
{% plugin_left_page object %}
|
||||||
|
</div>
|
||||||
|
<div class="col col-12 col-xl-7">
|
||||||
<div class="row" style="margin-bottom: 20px">
|
<div class="row" style="margin-bottom: 20px">
|
||||||
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
|
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
|
||||||
<div style="margin-left: 30px">
|
<div style="margin-left: 30px">
|
||||||
<h2 class="h4">{% trans "Front" %}</h2>
|
<h2 class="h4">{% trans "Front" %}</h2>
|
||||||
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='front' %}
|
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='front' %}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
|
</div>
|
||||||
<div style="margin-left: -30px">
|
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
|
||||||
<h2 class="h4">{% trans "Rear" %}</h2>
|
<div style="margin-left: -30px">
|
||||||
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' %}
|
<h2 class="h4">{% trans "Rear" %}</h2>
|
||||||
</div>
|
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% plugin_right_page object %}
|
{% plugin_right_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-md-12">
|
<div class="col col-md-12">
|
||||||
{% plugin_full_width_page object %}
|
{% plugin_full_width_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user