feat(itim): Ability to add external link to cluster

ref: #244 #71 #6
This commit is contained in:
2024-08-18 15:41:05 +09:30
parent 6b28569bca
commit bfb20dab0f
9 changed files with 123 additions and 192 deletions

View File

@ -83,7 +83,11 @@ class ChangeView(View, generic.UpdateView):
context['open_tab'] = None
if self.model._meta.model_name == 'device':
if self.model._meta.model_name == 'cluster':
external_links_query = ExternalLink.objects.filter(cluster=True)
elif self.model._meta.model_name == 'device':
external_links_query = ExternalLink.objects.filter(devices=True)

View File

@ -21,8 +21,8 @@
<th>Name</th>
<th>Organization</th>
</tr>
{% if item.nodes.all %}
{% for node in item.nodes.all %}
{% if cluster.nodes.all %}
{% for node in cluster.nodes.all %}
<tr>
<td><a href="{% url 'ITAM:_device_view' node.pk %}">{{ node }}</a></td>
<td>{{ node.organization }}</td>
@ -46,8 +46,8 @@
<th>Name</th>
<th>Organization</th>
</tr>
{% if item.devices.all %}
{% for device in item.devices.all %}
{% if cluster.devices.all %}
{% for device in cluster.devices.all %}
<tr>
<td><a href="{% url 'ITAM:_device_view' device.pk %}">{{ device }}</a></td>
<td>{{ device.organization }}</td>
@ -73,8 +73,8 @@
<th>Name</th>
<th>Ports</th>
</tr>
{% if item.services.all %}
{% for device in item.devices.all %}
{% if cluster.services.all %}
{% for device in cluster.devices.all %}
<tr>
<td></td>
<td></td>
@ -91,7 +91,7 @@
<div style="display: block; width: 100%;">
<h3>Config</h3>
<pre>{{ item.config | json_pretty }}</pre>
<pre>{{ cluster.config | json_pretty }}</pre>
</div>
</div>

View File

@ -134,7 +134,7 @@ class Index(IndexView):
class View(ChangeView):
context_object_name = "item"
context_object_name = "cluster"
form_class = DetailForm

View File

@ -1,10 +1,12 @@
from django import forms
from django.db.models import Q
from django.contrib.auth.models import User
from django import forms
# from django.contrib.auth.models import User
from django.urls import reverse
from access.models import Organization, TeamUsers
from app import settings
from core.forms.common import CommonModelForm
from settings.models.external_link import ExternalLink
@ -19,3 +21,64 @@ class ExternalLinksForm(CommonModelForm):
fields = '__all__'
model = ExternalLink
class DetailForm(ExternalLinksForm):
tabs: dict = {
"details": {
"name": "Details",
"slug": "details",
"sections": [
{
"layout": "double",
"left": [
'organization',
'name',
'template',
'colour',
'cluster',
'devices'
'software',
'c_created',
'c_modified',
],
"right": [
'model_notes',
]
}
]
},
"notes": {
"name": "Notes",
"slug": "notes",
"sections": []
},
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
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('Settings:_external_link_change', args=(self.instance.pk,))
})
self.url_index_view = reverse('Settings:External Links')

View File

@ -0,0 +1,18 @@
# Generated by Django 5.0.7 on 2024-08-18 05:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('settings', '0003_alter_externallink_options'),
]
operations = [
migrations.AddField(
model_name='externallink',
name='cluster',
field=models.BooleanField(default=False, help_text='Render link for clusters', verbose_name='Clusters'),
),
]

View File

@ -47,6 +47,13 @@ class ExternalLink(TenancyObject):
verbose_name = 'Button Colour',
)
cluster = models.BooleanField(
default = False,
blank = False,
help_text = 'Render link for clusters',
verbose_name = 'Clusters',
)
devices = models.BooleanField(
default = False,
blank = False,

View File

@ -1,194 +1,31 @@
{% extends 'base.html.j2' %}
{% extends 'detail.html.j2' %}
{% load json %}
{% load markdown %}
{% block title %}{{ externallink.name }}{% endblock %}
{% block content %}
{% block tabs %}
<script>
<div id="details" class="content-tab">
function openCity(evt, cityName) {
// Declare all variables
var i, tabcontent, tablinks;
{% include 'content/section.html.j2' with tab=form.tabs.details %}
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
</script>
<div class="tab">
<button onclick="window.location='{% url 'Settings:External Links' %}';"
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 External Links</button>
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
<button id="NotesOpen" class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
</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;
/*padding: 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;
}
</style>
<form action="" method="post">
{% csrf_token %}
<div id="Details" class="tabcontent">
<h3>
Details
{% for external_link in external_links %}
<span style="font-weight: normal; float: right;">{% include 'icons/external_link.html.j2' with external_link=external_link %}</span>
{% endfor %}
</h3>
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
<div id="notes" class="content-tab">
<div style="display: inline; width: 40%; margin: 30px;">
<div class="detail-view-field">
<label>{{ form.organization.label }}</label>
<span>{{ externallink.organization }}</span>
</div>
<div class="detail-view-field">
<label>{{ form.name.label }}</label>
<span>{{ form.name.value }}</span>
</div>
<div class="detail-view-field">
<label>{{ form.template.label }}</label>
<span>{{ externallink.template }}</span>
</div>
<div class="detail-view-field">
<label>{{ form.colour.label }}</label>
<span>
{% if form.colour.value %}
{{ form.colour.value }}
{% else %}
&nbsp;
{% endif %}
</span>
</div>
<div class="detail-view-field">
<label>{{ form.devices.label }}</label>
<span> {{ form.devices.value }}</span>
</div>
<div class="detail-view-field">
<label>{{ form.software.label }}</label>
<span>{{ externallink.software }}</span>
</div>
<div class="detail-view-field">
<label>Created</label>
<span>{{ externallink.created }}</span>
</div>
<div class="detail-view-field">
<label>Modified</label>
<span>{{ externallink.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 %}
&nbsp;
{% endif %}
</div>
</div>
</div>
</div>
<input type="button" value="Edit" onclick="window.location='{% url 'Settings:_external_link_change' externallink.id %}';">
{% if not tab %}
<script>
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
</script>
{% endif %}
</div>
<div id="Notes" class="tabcontent">
<h3>
Notes
</h3>
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
{{ 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 %}
{% if notes %}
{% for note in notes%}
{% include 'note.html.j2' %}
{% endfor %}
{% endif %}
</div>
{% if tab == 'notes' %}
<script>
// Get the element with id="defaultOpen" and click on it
document.getElementById("NotesOpen").click();
</script>
{% endif %}
</div>
</div>
</form>
{% endblock %}
{% endblock %}

View File

@ -9,7 +9,7 @@ from access.mixin import OrganizationPermission
from core.views.common import AddView, ChangeView, DeleteView, DisplayView, IndexView
from settings.forms.external_links import ExternalLinksForm
from settings.forms.external_links import DetailForm, ExternalLinksForm
from settings.models.external_link import ExternalLink
@ -44,7 +44,7 @@ class View(ChangeView):
context_object_name = "externallink"
form_class = ExternalLinksForm
form_class = DetailForm
model = ExternalLink

View File

@ -11,8 +11,10 @@ External Links allow an end user to specify by means of a jinja template a link
## Create a link
- Software context is under key `software`
- Cluster context is under key `cluster`
- Device context is under key `device`
- Software context is under key `software`
To add a templated link within the `Link Template` field enter your url, with the variable within jinja braces. for example to add a link that will expand with the devices id, specify `{{ device.id }}`. i.e. `https://domainname.tld/{{ device.id }}`. If the link is for software use key `software`. Available fields under context key all of those that are available at the time the page is rendered.