Closes #8296: Allow disabling custom links

This commit is contained in:
jeremystretch
2022-01-10 12:11:37 -05:00
parent 17aa37ae21
commit 72e17914e2
17 changed files with 88 additions and 27 deletions

View File

@@ -101,7 +101,7 @@ class CustomLinkSerializer(ValidatedModelSerializer):
class Meta:
model = CustomLink
fields = [
'id', 'url', 'display', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name',
'id', 'url', 'display', 'content_type', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name',
'button_class', 'new_window',
]

View File

@@ -82,7 +82,9 @@ class CustomLinkFilterSet(BaseFilterSet):
class Meta:
model = CustomLink
fields = ['id', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'new_window']
fields = [
'id', 'content_type', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name', 'new_window',
]
def search(self, queryset, name, value):
if not value.strip():

View File

@@ -47,6 +47,10 @@ class CustomLinkBulkEditForm(BulkEditForm):
limit_choices_to=FeatureQuery('custom_fields'),
required=False
)
enabled = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect()
)
new_window = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect()

View File

@@ -51,7 +51,8 @@ class CustomLinkCSVForm(CSVModelForm):
class Meta:
model = CustomLink
fields = (
'name', 'content_type', 'weight', 'group_name', 'button_class', 'new_window', 'link_text', 'link_url',
'name', 'content_type', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', 'link_text',
'link_url',
)

View File

@@ -58,15 +58,18 @@ class CustomFieldFilterForm(FilterForm):
class CustomLinkFilterForm(FilterForm):
field_groups = [
['q'],
['content_type', 'weight', 'new_window'],
['content_type', 'enabled', 'new_window', 'weight'],
]
content_type = ContentTypeChoiceField(
queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'),
required=False
)
weight = forms.IntegerField(
required=False
enabled = forms.NullBooleanField(
required=False,
widget=StaticSelect(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
new_window = forms.NullBooleanField(
required=False,
@@ -74,6 +77,9 @@ class CustomLinkFilterForm(FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
weight = forms.IntegerField(
required=False
)
class ExportTemplateFilterForm(FilterForm):

View File

@@ -53,7 +53,7 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm):
model = CustomLink
fields = '__all__'
fieldsets = (
('Custom Link', ('name', 'content_type', 'weight', 'group_name', 'button_class', 'new_window')),
('Custom Link', ('name', 'content_type', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')),
('Templates', ('link_text', 'link_url')),
)
widgets = {

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.11 on 2022-01-10 16:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('extras', '0069_custom_object_field'),
]
operations = [
migrations.AddField(
model_name='customlink',
name='enabled',
field=models.BooleanField(default=True),
),
]

View File

@@ -192,6 +192,9 @@ class CustomLink(ChangeLoggedModel):
max_length=100,
unique=True
)
enabled = models.BooleanField(
default=True
)
link_text = models.CharField(
max_length=500,
help_text="Jinja2 template code for link text"

View File

@@ -73,15 +73,16 @@ class CustomLinkTable(BaseTable):
linkify=True
)
content_type = ContentTypeColumn()
enabled = BooleanColumn()
new_window = BooleanColumn()
class Meta(BaseTable.Meta):
model = CustomLink
fields = (
'pk', 'id', 'name', 'content_type', 'link_text', 'link_url', 'weight', 'group_name',
'pk', 'id', 'name', 'content_type', 'enabled', 'link_text', 'link_url', 'weight', 'group_name',
'button_class', 'new_window',
)
default_columns = ('pk', 'name', 'content_type', 'group_name', 'button_class', 'new_window')
default_columns = ('pk', 'name', 'content_type', 'enabled', 'group_name', 'button_class', 'new_window')
#

View File

@@ -36,7 +36,7 @@ def custom_links(context, obj):
Render all applicable links for the given object.
"""
content_type = ContentType.objects.get_for_model(obj)
custom_links = CustomLink.objects.filter(content_type=content_type)
custom_links = CustomLink.objects.filter(content_type=content_type, enabled=True)
if not custom_links:
return ''

View File

@@ -139,24 +139,28 @@ class CustomLinkTest(APIViewTestCases.APIViewTestCase):
{
'content_type': 'dcim.site',
'name': 'Custom Link 4',
'enabled': True,
'link_text': 'Link 4',
'link_url': 'http://example.com/?4',
},
{
'content_type': 'dcim.site',
'name': 'Custom Link 5',
'enabled': True,
'link_text': 'Link 5',
'link_url': 'http://example.com/?5',
},
{
'content_type': 'dcim.site',
'name': 'Custom Link 6',
'enabled': False,
'link_text': 'Link 6',
'link_url': 'http://example.com/?6',
},
]
bulk_update_data = {
'new_window': True,
'enabled': False,
}
@classmethod
@@ -167,18 +171,21 @@ class CustomLinkTest(APIViewTestCases.APIViewTestCase):
CustomLink(
content_type=site_ct,
name='Custom Link 1',
enabled=True,
link_text='Link 1',
link_url='http://example.com/?1',
),
CustomLink(
content_type=site_ct,
name='Custom Link 2',
enabled=True,
link_text='Link 2',
link_url='http://example.com/?2',
),
CustomLink(
content_type=site_ct,
name='Custom Link 3',
enabled=False,
link_text='Link 3',
link_url='http://example.com/?3',
),

View File

@@ -100,6 +100,7 @@ class CustomLinkTestCase(TestCase, BaseFilterSetTests):
CustomLink(
name='Custom Link 1',
content_type=content_types[0],
enabled=True,
weight=100,
new_window=False,
link_text='Link 1',
@@ -108,6 +109,7 @@ class CustomLinkTestCase(TestCase, BaseFilterSetTests):
CustomLink(
name='Custom Link 2',
content_type=content_types[1],
enabled=True,
weight=200,
new_window=False,
link_text='Link 1',
@@ -116,6 +118,7 @@ class CustomLinkTestCase(TestCase, BaseFilterSetTests):
CustomLink(
name='Custom Link 3',
content_type=content_types[2],
enabled=False,
weight=300,
new_window=True,
link_text='Link 1',
@@ -136,6 +139,12 @@ class CustomLinkTestCase(TestCase, BaseFilterSetTests):
params = {'weight': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_enabled(self):
params = {'enabled': True}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'enabled': False}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_new_window(self):
params = {'new_window': False}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@@ -59,14 +59,15 @@ class CustomLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
site_ct = ContentType.objects.get_for_model(Site)
CustomLink.objects.bulk_create((
CustomLink(name='Custom Link 1', content_type=site_ct, link_text='Link 1', link_url='http://example.com/?1'),
CustomLink(name='Custom Link 2', content_type=site_ct, link_text='Link 2', link_url='http://example.com/?2'),
CustomLink(name='Custom Link 3', content_type=site_ct, link_text='Link 3', link_url='http://example.com/?3'),
CustomLink(name='Custom Link 1', content_type=site_ct, enabled=True, link_text='Link 1', link_url='http://example.com/?1'),
CustomLink(name='Custom Link 2', content_type=site_ct, enabled=True, link_text='Link 2', link_url='http://example.com/?2'),
CustomLink(name='Custom Link 3', content_type=site_ct, enabled=False, link_text='Link 3', link_url='http://example.com/?3'),
))
cls.form_data = {
'name': 'Custom Link X',
'content_type': site_ct.pk,
'enabled': False,
'weight': 100,
'button_class': CustomLinkButtonClassChoices.DEFAULT,
'link_text': 'Link X',
@@ -74,14 +75,15 @@ class CustomLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
}
cls.csv_data = (
"name,content_type,weight,button_class,link_text,link_url",
"Custom Link 4,dcim.site,100,blue,Link 4,http://exmaple.com/?4",
"Custom Link 5,dcim.site,100,blue,Link 5,http://exmaple.com/?5",
"Custom Link 6,dcim.site,100,blue,Link 6,http://exmaple.com/?6",
"name,content_type,enabled,weight,button_class,link_text,link_url",
"Custom Link 4,dcim.site,True,100,blue,Link 4,http://exmaple.com/?4",
"Custom Link 5,dcim.site,True,100,blue,Link 5,http://exmaple.com/?5",
"Custom Link 6,dcim.site,False,100,blue,Link 6,http://exmaple.com/?6",
)
cls.bulk_edit_data = {
'button_class': CustomLinkButtonClassChoices.CYAN,
'enabled': False,
'weight': 200,
}

View File

@@ -19,6 +19,10 @@
<th scope="row">Content Type</th>
<td>{{ object.content_type }}</td>
</tr>
<tr>
<th scope="row">Enabled</th>
<td>{% checkmark object.enabled %}</td>
</tr>
<tr>
<th scope="row">Group Name</th>
<td>{{ object.group_name|placeholder }}</td>

View File

@@ -35,15 +35,16 @@ class BaseTable(tables.Table):
if extra_columns is None:
extra_columns = []
# Add custom field columns
obj_type = ContentType.objects.get_for_model(self._meta.model)
cf_columns = [
(f'cf_{cf.name}', columns.CustomFieldColumn(cf)) for cf in CustomField.objects.filter(content_types=obj_type)
]
cl_columns = [
(f'cl_{cl.name}', columns.CustomLinkColumn(cl)) for cl in CustomLink.objects.filter(content_type=obj_type)
]
extra_columns.extend([*cf_columns, *cl_columns])
# Add custom field & custom link columns
content_type = ContentType.objects.get_for_model(self._meta.model)
custom_fields = CustomField.objects.filter(content_types=content_type)
extra_columns.extend([
(f'cf_{cf.name}', columns.CustomFieldColumn(cf)) for cf in custom_fields
])
custom_links = CustomLink.objects.filter(content_type=content_type, enabled=True)
extra_columns.extend([
(f'cl_{cl.name}', columns.CustomLinkColumn(cl)) for cl in custom_links
])
super().__init__(*args, extra_columns=extra_columns, **kwargs)