diff --git a/tom_common/templatetags/user_extras.py b/tom_common/templatetags/user_extras.py index 8a41fbb95..e5d35a1ea 100644 --- a/tom_common/templatetags/user_extras.py +++ b/tom_common/templatetags/user_extras.py @@ -54,10 +54,10 @@ def include_app_user_lists(context): for app_users in user_lists: try: context_method = import_string(app_users['context']) - except ImportError: + except ImportError as e: logger.warning(f'WARNING: Could not import context for {app.name} user list from ' f'{app_users["context"]}.\n' - f'Are you sure you have the right path?') + f'{e}') continue new_context = context_method(context) user_lists_to_display.append({'partial': app_users['partial'], 'context': new_context}) diff --git a/tom_targets/templates/tom_targets/partials/app_tab_divs.html b/tom_targets/templates/tom_targets/partials/app_tab_divs.html new file mode 100644 index 000000000..1e8a56302 --- /dev/null +++ b/tom_targets/templates/tom_targets/partials/app_tab_divs.html @@ -0,0 +1,6 @@ +{% load targets_extras tom_common_extras%} +{% for target_tab in target_tabs_to_display %} +
+ {% show_individual_app_partial target_tab %} +
+{% endfor %} \ No newline at end of file diff --git a/tom_targets/templates/tom_targets/partials/app_tabs.html b/tom_targets/templates/tom_targets/partials/app_tabs.html new file mode 100644 index 000000000..442e57497 --- /dev/null +++ b/tom_targets/templates/tom_targets/partials/app_tabs.html @@ -0,0 +1,6 @@ +{% load targets_extras %} +{% for target_tab in target_tabs_to_display %} + +{% endfor %} \ No newline at end of file diff --git a/tom_targets/templates/tom_targets/target_detail.html b/tom_targets/templates/tom_targets/target_detail.html index 9bd27bb97..9c3ca35c6 100644 --- a/tom_targets/templates/tom_targets/target_detail.html +++ b/tom_targets/templates/tom_targets/target_detail.html @@ -71,6 +71,7 @@ + {% include_app_tabs %}
@@ -114,6 +115,7 @@

Observations

{% spectroscopy_for_target target %}
+ {% include_app_tab_divs %} {% comments_enabled as comments_are_enabled %} {% if comments_are_enabled %} diff --git a/tom_targets/templates/tom_targets/target_list.html b/tom_targets/templates/tom_targets/target_list.html index 7b2d4ea19..a311b2ee3 100644 --- a/tom_targets/templates/tom_targets/target_list.html +++ b/tom_targets/templates/tom_targets/target_list.html @@ -7,7 +7,7 @@
- {{ target_count }} Targets   + {{ target_count }} Target{{ target_count|pluralize }}   diff --git a/tom_targets/templatetags/targets_extras.py b/tom_targets/templatetags/targets_extras.py index c277f4dc2..667271506 100644 --- a/tom_targets/templatetags/targets_extras.py +++ b/tom_targets/templatetags/targets_extras.py @@ -16,6 +16,7 @@ import numpy as np from plotly import offline from plotly import graph_objs as go +from django.utils.module_loading import import_string from tom_observations.utils import get_sidereal_visibility from tom_targets.base_models import BaseTarget @@ -381,7 +382,7 @@ def target_table_headers(model: type[BaseTarget]) -> list[str]: headers.append("Saved Data") else: try: - field = model._meta.get_field(column) # type: ignore[attr-defined]) + field = model._meta.get_field(column) headers.append(field.verbose_name) except FieldDoesNotExist: headers.append(column) @@ -401,7 +402,7 @@ def target_table_row(target: BaseTarget) -> list[Any]: row.append(target.dataproduct_set.count()) else: try: - field = target._meta.get_field(column) # type: ignore[attr-defined]) + field = target._meta.get_field(column) value = getattr(target, column) if field.get_internal_type() in ["FloatField", "DecimalField"]: try: @@ -504,3 +505,53 @@ def extra_form_field(form, field): if field not in [e['name'] for e in settings.EXTRA_FIELDS]: raise AttributeError("Attempted to lookup non-defined extra field") return form[field] + + +def get_app_tabs(context): + """ + Imports the target detail tab content from relevant apps into the template. + + Each target_tab should be contained in a list of dictionaries in an app's apps.py `target_detail_tabs` method. + Each target_tab dictionary should contain a 'context' key with the path to the context processor class + (typically a templatetag), a 'partial' key with the path to the html partial template, and a 'label' key with + a string describing the label for the tab. + + FOR EXAMPLE: + [{'partial': 'path/to/partial.html', + 'context': 'path/to/context/data/method', + 'label: 'Nice String'}] + """ + target_tabs_to_display = [] + for app in apps.get_app_configs(): + try: + target_tabs = app.target_detail_tabs() + except AttributeError: + continue + if target_tabs: + for tab in target_tabs: + new_context = {} + if tab.get('context'): + try: + context_method = import_string(tab.get('context')) + except ImportError as e: + logger.warning(f'WARNING: Could not import context for {app.name} target detail tab from ' + f'{tab["context"]}.\n' + f'{e}') + continue + new_context = context_method(context) + target_tabs_to_display.append({'partial': tab['partial'], + 'context': new_context, + 'label': tab['label']}) + return target_tabs_to_display + + +@register.inclusion_tag('tom_targets/partials/app_tab_divs.html', takes_context=True) +def include_app_tab_divs(context): + context['target_tabs_to_display'] = get_app_tabs(context) + return context + + +@register.inclusion_tag('tom_targets/partials/app_tabs.html', takes_context=True) +def include_app_tabs(context): + context['target_tabs_to_display'] = get_app_tabs(context) + return context