Compare commits
10 Commits
4cb37f8347
...
8d071c68df
Author | SHA1 | Date | |
---|---|---|---|
8d071c68df | |||
3b1691ff62 | |||
a77c43d213 | |||
086959b431 | |||
3f117f9d83 | |||
6a23845a4f | |||
b9c6d04e04 | |||
32c0027ecf | |||
dae52e8646 | |||
890a5651a0 |
39
.github/pull_request_template.md
vendored
Normal file
39
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
### :books: Summary
|
||||
<!-- your summary here emojis ref: https://github.com/yodamad/gitlab-emoji -->
|
||||
|
||||
|
||||
|
||||
### :link: Links / References
|
||||
<!--
|
||||
|
||||
using a list as any links to other references or links as required. if relevant, describe the link/reference
|
||||
|
||||
Include any issues or related merge requests. Note: dependent MR's also to be added to "Merge request dependencies"
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
### :construction_worker: Tasks
|
||||
|
||||
- [ ] Add your tasks here if required (delete)
|
||||
|
||||
<!-- dont remove tasks below strike through including the checkbox by enclosing in double tidle '~~' -->
|
||||
|
||||
- [ ] :firecracker: Contains breaking-change Any Breaking change(s)?
|
||||
|
||||
_Breaking Change must also be notated in the commit that introduces it and in [Conventional Commit Format](https://www.conventionalcommits.org/en/v1.0.0/)._
|
||||
|
||||
- [ ] :notebook: Release notes updated
|
||||
|
||||
- [ ] :blue_book: Documentation written
|
||||
|
||||
_All features to be documented within the correct section(s). Administration, Development and/or User_
|
||||
|
||||
- [ ] :checkered_flag: Milestone assigned
|
||||
|
||||
- [ ] :test_tube: [Unit Test(s) Written](https://nofusscomputing.com/projects/centurion_erp/development/testing/)
|
||||
|
||||
_ensure test coverage delta is not less than zero_
|
||||
|
||||
- [ ] :page_facing_up: Roadmap updated
|
@ -35,3 +35,5 @@
|
||||
- [ ] [Unit Test(s) Written](https://nofusscomputing.com/projects/centurion_erp/development/testing/)
|
||||
|
||||
_ensure test coverage delta is not less than zero_
|
||||
|
||||
- [ ] :page_facing_up: Roadmap updated
|
||||
|
@ -75,6 +75,13 @@ class ChangeView(View, generic.UpdateView):
|
||||
|
||||
external_links_query = None
|
||||
|
||||
if 'tab' in self.request.GET:
|
||||
|
||||
context['open_tab'] = str(self.request.GET.get("tab")).lower()
|
||||
|
||||
else:
|
||||
context['open_tab'] = None
|
||||
|
||||
|
||||
if self.model._meta.model_name == 'device':
|
||||
|
||||
|
@ -288,10 +288,10 @@ class Device(DeviceCommonFieldsName, SaveHistory):
|
||||
|
||||
for service in services:
|
||||
|
||||
if service.config:
|
||||
if service.config_variables:
|
||||
|
||||
service_config:dict = {
|
||||
service.config_key_variable: service.config
|
||||
service.config_key_variable: service.config_variables
|
||||
}
|
||||
|
||||
config.update(service_config)
|
||||
|
@ -1,8 +1,11 @@
|
||||
from django import forms
|
||||
from django.forms import ValidationError
|
||||
from django.urls import reverse
|
||||
|
||||
from itim.models.services import Service
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
|
||||
@ -79,3 +82,81 @@ class ServiceForm(CommonModelForm):
|
||||
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
|
||||
class DetailForm(ServiceForm):
|
||||
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'config_key_variable',
|
||||
'template',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified'
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rendered_config": {
|
||||
"name": "Rendered Config",
|
||||
"slug": "rendered_config",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "single",
|
||||
"fields": [
|
||||
'config_variables',
|
||||
],
|
||||
"json": [
|
||||
'config_variables'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['config_variables'] = forms.fields.JSONField(
|
||||
widget = forms.Textarea(
|
||||
attrs = {
|
||||
"cols": "80",
|
||||
"rows": "100"
|
||||
}
|
||||
),
|
||||
label = 'Rendered Configuration',
|
||||
initial = self.instance.config_variables,
|
||||
)
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITIM:_service_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
@ -223,10 +223,13 @@ class Service(TenancyObject):
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||
|
||||
self.config_key_variable = self.config_key_variable.lower()
|
||||
if self.config_key_variable:
|
||||
|
||||
self.config_key_variable = self.config_key_variable.lower()
|
||||
|
||||
super().save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return self.name
|
||||
|
@ -1,271 +1,75 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<script>
|
||||
{% block tabs %}
|
||||
|
||||
function openCity(evt, cityName) {
|
||||
var i, tabcontent, tablinks;
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
<hr />
|
||||
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Ports</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
{% if item.port.all and not item.template %}
|
||||
{% for port in item.port.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_port_view' item.pk %}">{{ port }}</a></td>
|
||||
<td>{{ port.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% elif not item.port.all and item.template %}
|
||||
{% for port in item.template.port.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_port_view' item.pk %}">{{ port }}</a></td>
|
||||
<td>{{ port.description }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Dependent Services</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
</tr>
|
||||
{% if item.dependent_service.all %}
|
||||
{% for service in item.dependent_service.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITIM:_service_view' service.pk %}">{{ service }}</a></td>
|
||||
<td>{{ service.organization }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.detail-view-field {
|
||||
display: unset;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0px 20px 40px 20px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field label {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field span {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
margin: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
<div class="tab">
|
||||
<button onclick="window.location='{% url 'ITIM:Services' %}';"
|
||||
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 Services</button>
|
||||
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Rendered_Config')">Rendered Config</button>
|
||||
{% if perms.assistance.change_service %}
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>Details</h3>
|
||||
|
||||
{% csrf_token %}
|
||||
<div id="rendered_config" class="content-tab">
|
||||
|
||||
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.rendered_config %}
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px;">
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.name.label }}</label>
|
||||
<span>{{ form.name.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.config_key_variable.label }}</label>
|
||||
<span>{{ form.config_key_variable.value }}</span>
|
||||
</div>
|
||||
|
||||
{% if form.template.value or form.is_template.value %}
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.is_template.label }}</label>
|
||||
<span>
|
||||
{% if form.is_template.value %}
|
||||
{{ form.is_template.value }}
|
||||
{% else %}
|
||||
<a href="{% url 'ITIM:_service_view' item.template.pk %}">{{ item.template }}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.organization.label }}</label>
|
||||
<span>
|
||||
{% if form.organization.value %}
|
||||
{{ item.organization }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>Created</label>
|
||||
<span>{{ item.created }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label title="{% if item.cluster %}{{ form.cluster.help_text }}{% else %}{{ form.device.help_text }}{% endif %}">
|
||||
{% if item.cluster %}
|
||||
Cluster
|
||||
{% else %}
|
||||
Device
|
||||
{% endif %}
|
||||
</label>
|
||||
<span>
|
||||
{% if item.cluster %}
|
||||
{{ item.cluster }}
|
||||
{% else %}
|
||||
<a href="{% url 'ITAM:_device_view' item.device.id %}">{{ item.device }}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>Modified</label>
|
||||
<span>{{ item.modified }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px; text-align: left;">
|
||||
<div>
|
||||
<label
|
||||
style="font-weight: bold; width: 100%; border-bottom: 1px solid #ccc; display: block; text-align: inherit;">{{ form.model_notes.label }}</label>
|
||||
|
||||
<div style="display: inline-block; text-align: left;">
|
||||
{% if form.model_notes.value %}
|
||||
{{ form.model_notes.value | markdown | safe }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<input type="button" value="Edit" onclick="window.location='{% url 'ITIM:_service_change' item.pk %}';">
|
||||
|
||||
<hr />
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Ports</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
{% if item.port.all and not item.template %}
|
||||
{% for port in item.port.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_port_view' item.pk %}">{{ port }}</a></td>
|
||||
<td>{{ port.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% elif not item.port.all and item.template %}
|
||||
{% for port in item.template.port.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_port_view' item.pk %}">{{ port }}</a></td>
|
||||
<td>{{ port.description }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Dependent Services</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
</tr>
|
||||
{% if item.dependent_service.all %}
|
||||
{% for service in item.dependent_service.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITIM:_service_view' service.pk %}">{{ service }}</a></td>
|
||||
<td>{{ service.organization }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Service Config</h3>
|
||||
<br>
|
||||
<textarea cols="90" rows="30" readonly>{{ item.config | json_pretty }}</textarea>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<script>
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="Rendered_Config" class="tabcontent">
|
||||
<h3>
|
||||
Rendered Config
|
||||
</h3>
|
||||
|
||||
<div>
|
||||
<textarea cols="90" rows="30" readonly>{{ item.config_variables | json_pretty }}</textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{ notes_form.prefix }}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes %}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -6,7 +6,7 @@ from core.forms.comment import AddNoteForm
|
||||
from core.models.notes import Notes
|
||||
from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itim.forms.services import ServiceForm
|
||||
from itim.forms.services import ServiceForm, DetailForm
|
||||
from itim.models.services import Service
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
@ -136,7 +136,7 @@ class View(ChangeView):
|
||||
|
||||
context_object_name = "item"
|
||||
|
||||
form_class = ServiceForm
|
||||
form_class = DetailForm
|
||||
|
||||
model = Service
|
||||
|
||||
|
@ -65,6 +65,119 @@ input[type=submit] {
|
||||
height: 30px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Style the navigation tabs at the top of a content page */
|
||||
.content-navigation-tabs {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #ccc;
|
||||
/* background-color: #f1f1f1; */
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 0px;
|
||||
margin: 0px
|
||||
}
|
||||
|
||||
|
||||
.content-navigation-tabs-link {
|
||||
border: 0px;
|
||||
margin: none;
|
||||
padding: none;
|
||||
}
|
||||
|
||||
/* Style the buttons that are used to open the tab content */
|
||||
.content-navigation-tabs button {
|
||||
display: inline;
|
||||
background-color: inherit;
|
||||
float: left;
|
||||
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 */
|
||||
.content-navigation-tabs button:hover {
|
||||
/* background-color: #ddd; */
|
||||
border-bottom: 3px solid #ccc;
|
||||
}
|
||||
|
||||
|
||||
/* Create an active/current tablink class */
|
||||
.content-navigation-tabs button.active {
|
||||
/* background-color: #ccc; */
|
||||
border-bottom: 3px solid #177ee6;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Style content for each tab */
|
||||
.content-tab {
|
||||
width: 100%;
|
||||
display: none;
|
||||
padding-bottom: 0px;
|
||||
border: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.content-tab hr {
|
||||
border: none;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.content-tab pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* Style for section fields on details page */
|
||||
.detail-view-field {
|
||||
display: unset;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0px 20px 40px 20px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field label {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field span {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
margin: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
EoF refactored
|
||||
@ -124,61 +237,6 @@ input[type=checkbox]:checked::after {
|
||||
|
||||
|
||||
|
||||
/* Style the tab */
|
||||
.tab {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #ccc;
|
||||
/* 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 */
|
||||
.tab button {
|
||||
display: inline;
|
||||
background-color: inherit;
|
||||
float: left;
|
||||
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 */
|
||||
.tab button:hover {
|
||||
/* background-color: #ddd; */
|
||||
border-bottom: 3px solid #ccc;
|
||||
}
|
||||
|
||||
/* Create an active/current tablink class */
|
||||
.tab button.active {
|
||||
/* background-color: #ccc; */
|
||||
border-bottom: 3px solid #177ee6;
|
||||
}
|
||||
|
||||
/* Style the tab content */
|
||||
.tabcontent {
|
||||
width: 100%;
|
||||
display: none;
|
||||
/* padding: 6px 12px; */
|
||||
padding-bottom: 0px;
|
||||
border: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
|
16
app/project-static/functions.js
Normal file
16
app/project-static/functions.js
Normal file
@ -0,0 +1,16 @@
|
||||
function openContentNavigationTab(evt, TabName) {
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
tabcontent = document.getElementsByClassName("content-tab");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
tablinks = document.getElementsByClassName("content-navigation-tabs-link");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
document.getElementById(TabName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
@ -14,6 +14,7 @@
|
||||
<link rel="stylesheet" href="{% static 'base.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'code.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'content.css' %}">
|
||||
<script src="{% static 'functions.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
</head>
|
||||
|
72
app/templates/content/field.html.j2
Normal file
72
app/templates/content/field.html.j2
Normal file
@ -0,0 +1,72 @@
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% if field.widget_type == 'textarea' or field.label == 'Notes' %}
|
||||
|
||||
{% if field.name in section.json and field.value %}
|
||||
|
||||
<pre style="width: 80%; text-align: left; display:inline; border: 1px solid #ccc; padding: 22px;">{{ field.value.strip | json_pretty | safe }}</pre>
|
||||
|
||||
{% elif field.name in section.markdown or field.label == 'Notes' %}
|
||||
|
||||
{% if field.label == 'Notes' %}
|
||||
|
||||
<div>
|
||||
<label style="font-weight: bold; width: 100%; border-bottom: 1px solid #ccc; display: block; text-align: inherit;">
|
||||
{{ field.label }}
|
||||
</label>
|
||||
|
||||
<div style="display: inline-block; text-align: left;">
|
||||
{% if field.value %}
|
||||
{{ field.value | markdown | safe }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
{% if field.value %}
|
||||
|
||||
{{ field.value | markdown | safe }}
|
||||
|
||||
{% else %}
|
||||
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% elif not field.value %}
|
||||
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% else %}
|
||||
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ field.label }}</label>
|
||||
<span>
|
||||
{% if field.field.choices %} {# Display the selected choice text value #}
|
||||
{% for id, value in field.field.choices %}
|
||||
|
||||
{% if field.value == id %}
|
||||
|
||||
{{ value }}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{%endfor%}
|
||||
|
||||
{% else %}
|
||||
{{ field.value }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
93
app/templates/content/section.html.j2
Normal file
93
app/templates/content/section.html.j2
Normal file
@ -0,0 +1,93 @@
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% for section in tab.sections %}
|
||||
|
||||
|
||||
{% if forloop.first %}
|
||||
|
||||
<h3>{{ tab.name }}</h3>
|
||||
|
||||
{% else %}
|
||||
|
||||
<hr />
|
||||
<h3>{{ section.name }}</h3>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
|
||||
|
||||
{% if section.layout == 'single' %}
|
||||
|
||||
{% for section_field in section.fields %}
|
||||
{% for field in form %}
|
||||
|
||||
{% if field.name in section_field %}
|
||||
|
||||
{% include 'content/field.html.j2' %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% elif section.layout == 'double' %}
|
||||
|
||||
{% if section.left %}
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px;">
|
||||
|
||||
{% for section_field in section.left %}
|
||||
{% for field in form %}
|
||||
|
||||
{% if field.name in section_field %}
|
||||
|
||||
{% include 'content/field.html.j2' %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if section.right %}
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px; text-align: left;">
|
||||
|
||||
{% for section_field in section.right %}
|
||||
{% for field in form %}
|
||||
|
||||
{% if field.name in section_field %}
|
||||
|
||||
{% include 'content/field.html.j2' %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if forloop.first %}
|
||||
|
||||
{% if tab.edit_url %}
|
||||
|
||||
<div style="display:block;">
|
||||
<input type="button" value="Edit" onclick="window.location='{{ tab.edit_url }}';">
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
47
app/templates/detail.html.j2
Normal file
47
app/templates/detail.html.j2
Normal file
@ -0,0 +1,47 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="content-navigation-tabs">
|
||||
|
||||
<button onclick="window.location='{% url 'ITIM:Services' %}';" 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 Services
|
||||
</button>
|
||||
|
||||
{% for key, tab in form.tabs.items %}
|
||||
|
||||
{% if forloop.first %}
|
||||
|
||||
<button id="defaultOpen" class="content-navigation-tabs-link" onclick="openContentNavigationTab(event, '{{ tab.slug }}')">{{ tab.name }}</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button id="tab-{{ tab.slug }}" class="content-navigation-tabs-link" onclick="openContentNavigationTab(event, '{{ tab.slug }}')">{{ tab.name }}</button>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
{% block tabs %}{% endblock %}
|
||||
|
||||
{% if open_tab %}
|
||||
|
||||
<script>
|
||||
document.getElementById("tab-{{ open_tab }}").click();
|
||||
</script>
|
||||
|
||||
{% else %}
|
||||
|
||||
<script>
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
1
app/templates/icons/service.svg
Normal file
1
app/templates/icons/service.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.7 18.6V17.6L22.8 16.8C22.9 16.7 23 16.6 22.9 16.5L21.9 14.8C21.9 14.7 21.7 14.7 21.6 14.7L20.4 15.2C20.1 15 19.8 14.8 19.5 14.7L19.3 13.4C19.3 13.3 19.2 13.2 19.1 13.2H17.1C16.9 13.2 16.8 13.3 16.8 13.4L16.6 14.7C16.3 14.9 16.1 15 15.8 15.2L14.6 14.7C14.5 14.7 14.4 14.7 14.3 14.8L13.3 16.5C13.3 16.6 13.3 16.7 13.4 16.8L14.5 17.6V18.6L13.4 19.4C13.3 19.5 13.2 19.6 13.3 19.7L14.3 21.4C14.4 21.5 14.5 21.5 14.6 21.5L15.8 21C16 21.2 16.3 21.4 16.6 21.5L16.8 22.8C16.9 22.9 17 23 17.1 23H19.1C19.2 23 19.3 22.9 19.3 22.8L19.5 21.5C19.8 21.3 20 21.2 20.3 21L21.5 21.4C21.6 21.4 21.7 21.4 21.8 21.3L22.8 19.6C22.9 19.5 22.9 19.4 22.8 19.4L21.7 18.6M18 19.5C17.2 19.5 16.5 18.8 16.5 18S17.2 16.5 18 16.5 19.5 17.2 19.5 18 18.8 19.5 18 19.5M12.3 22H3C1.9 22 1 21.1 1 20V4C1 2.9 1.9 2 3 2H21C22.1 2 23 2.9 23 4V13.1C22.4 12.5 21.7 12 21 11.7V6H3V20H11.3C11.5 20.7 11.8 21.4 12.3 22Z" /></svg>
|
After Width: | Height: | Size: 958 B |
@ -49,6 +49,8 @@ span.navigation_icon {
|
||||
{% include 'icons/devices.svg' %}
|
||||
{% elif group_urls.name == 'Knowledge Base' %}
|
||||
{% include 'icons/information.svg' %}
|
||||
{% elif group_urls.name == 'Services' %}
|
||||
{% include 'icons/service.svg' %}
|
||||
{% elif group_urls.name == 'Software' %}
|
||||
{% include 'icons/software.svg' %}
|
||||
{% elif group_urls.name == 'Groups' %}
|
||||
|
@ -51,6 +51,18 @@ All forms must meet the following requirements:
|
||||
|
||||
```
|
||||
|
||||
## Details Form
|
||||
|
||||
A details form is for the display of a models data. This form should inherit from a base form and contain any additional fields as is required for the display of the models data. Additional requirements are as follows:
|
||||
|
||||
- `tab` is defined as a `dict` within the class. _See [Template](./templates.md#detail)._
|
||||
|
||||
- There is an `__init__` class defined that sets up the additional fields.
|
||||
|
||||
!!! danger "Requirement"
|
||||
Ensure that there is a call to the super-class `__init__` method so that the form is correctly initialised. i.e. `super().__init__(*args, **kwargs)`
|
||||
|
||||
|
||||
|
||||
## Abstract Classes
|
||||
|
||||
|
@ -19,6 +19,8 @@ Centurion ERP is a Django Application. We have added a lot of little tid bits th
|
||||
|
||||
- [Models](./models.md)
|
||||
|
||||
- [Templates](./templates.md)
|
||||
|
||||
- [Testing](./testing.md)
|
||||
|
||||
- [Views](./views.md)
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
@ -0,0 +1,46 @@
|
||||
<mxfile host="app.diagrams.net" modified="2024-08-13T04:59:07.625Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" etag="UnD9NsC2nlQotuYi3Jgi" version="24.4.13" type="device">
|
||||
<diagram name="Page-1" id="43mCgrILUMj9ztUM_gXM">
|
||||
<mxGraphModel dx="1434" dy="766" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-2" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="110" y="80" width="1000" height="520" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-3" value="Page Header" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="110" y="80" width="1000" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-4" value="Navigation<div><br></div>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="110" y="140" width="200" height="460" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-5" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxGeometry x="310" y="140" width="800" height="460" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-6" value="Page Title" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#D1FCFF;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="310" y="140" width="800" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-7" value="Section Content, Single Column" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="210" width="780" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-8" value="Page Footer" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
|
||||
<mxGeometry x="310" y="560" width="800" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-9" value="Section Navigation Tabs" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="210" width="780" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-10" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="370" width="780" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-11" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="390" y="370" width="320" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-15" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="710" y="370" width="320" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="S1pZBpeQw_pKLN31ISmP-12" value="<span style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: center; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(251, 251, 251); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">Section Content, Double Column</span>" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="620" y="425" width="210" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
188
docs/projects/centurion_erp/development/templates.md
Normal file
188
docs/projects/centurion_erp/development/templates.md
Normal file
@ -0,0 +1,188 @@
|
||||
---
|
||||
title: Templates
|
||||
description: Development documentation for template usage and layout for Centurion ERP by No Fuss Computing
|
||||
date: 2024-08-13
|
||||
template: project.html
|
||||
about: https://gitlab.com/nofusscomputing/infrastructure/configuration-management/centurion_erp
|
||||
---
|
||||
|
||||
This section of the documentation contains the details related to the templates used within Centurion ERP for rendering data for the end user to view.
|
||||
|
||||
|
||||
## Templates
|
||||
|
||||
- Base
|
||||
|
||||
- Detail
|
||||
|
||||
|
||||
## Base
|
||||
|
||||
The base template is common to all templates and is responsible for the rendering of the common layout. Each subsequent template includes this template. This enables **ALL** pages within the site to share the same layout.
|
||||
|
||||

|
||||
|
||||
Point of note is that the orange area of the template is what each template is "filling out."
|
||||
|
||||
This view contains the following areas:
|
||||
|
||||
- Page Header
|
||||
|
||||
_Site header._
|
||||
|
||||
- Navigation
|
||||
|
||||
_Site navigation._
|
||||
|
||||
- Page Title
|
||||
|
||||
_represents the "what" to the contents of the page. i.e. for a device this would be the device name._
|
||||
|
||||
- Content Area
|
||||
|
||||
_The views content_
|
||||
|
||||
- Page footer
|
||||
|
||||
_Site footer_
|
||||
|
||||
!!! note
|
||||
This template should not be included directly as it is incomplete and requires subsequent templates to populate the contents of the orange area.
|
||||
|
||||
|
||||
## Detail
|
||||
|
||||
This template is intended to be used to render the details of a single model. The layout of the detail view is as follows:
|
||||
|
||||

|
||||
|
||||
This view contains the following areas:
|
||||
|
||||
- Section navigation tabs
|
||||
- Section Content
|
||||
|
||||
A detail page contains navigation tabs to aid in displaying multiple facets of an item, with each "tabbed" page containing one or more sections. Point of note is that the tabs are only rendered within the top section of each "tabbed" page.
|
||||
|
||||
Base definition for defining a detail page is as follows:
|
||||
|
||||
``` jinja
|
||||
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
|
||||
your tabs content here
|
||||
|
||||
{% endblock %}
|
||||
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Need to navigate directly to a tab, add `tab=<slug>` to the url query string
|
||||
|
||||
|
||||
### Providing data for the view
|
||||
|
||||
For the view to render the page, you must define the data as part of the form class.
|
||||
|
||||
|
||||
|
||||
The variable name to use is `tabs` The layout/schema is as follows:
|
||||
|
||||
|
||||
#### Full Example
|
||||
|
||||
This example is a full example with two tabs: `details` and `rendered_config`
|
||||
|
||||
``` python
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'config_key_variable',
|
||||
'template',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified'
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rendered_config": {
|
||||
"name": "Rendered Config",
|
||||
"slug": "rendered_config",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "single",
|
||||
"fields": [
|
||||
'config_variables',
|
||||
],
|
||||
"json": [
|
||||
'config_variables'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
additional fields can be defined as part of the form `__init__` method.
|
||||
|
||||
``` python
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields['config_variables'] = forms.fields.JSONField(
|
||||
widget = forms.Textarea(
|
||||
attrs = {
|
||||
"cols": "80",
|
||||
"rows": "100"
|
||||
}
|
||||
),
|
||||
label = 'Rendered Configuration',
|
||||
initial = self.instance.config_variables,
|
||||
)
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
You can add an edit button to any tab by defining the following as part of the `__init__` method:
|
||||
|
||||
``` py
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITIM:_service_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
in this example, the details tab will display an `Edit` button. The `Edit` button will only display at the end of the first section of any tab it has been defined for.
|
@ -34,6 +34,8 @@ Centurion ERP contains the following modules:
|
||||
|
||||
- [IT Asset Management (ITAM)](./user/itam/index.md)
|
||||
|
||||
- [Knowledge Base](./user/assistance/knowledge_base.md)
|
||||
|
||||
|
||||
- **Core Features:**
|
||||
|
||||
@ -75,75 +77,71 @@ Below is a list of modules/features we intend to add to Centurion. To find out w
|
||||
|
||||
- **Planned Modules:**
|
||||
|
||||
- Accounting _[see #88](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/88)_
|
||||
- Accounting _[see #88](https://github.com/nofusscomputing/centurion_erp/issues/88)_
|
||||
|
||||
General Ledger - _[see #116](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/116)_
|
||||
General Ledger - _[see #116](https://github.com/nofusscomputing/centurion_erp/issues/116)_
|
||||
|
||||
- Asset Management _[see #89](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/88)_
|
||||
- Asset Management _[see #89](https://github.com/nofusscomputing/centurion_erp/issues/88)_
|
||||
|
||||
- Change Management _[see #90](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/90)_
|
||||
- Change Management _[see #90](https://github.com/nofusscomputing/centurion_erp/issues/90)_
|
||||
|
||||
- Config Management
|
||||
|
||||
- Host Config _[see #44](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/44)_
|
||||
|
||||
- Core
|
||||
|
||||
- Location Management (Regions, Sites and Locations) _[see #62](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/62)_
|
||||
- Location Management (Regions, Sites and Locations) _[see #62](https://github.com/nofusscomputing/centurion_erp/issues/62)_
|
||||
|
||||
- Customer Relationship Management (CRM) _[see #91](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/91)_
|
||||
- Customer Relationship Management (CRM) _[see #91](https://github.com/nofusscomputing/centurion_erp/issues/91)_
|
||||
|
||||
- Database Management _[see #72](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/72)_
|
||||
- Database Management _[see #72](https://github.com/nofusscomputing/centurion_erp/issues/72)_
|
||||
|
||||
- Development Operations (DevOPS) _[see #68](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/58)_
|
||||
- Development Operations (DevOPS) _[see #68](https://github.com/nofusscomputing/centurion_erp/issues/58)_
|
||||
|
||||
- Repository Management _[see #115](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/115)_
|
||||
- Repository Management _[see #115](https://github.com/nofusscomputing/centurion_erp/issues/115)_
|
||||
|
||||
- Human Resource Management _[see #92](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/92)_
|
||||
- Human Resource Management _[see #92](https://github.com/nofusscomputing/centurion_erp/issues/92)_
|
||||
|
||||
- Incident Management _[see #93](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/93)_
|
||||
|
||||
- Information Management _[see #10](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/10)_
|
||||
- Incident Management _[see #93](https://github.com/nofusscomputing/centurion_erp/issues/93)_
|
||||
|
||||
- IT Asset Management (ITAM)
|
||||
|
||||
- Licence Management _[see #4](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/4)_
|
||||
- Licence Management _[see #4](https://github.com/nofusscomputing/centurion_erp/issues/4)_
|
||||
|
||||
- IT Infrastructure Management (ITIM) _[see #61](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/61)_
|
||||
- IT Infrastructure Management (ITIM) _[see #61](https://github.com/nofusscomputing/centurion_erp/issues/61)_
|
||||
|
||||
- Cluster Management _[see #71](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/71)_
|
||||
- Cluster Management _[see #71](https://github.com/nofusscomputing/centurion_erp/issues/71)_
|
||||
|
||||
- Database Management _[see #72](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/72)_
|
||||
- Database Management _[see #72](https://github.com/nofusscomputing/centurion_erp/issues/72)_
|
||||
|
||||
- Service Management _[see #19](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/19)_
|
||||
- Service Management _[see #19](https://github.com/nofusscomputing/centurion_erp/issues/19)_
|
||||
|
||||
- Software Package Management _[see #96](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/96)_
|
||||
- Software Package Management _[see #96](https://github.com/nofusscomputing/centurion_erp/issues/96)_
|
||||
|
||||
- Role Management _[see #70](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/70)_
|
||||
- Role Management _[see #70](https://github.com/nofusscomputing/centurion_erp/issues/70)_
|
||||
|
||||
- Virtual Machine Management _[see #73](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/73)_
|
||||
- Virtual Machine Management _[see #73](https://github.com/nofusscomputing/centurion_erp/issues/73)_
|
||||
|
||||
- Vulnerability Management
|
||||
|
||||
- Software _[see #3](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/3)_
|
||||
- Software _[see #3](https://github.com/nofusscomputing/centurion_erp/issues/3)_
|
||||
|
||||
- Order Management _[see #94](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/94)_
|
||||
- Order Management _[see #94](https://github.com/nofusscomputing/centurion_erp/issues/94)_
|
||||
|
||||
- Supplier Management _[see #123](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/123)_
|
||||
- Supplier Management _[see #123](https://github.com/nofusscomputing/centurion_erp/issues/123)_
|
||||
|
||||
- Project Management _[see #14](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/14)_
|
||||
- Project Management _[see #14](https://github.com/nofusscomputing/centurion_erp/issues/14)_
|
||||
|
||||
- Problem Management _[see #95](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/95)_
|
||||
- Problem Management _[see #95](https://github.com/nofusscomputing/centurion_erp/issues/95)_
|
||||
|
||||
- Request Management _[see #96](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/96)_
|
||||
- Request Management _[see #96](https://github.com/nofusscomputing/centurion_erp/issues/96)_
|
||||
|
||||
|
||||
- **Planned Integrations:**
|
||||
|
||||
- ArgoCD _[see #77](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/77)_
|
||||
- ArgoCD _[see #77](https://github.com/nofusscomputing/centurion_erp/issues/77)_
|
||||
|
||||
[ArgoCD](https://github.com/argoproj-labs) is a Continuous Deployment system for ensuring objects deployed to kubernetes remain in the desired state.
|
||||
|
||||
- AWX _[see #113](https://gitlab.com/nofusscomputing/projects/django_template/-/issues/113)_
|
||||
- AWX _[see #113](https://github.com/nofusscomputing/centurion_erp/issues/113)_
|
||||
|
||||
[AWX](https://github.com/ansible/awx) is an Automation Orchestration system that uses Ansible for its configuration.
|
||||
|
@ -10,3 +10,9 @@ This component within ITIM is an extension of Service Management, in particular
|
||||
|
||||
|
||||
## Ports
|
||||
|
||||
- number _A Valid port number [1-65535]_
|
||||
|
||||
- description _Short description of the port_
|
||||
|
||||
- protocol _OSI Layer 4 protocol [TCP or UDP]_
|
||||
|
@ -6,7 +6,36 @@ template: project.html
|
||||
about: https://gitlab.com/nofusscomputing/infrastructure/configuration-management/centurion_erp
|
||||
---
|
||||
|
||||
This component within ITIM is intended to enable the management of services deployed throughout your IT infrastructure. A service is defined as anything that is deployed that end users would access via a client application.
|
||||
This component within ITIM is intended to enable the management of services deployed throughout your IT infrastructure. A service is defined as anything that is deployed that end users would access via a client application. The design of our services is intended to work with either ansible collections or roles. Either way as long as the resulting ansible tasks look for the variables under a single key for the service; any method you choose to deploy a service is up to you.
|
||||
|
||||
|
||||
## Services
|
||||
|
||||
Within the services the following fields are available:
|
||||
|
||||
- is_template _Defines the service as a template_
|
||||
|
||||
- template _name if the template that this service inherits from_
|
||||
|
||||
- name _name of the service_
|
||||
|
||||
- device _Device service deployed to_
|
||||
|
||||
- cluster _Cluster the service is deployed to_
|
||||
|
||||
- config _Ansible configuration variables_
|
||||
|
||||
- config_key_variable _Ansible dictionary key name for config_
|
||||
|
||||
- [port](./port.md) _Ports assosiated with the service_
|
||||
|
||||
- dependent_service _A List of services this service depends upon_
|
||||
|
||||
|
||||
## Service Template
|
||||
|
||||
A service can be setup as a template `is_template=True` for which then can be used as the base template for further service creations. Both config and Ports are inherited from the template with any conflict taking the current services values.
|
||||
|
||||
## Deployed to
|
||||
|
||||
A service can be deployed to a Cluster or a Device. When assosiated with an item, within it's details page the services deployed to it are available.
|
||||
|
@ -152,6 +152,8 @@ nav:
|
||||
|
||||
- projects/centurion_erp/development/models.md
|
||||
|
||||
- projects/centurion_erp/development/templates.md
|
||||
|
||||
- projects/centurion_erp/development/testing.md
|
||||
|
||||
- projects/centurion_erp/development/views.md
|
||||
|
Reference in New Issue
Block a user