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:
@ -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"
|
||||
|
22
app/itam/forms/device_softwareupdate.py
Normal file
22
app/itam/forms/device_softwareupdate.py
Normal 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)
|
||||
|
18
app/itam/migrations/0002_alter_softwareversion_name.py
Normal file
18
app/itam/migrations/0002_alter_softwareversion_name.py
Normal 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),
|
||||
),
|
||||
]
|
19
app/itam/migrations/0003_devicesoftware_version.py
Normal file
19
app/itam/migrations/0003_devicesoftware_version.py
Normal 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'),
|
||||
),
|
||||
]
|
@ -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
|
||||
|
||||
)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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> </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> </td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<td colspan="5">Nothing Found {% include 'icons/issue_link.html.j2' with issue=2 %}</td>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
@ -28,4 +28,22 @@
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
|
||||
<div class="pagination">
|
||||
<span class="step-links">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page=1">« 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 »</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endblock %}
|
@ -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> </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> </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> </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> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
@ -26,4 +26,23 @@
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
|
||||
<div class="pagination">
|
||||
<span class="step-links">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page=1">« 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 »</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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:
|
||||
|
39
app/itam/views/software_version.py
Normal file
39
app/itam/views/software_version.py
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 %}
|
||||
|
8
app/templates/icons/change_text.html.j2
Normal file
8
app/templates/icons/change_text.html.j2
Normal 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>
|
8
app/templates/icons/cross_text.html.j2
Normal file
8
app/templates/icons/cross_text.html.j2
Normal 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>
|
6
app/templates/icons/issue_link.html.j2
Normal file
6
app/templates/icons/issue_link.html.j2
Normal 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>
|
8
app/templates/icons/success_text.html.j2
Normal file
8
app/templates/icons/success_text.html.j2
Normal 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>
|
57
docs/projects/django-template/development/index.md
Normal file
57
docs/projects/django-template/development/index.md
Normal 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.
|
@ -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)
|
||||
|
@ -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`.
|
||||
|
@ -35,6 +35,10 @@ nav:
|
||||
|
||||
- projects/django-template/itam/software.md
|
||||
|
||||
- Development:
|
||||
|
||||
- projects/django-template/development/index.md
|
||||
|
||||
- Operations:
|
||||
|
||||
- operations/index.md
|
||||
|
Reference in New Issue
Block a user