mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Closes #33: Add ability to clone objects (pre-populate form fields)
This commit is contained in:
parent
47fefbec07
commit
446acbdf82
@ -127,6 +127,7 @@ PATCH) to maintain backward compatibility. This behavior will be discontinued be
|
||||
|
||||
## Enhancements
|
||||
|
||||
* [#33](https://github.com/digitalocean/netbox/issues/33) - Add ability to clone objects (pre-populate form fields)
|
||||
* [#792](https://github.com/digitalocean/netbox/issues/792) - Add power port and power outlet types
|
||||
* [#1865](https://github.com/digitalocean/netbox/issues/1865) - Add console port and console server port types
|
||||
* [#2902](https://github.com/digitalocean/netbox/issues/2902) - Replace `supervisord` with `systemd`
|
||||
|
@ -57,7 +57,12 @@ class Provider(ChangeLoggedModel, CustomFieldModel):
|
||||
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
csv_headers = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
|
||||
csv_headers = [
|
||||
'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
@ -171,6 +176,9 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
|
||||
csv_headers = [
|
||||
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
CircuitStatusChoices.STATUS_DEPROVISIONING: 'warning',
|
||||
|
@ -331,6 +331,10 @@ class Site(ChangeLoggedModel, CustomFieldModel):
|
||||
'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description', 'physical_address',
|
||||
'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone', 'contact_email', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description', 'physical_address',
|
||||
'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone', 'contact_email',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
SiteStatusChoices.STATUS_ACTIVE: 'success',
|
||||
@ -559,6 +563,10 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
|
||||
'site', 'group_name', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag', 'width',
|
||||
'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'site', 'group', 'tenant', 'status', 'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
|
||||
'outer_depth', 'outer_unit',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
RackStatusChoices.STATUS_RESERVED: 'warning',
|
||||
@ -948,6 +956,9 @@ class DeviceType(ChangeLoggedModel, CustomFieldModel):
|
||||
csv_headers = [
|
||||
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
ordering = ['manufacturer', 'model']
|
||||
@ -1617,6 +1628,9 @@ class Device(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
|
||||
'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status',
|
||||
'site', 'rack_group', 'rack_name', 'position', 'face', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'device_type', 'device_role', 'tenant', 'platform', 'site', 'rack', 'status', 'cluster',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
DeviceStatusChoices.STATUS_OFFLINE: 'warning',
|
||||
@ -3159,6 +3173,10 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel):
|
||||
'site', 'panel_name', 'rack_group', 'rack_name', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
|
||||
'amperage', 'max_utilization', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'power_panel', 'rack', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization',
|
||||
'available_power',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
PowerFeedStatusChoices.STATUS_OFFLINE: 'warning',
|
||||
|
@ -78,6 +78,9 @@ class VRF(ChangeLoggedModel, CustomFieldModel):
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
csv_headers = ['name', 'rd', 'tenant', 'enforce_unique', 'description']
|
||||
clone_fields = [
|
||||
'tenant', 'enforce_unique', 'description',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
ordering = ['name', 'rd']
|
||||
@ -177,6 +180,9 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
csv_headers = ['prefix', 'rir', 'date_added', 'description']
|
||||
clone_fields = [
|
||||
'rir', 'date_added', 'description',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
ordering = ['family', 'prefix']
|
||||
@ -350,6 +356,9 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
||||
csv_headers = [
|
||||
'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description',
|
||||
]
|
||||
clone_fields = [
|
||||
'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'description',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
'container': 'default',
|
||||
@ -627,6 +636,9 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
|
||||
'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface_name', 'is_primary',
|
||||
'dns_name', 'description',
|
||||
]
|
||||
clone_fields = [
|
||||
'vrf', 'tenant', 'status', 'role', 'description',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
'active': 'primary',
|
||||
@ -898,6 +910,9 @@ class VLAN(ChangeLoggedModel, CustomFieldModel):
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
csv_headers = ['site', 'group_name', 'vid', 'name', 'tenant', 'status', 'role', 'description']
|
||||
clone_fields = [
|
||||
'site', 'group', 'tenant', 'status', 'role', 'description',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
'active': 'primary',
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -27,6 +28,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.circuits.add_circuit %}
|
||||
{% clone_button 'circuits:circuit_add' circuit %}
|
||||
{% endif %}
|
||||
{% if perms.circuits.change_circuit %}
|
||||
<a href="{% url 'circuits:circuit_edit' pk=circuit.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load static %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
@ -33,6 +34,9 @@
|
||||
Graphs
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.circuits.add_provider %}
|
||||
{% clone_button 'circuits:provider_add' provider %}
|
||||
{% endif %}
|
||||
{% if perms.circuits.change_provider %}
|
||||
<a href="{% url 'circuits:provider_edit' slug=provider.slug %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
{% load custom_links %}
|
||||
@ -57,6 +58,11 @@
|
||||
{% if perms.dcim.add_devicebay %}<li><a href="{% url 'dcim:devicebay_add' pk=device.pk %}">Device Bays</a></li>{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if perms.dcim.add_device %}
|
||||
{% clone_button 'dcim:device_add' device %}
|
||||
{% endif %}
|
||||
{% if perms.dcim.change_device %}
|
||||
<a href="{% url 'dcim:device_edit' pk=device.pk %}" class="btn btn-warning">
|
||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
|
||||
Edit this device
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -14,37 +15,40 @@
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.change_devicetype or perms.dcim.delete_devicetype %}
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.dcim.change_devicetype %}
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Components <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% if perms.dcim.add_consoleporttemplate %}<li><a href="{% url 'dcim:devicetype_add_consoleport' pk=devicetype.pk %}">Console Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_consoleserverporttemplate %}<li><a href="{% url 'dcim:devicetype_add_consoleserverport' pk=devicetype.pk %}">Console Server Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_powerporttemplate %}<li><a href="{% url 'dcim:devicetype_add_powerport' pk=devicetype.pk %}">Power Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_poweroutlettemplate %}<li><a href="{% url 'dcim:devicetype_add_poweroutlet' pk=devicetype.pk %}">Power Outlets</a></li>{% endif %}
|
||||
{% if perms.dcim.add_interfacetemplate %}<li><a href="{% url 'dcim:devicetype_add_interface' pk=devicetype.pk %}">Interfaces</a></li>{% endif %}
|
||||
{% if perms.dcim.add_frontporttemplate %}<li><a href="{% url 'dcim:devicetype_add_frontport' pk=devicetype.pk %}">Front Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_rearporttemplate %}<li><a href="{% url 'dcim:devicetype_add_rearport' pk=devicetype.pk %}">Rear Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_devicebaytemplate %}<li><a href="{% url 'dcim:devicetype_add_devicebay' pk=devicetype.pk %}">Device Bays</a></li>{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<a href="{% url 'dcim:devicetype_edit' pk=devicetype.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
Edit this device type
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.dcim.delete_devicetype %}
|
||||
<a href="{% url 'dcim:devicetype_delete' pk=devicetype.pk %}" class="btn btn-danger">
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.dcim.change_devicetype %}
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Components <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% if perms.dcim.add_consoleporttemplate %}<li><a href="{% url 'dcim:devicetype_add_consoleport' pk=devicetype.pk %}">Console Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_consoleserverporttemplate %}<li><a href="{% url 'dcim:devicetype_add_consoleserverport' pk=devicetype.pk %}">Console Server Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_powerporttemplate %}<li><a href="{% url 'dcim:devicetype_add_powerport' pk=devicetype.pk %}">Power Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_poweroutlettemplate %}<li><a href="{% url 'dcim:devicetype_add_poweroutlet' pk=devicetype.pk %}">Power Outlets</a></li>{% endif %}
|
||||
{% if perms.dcim.add_interfacetemplate %}<li><a href="{% url 'dcim:devicetype_add_interface' pk=devicetype.pk %}">Interfaces</a></li>{% endif %}
|
||||
{% if perms.dcim.add_frontporttemplate %}<li><a href="{% url 'dcim:devicetype_add_frontport' pk=devicetype.pk %}">Front Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_rearporttemplate %}<li><a href="{% url 'dcim:devicetype_add_rearport' pk=devicetype.pk %}">Rear Ports</a></li>{% endif %}
|
||||
{% if perms.dcim.add_devicebaytemplate %}<li><a href="{% url 'dcim:devicetype_add_devicebay' pk=devicetype.pk %}">Device Bays</a></li>{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if perms.dcim.add_devicetype %}
|
||||
{% clone_button 'dcim:devicetype_add' devicetype %}
|
||||
{% endif %}
|
||||
{% if perms.dcim.change_devicetype %}
|
||||
<a href="{% url 'dcim:devicetype_edit' pk=devicetype.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
Edit this device type
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.dcim.delete_devicetype %}
|
||||
<a href="{% url 'dcim:devicetype_delete' pk=devicetype.pk %}" class="btn btn-danger">
|
||||
<span class="fa fa-trash" aria-hidden="true"></span>
|
||||
Delete this device type
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h1>{{ devicetype.manufacturer }} {{ devicetype.model }}</h1>
|
||||
{% include 'inc/created_updated.html' with obj=devicetype %}
|
||||
<div class="pull-right noprint">
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load static %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
@ -30,6 +31,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.dcim.add_powerfeed %}
|
||||
{% clone_button 'dcim:powerfeed_add' powerfeed %}
|
||||
{% endif %}
|
||||
{% if perms.dcim.change_powerfeed %}
|
||||
<a href="{% url 'dcim:powerfeed_edit' pk=powerfeed.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -31,6 +32,9 @@
|
||||
<a {% if next_rack %}href="{% url 'dcim:rack' pk=next_rack.pk %}"{% else %}disabled="disabled"{% endif %} class="btn btn-primary">
|
||||
<span class="fa fa-chevron-right" aria-hidden="true"></span> Next Rack
|
||||
</a>
|
||||
{% if perms.dcim.add_rack %}
|
||||
{% clone_button 'dcim:rack_add' rack %}
|
||||
{% endif %}
|
||||
{% if perms.dcim.change_rack %}
|
||||
<a href="{% url 'dcim:rack_edit' pk=rack.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span> Edit this rack
|
||||
|
@ -1,8 +1,9 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load static %}
|
||||
{% load tz %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load tz %}
|
||||
|
||||
{% block header %}
|
||||
<div class="row noprint">
|
||||
@ -38,6 +39,9 @@
|
||||
Graphs
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.add_site %}
|
||||
{% clone_button 'dcim:site_add' site %}
|
||||
{% endif %}
|
||||
{% if perms.dcim.change_site %}
|
||||
<a href="{% url 'dcim:site_edit' slug=site.slug %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -25,6 +26,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.ipam.add_aggregate %}
|
||||
{% clone_button 'ipam:aggregate_add' aggregate %}
|
||||
{% endif %}
|
||||
{% if perms.ipam.change_aggregate %}
|
||||
<a href="{% url 'ipam:aggregate_edit' pk=aggregate.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -27,6 +28,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.ipam.add_ipaddress %}
|
||||
{% clone_button 'ipam:ipaddress_add' ipaddress %}
|
||||
{% endif %}
|
||||
{% if perms.ipam.change_ipaddress %}
|
||||
<a href="{% url 'ipam:ipaddress_edit' pk=ipaddress.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -38,6 +39,9 @@
|
||||
Add an IP Address
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.ipam.add_prefix %}
|
||||
{% clone_button 'ipam:prefix_add' prefix %}
|
||||
{% endif %}
|
||||
{% if perms.ipam.change_prefix %}
|
||||
<a href="{% url 'ipam:prefix_edit' pk=prefix.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -30,6 +31,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.ipam.add_vlan %}
|
||||
{% clone_button 'ipam:vlan_add' vlan %}
|
||||
{% endif %}
|
||||
{% if perms.ipam.change_vlan %}
|
||||
<a href="{% url 'ipam:vlan_edit' pk=vlan.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -24,6 +25,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.ipam.add_vrf %}
|
||||
{% clone_button 'ipam:vrf_add' vrf %}
|
||||
{% endif %}
|
||||
{% if perms.ipam.change_vrf %}
|
||||
<a href="{% url 'ipam:vrf_edit' pk=vrf.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -27,6 +28,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.tenancy.add_tenant %}
|
||||
{% clone_button 'tenancy:tenant_add' tenant %}
|
||||
{% endif %}
|
||||
{% if perms.tenancy.change_tenant %}
|
||||
<a href="{% url 'tenancy:tenant_edit' slug=tenant.slug %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -27,6 +28,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.virtualization.add_cluster %}
|
||||
{% clone_button 'virtualization:cluster_add' cluster %}
|
||||
{% endif %}
|
||||
{% if perms.virtualization.change_cluster %}
|
||||
<a href="{% url 'virtualization:cluster_edit' pk=cluster.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load buttons %}
|
||||
{% load custom_links %}
|
||||
{% load helpers %}
|
||||
|
||||
@ -26,6 +27,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right noprint">
|
||||
{% if perms.virtualization.add_virtualmachine %}
|
||||
{% clone_button 'virtualization:virtualmachine_add' virtualmachine %}
|
||||
{% endif %}
|
||||
{% if perms.virtualization.change_virtualmachine %}
|
||||
<a href="{% url 'virtualization:virtualmachine_edit' pk=virtualmachine.pk %}" class="btn btn-warning">
|
||||
<span class="fa fa-pencil"></span>
|
||||
|
@ -73,6 +73,9 @@ class Tenant(ChangeLoggedModel, CustomFieldModel):
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
csv_headers = ['name', 'slug', 'group', 'description', 'comments']
|
||||
clone_fields = [
|
||||
'group', 'description',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
ordering = ['group', 'name']
|
||||
|
3
netbox/utilities/templates/buttons/clone.html
Normal file
3
netbox/utilities/templates/buttons/clone.html
Normal file
@ -0,0 +1,3 @@
|
||||
<a href="{{ url }}" class="btn btn-success">
|
||||
<span class="fa fa-plus" aria-hidden="true"></span> Clone
|
||||
</a>
|
@ -1,4 +1,5 @@
|
||||
from django import template
|
||||
from django.urls import reverse
|
||||
|
||||
from extras.models import ExportTemplate
|
||||
|
||||
@ -7,12 +8,47 @@ register = template.Library()
|
||||
|
||||
@register.inclusion_tag('buttons/add.html')
|
||||
def add_button(url):
|
||||
return {'add_url': url}
|
||||
return {
|
||||
'add_url': url,
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag('buttons/import.html')
|
||||
def import_button(url):
|
||||
return {'import_url': url}
|
||||
return {
|
||||
'import_url': url,
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag('buttons/clone.html')
|
||||
def clone_button(url, instance):
|
||||
|
||||
url = reverse(url)
|
||||
|
||||
# Populate form field values
|
||||
params = {}
|
||||
for field_name in getattr(instance, 'clone_fields', []):
|
||||
field = instance._meta.get_field(field_name)
|
||||
field_value = field.value_from_object(instance)
|
||||
|
||||
# Swap out False with URL-friendly value
|
||||
if field_value is False:
|
||||
field_value = ''
|
||||
|
||||
# Omit empty values
|
||||
if field_value not in (None, ''):
|
||||
params[field_name] = field_value
|
||||
|
||||
# TODO: Tag replication
|
||||
|
||||
# Append parameters to URL
|
||||
param_string = '&'.join(['{}={}'.format(k, v) for k, v in params.items()])
|
||||
if param_string:
|
||||
url = '{}?{}'.format(url, param_string)
|
||||
|
||||
return {
|
||||
'url': url,
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag('buttons/export.html', takes_context=True)
|
||||
|
@ -129,6 +129,9 @@ class Cluster(ChangeLoggedModel, CustomFieldModel):
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
csv_headers = ['name', 'type', 'group', 'site', 'comments']
|
||||
clone_fields = [
|
||||
'type', 'group', 'tenant', 'site',
|
||||
]
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
@ -252,6 +255,9 @@ class VirtualMachine(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
|
||||
csv_headers = [
|
||||
'name', 'status', 'role', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments',
|
||||
]
|
||||
clone_fields = [
|
||||
'cluster', 'tenant', 'platform', 'status', 'role', 'vcpus', 'memory', 'disk',
|
||||
]
|
||||
|
||||
STATUS_CLASS_MAP = {
|
||||
'active': 'success',
|
||||
|
Loading…
Reference in New Issue
Block a user