Merge branch 'feat-2024-05-17' into 'development'

feat: 2024 05 17

See merge request nofusscomputing/projects/django_template!5
This commit is contained in:
2024-05-17 14:18:04 +00:00
27 changed files with 456 additions and 62 deletions

View File

@ -8,7 +8,7 @@ Unit:
- pip install -r requirements.txt
- pip install -r requirements_test.txt
- cd app
- pytest --cov --cov-report term --cov-report xml:../artifacts/coverage.xml --cov-report html:../artifacts/coverage/ --junit-xml=../artifacts/test.junit.xml
- pytest --cov --cov-report term --cov-report xml:../artifacts/coverage.xml --cov-report html:../artifacts/coverage/ --junit-xml=../artifacts/test.JUnit.xml
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
artifacts:
expire_in: "30 days"

View File

@ -0,0 +1,22 @@
from django import forms
from django.db.models import Q
from itam.models.device import DeviceSoftware
from itam.models.software import Software, SoftwareVersion
class SoftwareUpdate(forms.ModelForm):
class Meta:
model = DeviceSoftware
fields = [
'action',
'version',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['version'].queryset = SoftwareVersion.objects.filter(software_id=self.instance.software.id)

View File

@ -0,0 +1,18 @@
# Generated by Django 5.0.6 on 2024-05-17 10:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('itam', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='softwareversion',
name='name',
field=models.CharField(max_length=50),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.0.6 on 2024-05-17 10:18
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('itam', '0002_alter_softwareversion_name'),
]
operations = [
migrations.AddField(
model_name='devicesoftware',
name='version',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='itam.softwareversion'),
),
]

View File

@ -2,7 +2,7 @@ from django.db import models
from access.fields import *
from access.models import TenancyObject
from itam.models.software import Software
from itam.models.software import Software, SoftwareVersion
@ -98,11 +98,19 @@ class Device(DeviceCommonFieldsName):
state = 'absent'
software = {
print(f"here: {software.version}")
software_action = {
"name": software.software.slug,
"state": state
}
config['software'] = config['software'] + [ software ]
if software.version:
software_action['version'] = software.version.name
config['software'] = config['software'] + [ software_action ]
return config
@ -140,3 +148,12 @@ class DeviceSoftware(DeviceCommonFields):
choices=Actions,
default=None,
)
version = models.ForeignKey(
SoftwareVersion,
on_delete=models.CASCADE,
default = None,
null = True,
blank= True
)

View File

@ -62,5 +62,15 @@ class SoftwareVersion(SoftwareCommonFields):
on_delete=models.CASCADE,
)
name = models.CharField(
blank = False,
max_length = 50,
unique = False,
)
def __str__(self):
return self.name

View File

@ -30,8 +30,10 @@
</script>
<div class="tab">
<button onclick="window.location='{% url 'ITAM:Devices' %}';">
<< Back to Devices</button>
<button onclick="window.location='{% url 'ITAM:Devices' %}';" style="vertical-align: middle; padding: auto; margin: 0px">
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px" style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z"/>
</svg> Back to Devices</button>
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'OperatingSystem')">Operating System</button>
<button class="tablinks" onclick="openCity(event, 'Software')">Software</button>
@ -67,17 +69,31 @@
<thead>
<th>Name</th>
<th>Action</th>
<th>Version</th>
<th>Installed</th>
<th>&nbsp;</th>
</thead>
{% if softwares %}
{% for software in softwares %}
<tr>
<td><a href="{% url 'ITAM:_software_view' pk=software.id %}">{{ software.software }}</a></td>
<td><a href="{% url 'ITAM:_software_view' pk=software.software_id %}">{{ software.software }}</a></td>
<td><a href="{% url 'ITAM:_device_software_view' device_id=device.id pk=software.id %}">{{ software.get_action_display }}</a></td>
<td>
{% if software.version %}
{{ software.version }}
{% else %}
Any
{% endif %}
</td>
<td>
{% include 'icons/issue_link.html.j2' with issue=2 %}
</td>
<td>&nbsp;</td>
<th>&nbsp;</th>
</tr>
{% endfor %}
{% else %}
<td colspan="5">Nothing Found {% include 'icons/issue_link.html.j2' with issue=2 %}</td>
{% endif %}
</table>
</div>

View File

@ -28,4 +28,22 @@
{% endfor %}
</table>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">&laquo; first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
{% endif %}
</span>
</div>
{% endblock %}

View File

@ -30,8 +30,10 @@
</script>
<div class="tab">
<button onclick="window.location='{% url 'ITAM:Software' %}';">
<< Back to Software</button>
<button onclick="window.location='{% url 'ITAM:Software' %}';" style="vertical-align: middle; padding: auto; margin: 0px">
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px" style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z"/>
</svg> Back to Software</button>
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Versions')">Versions</button>
<button class="tablinks" onclick="openCity(event, 'Licences')">Licences</button>
@ -56,7 +58,7 @@
<div id="Versions" class="tabcontent">
<h3>Versions</h3>
Not Yet Implemented
<input type="button" value="New Software Version" onclick="window.location='{% url 'ITAM:_software_version_add' pk=software.id %}';">
<table>
<thead>
<th>Version</th>
@ -65,16 +67,19 @@
<th>&nbsp;</th>
</thead>
<tr>
<td>1.0.0</td>
<td>5</td>
<td><input type="checkbox" checked disabled></td>
{% for version in software_versions %}
<td>{{ version.name }}</td>
<td>{% include 'icons/issue_link.html.j2' with issue=2 %}</td>
<td>{% include 'icons/issue_link.html.j2' with issue=3 %}</td>
<td>&nbsp;</td>
{% endfor %}
</tr>
</table>
</div>
<div id="Licences" class="tabcontent">
<h3>Licences</h3>
Not Yet Implemented
{% include 'icons/issue_link.html.j2' with issue=4 %}
<table>
<thead>
<th>Name</th>
@ -105,24 +110,45 @@
<div id="Installations" class="tabcontent">
<h3>Installations</h3>
Dev Notes: This table will show joined tables installed software and device software action as a single row.
<table>
<thead>
<th>Device</th>
<th>Organization</th>
<th title="Not Set/Install/Remove">Action</th>
<th>Version</th>
<th title="Date Software Installed">Installed</th>
<th>&nbsp;</th>
</thead>
{% if device_software %}
{% for device in device_software %}
<tr>
<td><a href="{% url 'ITAM:_device_view' pk=device.device.id %}">{{ device.device }}</a></td>
<td>{{ device.organization }}</td>
<td>{{ device.get_action_display }}</td>
<td>Not Implemented</td>
<td>
{% if device.get_action_display == 'Install' %}
{% include 'icons/success_text.html.j2' with icon_text=device.get_action_display %}
{% elif device.get_action_display == 'Remove'%}
{% include 'icons/cross_text.html.j2' with icon_text=device.get_action_display %}
{% else %}
{{ device.get_action_display }}
{% endif %}
</td>
<td>
{% if device.version %}
{{ device.version }}
{% else %}
Any
{% endif %}
</td>
<td>{% include 'icons/issue_link.html.j2' with issue=2 %}</td>
<td>&nbsp;</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6">Nothing Found</td>
</tr>
{% endif %}
</table>
</div>

View File

@ -26,4 +26,23 @@
{% endfor %}
</table>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">&laquo; first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
{% endif %}
</span>
</div>
{% endblock %}

View File

@ -20,3 +20,11 @@ def test_device_software_action(user):
"""Ensure only software that is from the same organization or is global can be added to the device
"""
pass
@pytest.mark.skip(reason="to be written")
def test_device_not_global(user):
"""Devices are not global items.
Ensure that a device can't be set to be global.
"""
pass

View File

@ -20,3 +20,12 @@ def test_software_update_is_global_no_change(user):
"""
pass
@pytest.mark.skip(reason="to be written")
def test_software_prevent_delete_if_used(user):
"""Any software in use by a device must not be deleted.
i.e. A device has an action set for the software.
"""
pass

View File

@ -1,7 +1,7 @@
from django.urls import path
from . import views
from .views import device, device_type, software, software_category
from .views import device, device_type, software, software_category, software_version
app_name = "ITAM"
urlpatterns = [
@ -20,6 +20,7 @@ urlpatterns = [
path("software/", software.IndexView.as_view(), name="Software"),
path("software/<int:pk>/", software.View.as_view(), name="_software_view"),
path("software/<int:pk>/delete", software.Delete.as_view(), name="_software_delete"),
path("software/<int:pk>/version/add", software_version.Add.as_view(), name="_software_version_add"),
path("software/add/", software.Add.as_view(), name="_software_add"),
path("software_category/add/", software_category.Add.as_view(), name="_software_category_add"),

View File

@ -9,6 +9,7 @@ from access.models import Organization
from ..models.device import Device, DeviceSoftware
from itam.forms.device_softwareadd import SoftwareAdd
from itam.forms.device_softwareupdate import SoftwareUpdate
class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListView):
@ -17,6 +18,8 @@ class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListVie
template_name = 'itam/device_index.html.j2'
context_object_name = "devices"
paginate_by = 10
def get_queryset(self):
if self.request.user.is_superuser:
@ -42,7 +45,6 @@ class View(OrganizationPermission, generic.UpdateView):
'serial_number',
'uuid',
'device_type',
'is_global'
]
context_object_name = "device"
@ -74,13 +76,12 @@ class SoftwareView(OrganizationPermission, generic.UpdateView):
]
template_name = 'form.html.j2'
fields = [
'action',
]
context_object_name = "devicesoftware"
form_class = SoftwareUpdate
def form_valid(self, form):
device = Device.objects.get(pk=self.kwargs['device_id'])
@ -108,9 +109,12 @@ class Add(PermissionRequiredMixin, OrganizationPermission, generic.CreateView):
'uuid',
'device_type',
'organization',
'is_global'
]
def form_valid(self, form):
form.instance.is_global = False
return super().form_valid(form)
def get_success_url(self, **kwargs):

View File

@ -5,7 +5,7 @@ from django.views import generic
from access.mixin import OrganizationPermission
from itam.models.device import DeviceSoftware
from itam.models.software import Software
from itam.models.software import Software, SoftwareVersion
from itam.forms.software.update import Update as SoftwareUpdate_Form
class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListView):
@ -13,6 +13,7 @@ class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListVie
permission_required = 'itam.view_software'
template_name = 'itam/software_index.html.j2'
context_object_name = "softwares"
paginate_by = 10
def get_queryset(self):
@ -42,6 +43,10 @@ class View(OrganizationPermission, generic.UpdateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
software_versions = SoftwareVersion.objects.filter(software=self.kwargs['pk'])
context['software_versions'] = software_versions
context['content_title'] = self.object.name
if self.request.user.is_superuser:

View File

@ -0,0 +1,39 @@
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views import generic
from access.mixin import OrganizationPermission
from ..models.software import Software, SoftwareVersion
class Add(PermissionRequiredMixin, OrganizationPermission, generic.CreateView):
model = SoftwareVersion
permission_required = [
'access.add_softwareversion',
]
template_name = 'form.html.j2'
fields = [
'name'
]
def form_valid(self, form):
software = Software.objects.get(pk=self.kwargs['pk'])
form.instance.is_global = software.is_global
form.instance.organization_id = software.organization.id
form.instance.software_id = self.kwargs['pk']
return super().form_valid(form)
def get_success_url(self, **kwargs):
return f"/itam/software/{self.kwargs['pk']}/"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['content_title'] = 'Add Software Version'
return context

View File

@ -41,6 +41,81 @@ span#content_header_icon {
color: #177ee6;
}
span.icon-text {
vertical-align: middle;
border-radius: 25px;
font-size: inherit;
border: 1px solid #ccc;
line-height: 30px;
padding-left: 1px;
padding-right: 10px;
height: 30px;
display: inline-block;
}
span.success {
color: #319c3a;
}
span.icon-success {
fill: #319c3a;
height: 30px;
line-height: 30px;
margin: 0px;
margin-bottom: -7px;
padding: 0px;
vertical-align: middle;
display: inline-block;
}
span.cross {
color: #9c3131;
}
span.icon-cross {
fill: #9c3131;
height: 30px;
line-height: 30px;
margin: 0px;
margin-bottom: -7px;
padding: 0px;
vertical-align: middle;
display: inline-block;
}
span.change {
color: #cab706;
}
span.icon-change {
fill: #cab706;
height: 30px;
line-height: 30px;
margin: 0px;
margin-bottom: -7px;
padding: 0px;
vertical-align: middle;
display: inline-block;
}
/* span.issue {
color: #fc6d26;
} */
span.icon-issue {
fill: #fc6d26;
height: 30px;
line-height: 30px;
margin: 0px;
/* margin-bottom: -2px; */
padding: 0px;
vertical-align: middle;
display: inline-block;
}
/* .icon {
display: block;
content: none;

View File

@ -115,6 +115,14 @@ input[type=submit] {
/* background-color: #f1f1f1; */
width: 100%;
text-align: left;
padding: 0px;
margin: 0px
}
.tablinks {
border: 0px;
margin: none;
padding: none;
}
/* Style the buttons that are used to open the tab content */
@ -125,9 +133,12 @@ input[type=submit] {
border: none;
outline: none;
cursor: pointer;
margin: 0px;
padding: 0px;
padding: 14px 16px;
transition: 0.3s;
font-size: inherit;
color: #6a6e73;
}
/* Change background color of buttons on hover */
@ -146,7 +157,8 @@ input[type=submit] {
.tabcontent {
width: 100%;
display: none;
padding: 6px 12px;
/* padding: 6px 12px; */
padding-bottom: 0px;
border: none;
border-top: none;
}

View File

@ -2,4 +2,13 @@
{% block title %}Home{% endblock %}
{% block body%}{% endblock %}
{% block body%}
To Do List:
<ul>
<li>{% include 'icons/issue_link.html.j2' with issue=5 %} - Item History</li>
</ul>
{% endblock %}

View File

@ -0,0 +1,8 @@
<span class="icon-text change">
<span class="icon-change">
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px">
<path d="M483-337q-29 0-56.5-10T378-378q-20-20-31-46.28T336-480q0-9.74.8-18.99.8-9.25 3.2-18.01 2-10-1.66-18.82-3.65-8.83-12.59-12.5-9.75-3.68-18.37.51-8.63 4.19-11.63 14.24Q292-521 290-507.63q-2 13.37-2 27.63 0 38 14.71 73.42Q317.42-371.17 344-344q28 28 64.5 42t75.5 14l-27 27q-7 7.36-7 17.18t7 16.82q7 7 16.82 7t17.18-7l59.79-59.79Q562-298 562-312.18T551-337l-59-60q-7.36-7-17.18-7T458-397q-7 7-7 16.82t7 17.18l25 26Zm-7-287q29.7 0 57.35 10.5Q561-603 582-582q20 20 31 46.28T624-480q0 9-.8 18.5T620-443q-2 10 1.5 19t12.59 12q9.91 3 18.89-1.32 8.99-4.33 12.11-14.71Q669-441 670.5-453.5 672-466 672-480q0-38-15-73.5T615-616q-28-28-65-41.5T474-670l29-29q7-7.36 7-17.18T503-733q-7-7-16.82-7T469-733l-59.79 59.79Q398-662 398-647.82T409-623l60 60q7.36 7 17.18 7t16.82-7q7-7 7-16.82T503-597l-27-27Zm4.28 528Q401-96 331-126t-122.5-82.5Q156-261 126-330.96t-30-149.5Q96-560 126-629.5q30-69.5 82.5-122T330.96-834q69.96-30 149.5-30t149.04 30q69.5 30 122 82.5T834-629.28q30 69.73 30 149Q864-401 834-331t-82.5 122.5Q699-156 629.28-126q-69.73 30-149 30Z"/>
</svg>
</span>
{{ icon_text }}
</span>

View File

@ -0,0 +1,8 @@
<span class="icon-text cross">
<span class="icon-cross">
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px">
<path d="m480-429 116 116q11 11 25.5 10.5T647-314q11-11 11-25.5t-11-25.46L531-480.5l116-115.54q11-10.96 11-25.46T647-647q-11-11-25.5-11T596-647L480-531 364-647q-11-11-25-11t-25 11q-11 11-11 25.5t10.91 25.5L429-480 313-364q-11 11-10.5 25t11.5 25q11 11 25.5 11t25.41-10.91L480-429Zm.28 333Q401-96 331-126t-122.5-82.5Q156-261 126-330.96t-30-149.5Q96-560 126-629.5q30-69.5 82.5-122T330.96-834q69.96-30 149.5-30t149.04 30q69.5 30 122 82.5T834-629.28q30 69.73 30 149Q864-401 834-331t-82.5 122.5Q699-156 629.28-126q-69.73 30-149 30Z" />
</svg>
</span>
{{ icon_text }}
</span>

View File

@ -0,0 +1,6 @@
<span class="icon-text issue">
<span class="icon-issue">
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px"><path d="M480-144q-60 0-109-32.5T302-264h-74q-15.3 0-25.65-10.29Q192-284.58 192-299.79t10.35-25.71Q212.7-336 228-336h60v-60h-60q-15.3 0-25.65-10.29Q192-416.58 192-431.79t10.35-25.71Q212.7-468 228-468h60v-60h-60q-15.3 0-25.65-10.29Q192-548.58 192-563.79t10.35-25.71Q212.7-600 228-600h74q8-26 25.8-47.09Q345.6-668.18 369-684l-56-56q-11-11-10.5-25.5T314-791q11-11 25-11t25 11l76 75q19.86-5 40.43-5t40.57 5l75-75q11-11 25.67-11 14.66 0 25.33 11 11 11 11 25.5T647-740l-56 56q23 16 40 37t27 47h74q15.3 0 25.65 10.29Q768-579.42 768-564.21t-10.35 25.71Q747.3-528 732-528h-60v60h60q15.3 0 25.65 10.29Q768-447.42 768-432.21t-10.35 25.71Q747.3-396 732-396h-60v60h60q15.3 0 25.65 10.29Q768-315.42 768-300.21t-10.35 25.71Q747.3-264 732-264h-74q-20 55-69 87.5T480-144Zm0-72q48.67 0 83.34-35Q598-286 600-336v-192q2-50-33.5-85t-86-35q-50.5 0-85 35T360-528v192q-1 50 34 85t86 35Zm-36.09-120h71.83q15.26 0 25.76-10.29 10.5-10.29 10.5-25.5t-10.32-25.71Q531.35-408 516.09-408h-71.83q-15.26 0-25.76 10.29-10.5 10.29-10.5 25.5t10.32 25.71q10.33 10.5 25.59 10.5Zm0-120h71.83q15.26 0 25.76-10.29 10.5-10.29 10.5-25.5t-10.32-25.71Q531.35-528 516.09-528h-71.83q-15.26 0-25.76 10.29-10.5 10.29-10.5 25.5t10.32 25.71q10.33 10.5 25.59 10.5ZM480-430Z"/></svg>
</span>
<a href="https://gitlab.com/nofusscomputing/projects/django_template/-/issues/{{ issue }}" target="_blank"> see #{{ issue }}</a>
</span>

View File

@ -0,0 +1,8 @@
<span class="icon-text success">
<span class="icon-success">
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px">
<path class="tick" d="m424-408-86-86q-11-11-28-11t-28 11q-11 11-11 28t11 28l114 114q12 12 28 12t28-12l226-226q11-11 11-28t-11-28q-11-11-28-11t-28 11L424-408Zm56 328q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z"></path>
</svg>
</span>
{{ icon_text }}
</span>

View File

@ -0,0 +1,57 @@
---
title: Django Template Devlopment
description: No Fuss Computings NetBox Django Site Template Development
date: 2024-05-17
template: project.html
about: https://gitlab.com/nofusscomputing/infrastructure/configuration-management/django_app
---
This page contains different items related to the development of this application.
## Icons
Icons with text:
- Success `{% include 'icons/success_text.html.j2' with icon_text='success' %}` _denotes yes, success etc_
- Cross `{% include 'icons/cross_text.html.j2' with icon_text='cross' %}` _denotes no, negative etc_
- Change `{% include 'icons/change_text.html.j2' with icon_text='change' %}` _denotes that change management needs to run_
- Issue `{% include 'icons/issue_link.html.j2' with issue=2 %}` _Used to provide a link to an issue on GitLab. i.e. incomplete feature ticket_
## Adding an Application
1. Install the django application with `pip <app-name>`
1. Update `app.settings.py`
``` python
INSTALLED_APPS = [
'<app name>.apps.<apps.py Class Name>', # Within project directory
'<app name>', # not in project directory
]
```
1. Update `itsm/urls.py`
``` python
urlpatterns = [
path("<url path>/", include("<app name>.urls")),
]
```
!!! tip
No url from the application will be visible without including the `name` parameter when calling the `path` function within the applications `url.py`. i.e. `urlpatterns[].path(name='<Navigation Name>')`. This is by design and when combined with a prefix of `_` provides the option to limit what URL's are displayed within the navigation menu. A name beginning with an underscore `_` will not be displayed in the menu.
Once you have completed the above list, your application will display collapsed within the navigation menu with the name of your application.

View File

@ -19,38 +19,4 @@ This template has built into it multi-tenancy which can easily added to your dja
- Auto-Generated Navigation Menu
## Adding an Application
1. Install the django application with `pip <app-name>`
1. Update `app.settings.py`
``` python
INSTALLED_APPS = [
'<app name>.apps.<apps.py Class Name>', # Within project directory
'<app name>', # not in project directory
]
```
1. Update `itsm/urls.py`
``` python
urlpatterns = [
path("<url path>/", include("<app name>.urls")),
]
```
!!! tip
No url from the application will be visible without including the `name` parameter when calling the `path` function within the applications `url.py`. i.e. `urlpatterns[].path(name='<Navigation Name>')`. This is by design and when combined with a prefix of `_` provides the option to limit what URL's are displayed within the navigation menu. A name beginning with an underscore `_` will not be displayed in the menu.
Once you have completed the above list, your application will display collapsed within the navigation menu with the name of your application.
- [Configuration ready for ansible](itam/device.md#configuration)

View File

@ -6,4 +6,14 @@ template: project.html
about: https://gitlab.com/nofusscomputing/infrastructure/configuration-management/django_app
---
This component within ITAM is intended to display information about a device, be it a computer, router or switch etc.
## Software
software installed and actions to perform against software
## Configuration
Configuration is rendered in `JSON` format and specifically designed to be compatible with Ansible. This configuration can also be obtained from API endpoint `/api/config/<machine-slug>` where `<machine-slug>` would match the Ansible `inventory_hostname`.

View File

@ -35,6 +35,10 @@ nav:
- projects/django-template/itam/software.md
- Development:
- projects/django-template/development/index.md
- Operations:
- operations/index.md