diff --git a/mistraldashboard/action_executions/__init__.py b/mistraldashboard/action_executions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mistraldashboard/action_executions/forms.py b/mistraldashboard/action_executions/forms.py new file mode 100644 index 0000000..1b6beca --- /dev/null +++ b/mistraldashboard/action_executions/forms.py @@ -0,0 +1,102 @@ +# Copyright 2016 - Nokia. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms + +from mistraldashboard import api +from mistraldashboard.handle_errors import handle_errors + + +class UpdateForm(forms.SelfHandlingForm): + action_execution_id = forms.CharField(label=_("Action Execution ID"), + widget=forms.HiddenInput(), + required=False) + output_source = forms.ChoiceField( + label=_('Output'), + help_text=_('Content for output. ' + 'Select either file, raw content or Null value.'), + choices=[('null', _(' (sends empty value)')), + ('file', _('File')), + ('raw', _('Direct Input'))], + widget=forms.Select( + attrs={'class': 'switchable', + 'data-slug': 'outputsource'} + ), + required=False + ) + output_upload = forms.FileField( + label=_('Output File'), + help_text=_('A local output to upload'), + widget=forms.FileInput( + attrs={'class': 'switched', + 'data-switch-on': 'outputsource', + 'data-outputsource-file': _('Output File')} + ), + required=False + ) + output_data = forms.CharField( + label=_('Output Data'), + help_text=_('The raw content for output'), + widget=forms.widgets.Textarea( + attrs={'class': 'switched', + 'data-switch-on': 'outputsource', + 'data-outputsource-raw': _('Output Data'), + 'rows': 4} + ), + required=False + ) + + state = forms.ChoiceField( + label=_('State'), + help_text=_('Select state to update'), + choices=[('null', _(' (sends empty value)')), + ('SUCCESS', _('Success')), + ('ERROR', _('Error'))], + widget=forms.Select( + attrs={'class': 'switchable'} + ), + required=False + + ) + + def clean(self): + cleaned_data = super(UpdateForm, self).clean() + cleaned_data['output'] = None + + if cleaned_data.get('output_upload'): + files = self.request.FILES + cleaned_data['output'] = files['output_upload'].read() + elif cleaned_data.get('output_data'): + cleaned_data['output'] = cleaned_data['output_data'] + elif cleaned_data.get('output_source') == 'null': + cleaned_data['output'] = None + + del cleaned_data['output_upload'] + del cleaned_data['output_data'] + del cleaned_data['output_source'] + + if cleaned_data['state'] == 'null': + cleaned_data['state'] = None + + return cleaned_data + + @handle_errors(_("Unable to update Action Execution"), []) + def handle(self, request, data): + return api.action_execution_update( + request, + data['action_execution_id'], + data['state'], + data['output'], + ) diff --git a/mistraldashboard/action_executions/panel.py b/mistraldashboard/action_executions/panel.py new file mode 100644 index 0000000..f4f1442 --- /dev/null +++ b/mistraldashboard/action_executions/panel.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2016 - Nokia. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.utils.translation import ugettext_lazy as _ + +import horizon +from mistraldashboard import dashboard + + +class Tasks(horizon.Panel): + name = _("Action Executions") + slug = 'action_executions' + + +dashboard.MistralDashboard.register(Tasks) diff --git a/mistraldashboard/action_executions/tables.py b/mistraldashboard/action_executions/tables.py new file mode 100644 index 0000000..e8c5958 --- /dev/null +++ b/mistraldashboard/action_executions/tables.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2016 - Nokia. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.core.urlresolvers import reverse + +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ungettext_lazy + +from horizon import exceptions +from horizon import tables + +from mistraldashboard import api +import mistraldashboard.default.SmartCell as SmartCell +from mistraldashboard.default import utils + +SmartCell.init() + + +class UpdateRow(tables.Row): + ajax = True + + def get_data(self, request, id): + try: + instance = api.action_execution_get(request, id) + except Exception as e: + msg = _("Unable to get action execution by ID %(id)s: %(e)s.") % { + 'id': id, 'e': str(e) + } + exceptions.handle(request, msg) + + return instance + + +class DeleteActionExecution(tables.DeleteAction): + @staticmethod + def action_present(count): + return ungettext_lazy( + u"Delete Action Execution", + u"Delete Action Executions", + count + ) + + @staticmethod + def action_past(count): + return ungettext_lazy( + u"Deleted Action Execution", + u"Deleted Action Executions", + count + ) + + def delete(self, request, action_execution_id): + api.action_execution_delete(request, action_execution_id) + + +class UpdateActionExecution(tables.LinkAction): + name = "updateAE" + verbose_name = _("Update") + url = "horizon:mistral:action_executions:update" + classes = ("ajax-modal",) + + +class TaskExecutionIDColumn(tables.Column): + def get_link_url(self, datum): + task_url = "horizon:mistral:tasks:detail" + obj_id = datum.task_execution_id + return reverse(task_url, args=[obj_id]) + + +class WorkflowNameColumn(tables.Column): + def get_link_url(self, datum): + workflow_url = "horizon:mistral:workflows:detail" + obj_id = datum.workflow_name + return reverse(workflow_url, args=[obj_id]) + + +class ActionExecutionsTable(tables.DataTable): + + def getHoverHelp(data): + if hasattr(data, 'state_info') and data.state_info: + + return {'title': data.state_info} + + STATE_STATUS_CHOICES = ( + ("success", True), + ("error", False), + ("idle", None), + ("running", None), + ("canceled", None), + ) + + id = tables.Column( + "id", + verbose_name=_("ID"), + link="horizon:mistral:action_executions:detail" + ) + name = tables.Column( + "name", + verbose_name=_("Name") + ) + tags = tables.Column( + "tags", + verbose_name=_("Tags") + ) + workflow_name = WorkflowNameColumn( + "workflow_name", + verbose_name=_("Workflow Name"), + link=True + ) + task_execution_id = TaskExecutionIDColumn( + "task_execution_id", + verbose_name=_("Task Execution ID"), + link=True + ) + task_name = tables.Column( + "task_name", + verbose_name=_("Task name") + ) + description = tables.Column( + "description", + verbose_name=_("Description") + ) + input = tables.Column( + "", + verbose_name=_("Input"), + empty_value=_("View"), + link="horizon:mistral:action_executions:input", + link_classes=("ajax-modal",) + ) + output = tables.Column( + "", + verbose_name=_("Output"), + empty_value=_("View"), + link="horizon:mistral:action_executions:output", + link_classes=("ajax-modal",) + ) + created_at = tables.Column( + "created_at", + verbose_name=_("Created at"), + filters=[utils.humantime] + ) + updated_at = tables.Column( + "updated_at", + verbose_name=_("Updated at"), + filters=[utils.humantime] + ) + accepted = tables.Column( + "accepted", + verbose_name=_("Accepted"), + filters=[utils.booleanfield], + ) + state = tables.Column( + "state", + status=True, + status_choices=STATE_STATUS_CHOICES, + verbose_name=_("State"), + filters=[utils.label], + cell_attributes_getter=getHoverHelp + ) + + class Meta(object): + name = "actionExecutions" + verbose_name = _("Action Executions") + status_columns = ["state"] + row_class = UpdateRow + table_actions = ( + tables.FilterAction, + DeleteActionExecution + ) + row_actions = (UpdateActionExecution, DeleteActionExecution) diff --git a/mistraldashboard/action_executions/templates/action_executions/_update.html b/mistraldashboard/action_executions/templates/action_executions/_update.html new file mode 100644 index 0000000..7c0bc55 --- /dev/null +++ b/mistraldashboard/action_executions/templates/action_executions/_update.html @@ -0,0 +1,17 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

+ {% trans "Enter new output and or state to update the corresponding Action Execution." %} +

+

+ {% trans "For more info refer to:" %} +
+ + {% trans "Mistral documentation - Action Executions" %} + + +

+{% endblock %} \ No newline at end of file diff --git a/mistraldashboard/action_executions/templates/action_executions/detail.html b/mistraldashboard/action_executions/templates/action_executions/detail.html new file mode 100644 index 0000000..e6b649f --- /dev/null +++ b/mistraldashboard/action_executions/templates/action_executions/detail.html @@ -0,0 +1,96 @@ + +{% extends 'mistral/default/base.html' %} +{% load i18n %} +{% block title %}{% trans "Action Execution Details" %}{% endblock %} + +{% block page_header %} +

+ {% trans "Action Execution Details" %} +

+{% endblock page_header %} + +{% block main %} + {% load i18n sizeformat %} + +
+

{% trans "Overview" %}

+
+
+
{% trans "Name" %}
+
{{ action_execution.name }}
+
{% trans "ID" %}
+
{{ action_execution.id }}
+ {% if action_execution.description %} +
{% trans "Description" %}
+
{{ action_execution.description }}
+ {% endif %} +
+
{% trans "State" %}
+
{{ action_execution.state }}
+
+ {% if action_execution.state_info %} +
{% trans "State Info" %}
+
{{ action_execution.state_info }}
+ {% endif %} +
{% trans "Accepted" %}
+
{{ action_execution.accepted }}
+
{% trans "Tags" %}
+
{{ action_execution.tags }}
+
+
{% trans "Creation Date" %}
+
{{ action_execution.created_at|parse_isotime}}
+
{% trans "Time Since Created" %}
+
{{ action_execution.created_at|parse_isotime|timesince }}
+
+
{% trans "Update Date" %}
+
{{ action_execution.updated_at|parse_isotime}}
+
{% trans "Time Since Updated" %}
+
{{ action_execution.updated_at|parse_isotime|timesince }}
+
+
{% trans "Input" %}
+
{{ action_execution.input }}
+
{% trans "Output" %}
+
{{ action_execution.output }}
+
+
+ + {% if action_execution.workflow_url %} +
+

{% trans "Workflow Execution" %}

+
+
+
{% trans "Name" %}
+
+ + {{ action_execution.workflow_name }} + +
+
+
+ {% endif %} + {% if action_execution.task_execution_url %} +
+

{% trans "Task Execution" %}

+
+
+
{% trans "Name" %}
+
+ + {{ action_execution.task_name }} + +
+
{% trans "ID" %}
+
+ + {{ action_execution.task_execution_id }} + +
+
+
+ {% endif %} + +{% endblock %} +
\ No newline at end of file diff --git a/mistraldashboard/action_executions/templates/action_executions/filtered.html b/mistraldashboard/action_executions/templates/action_executions/filtered.html new file mode 100644 index 0000000..bae249b --- /dev/null +++ b/mistraldashboard/action_executions/templates/action_executions/filtered.html @@ -0,0 +1,13 @@ +{% extends 'mistral/default/table.html' %} +{% load i18n %} +{% block title %} + {% trans "Action Executions" %} + {{ task_id }} +{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Action Executions of Task ID:") %} +

+ {{ action_execution_id }} +

+{% endblock page_header %} diff --git a/mistraldashboard/action_executions/templates/action_executions/index.html b/mistraldashboard/action_executions/templates/action_executions/index.html new file mode 100644 index 0000000..ca07db2 --- /dev/null +++ b/mistraldashboard/action_executions/templates/action_executions/index.html @@ -0,0 +1,9 @@ +{% extends 'mistral/default/table.html' %} +{% load i18n %} +{% block title %} + {% trans "Action Executions" %} +{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Action Executions")%} +{% endblock page_header %} diff --git a/mistraldashboard/action_executions/templates/action_executions/update.html b/mistraldashboard/action_executions/templates/action_executions/update.html new file mode 100644 index 0000000..5a39946 --- /dev/null +++ b/mistraldashboard/action_executions/templates/action_executions/update.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" %} +{% endblock page_header %} + +{% block main %} + {% include 'mistral/executions/_update.html' %} +{% endblock %} \ No newline at end of file diff --git a/mistraldashboard/action_executions/urls.py b/mistraldashboard/action_executions/urls.py new file mode 100644 index 0000000..0133baa --- /dev/null +++ b/mistraldashboard/action_executions/urls.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2016 - Nokia. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.conf.urls import url # noqa + +from mistraldashboard.action_executions import views + +ACTION_EXECUTIONS = r'^(?P[^/]+)/%s$' + +urlpatterns = [ + url(r'^$', views.IndexView.as_view(), name='index'), + url(ACTION_EXECUTIONS % 'detail', views.OverviewView.as_view(), + name='detail'), + url(ACTION_EXECUTIONS % 'input', views.CodeView.as_view(), + {'column': 'input'}, name='input'), + url(ACTION_EXECUTIONS % 'output', views.CodeView.as_view(), + {'column': 'output'}, name='output'), + url(ACTION_EXECUTIONS % 'update', views.UpdateView.as_view(), + name='update'), + url(ACTION_EXECUTIONS % 'task', views.FilteredByTaskView.as_view(), + name='task') +] diff --git a/mistraldashboard/action_executions/views.py b/mistraldashboard/action_executions/views.py new file mode 100644 index 0000000..8273eb3 --- /dev/null +++ b/mistraldashboard/action_executions/views.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2016 - Nokia. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse_lazy + +from django.utils.translation import ugettext_lazy as _ +from django.views import generic + +from horizon import exceptions +from horizon import forms +from horizon import tables + +from mistraldashboard.action_executions import forms as action_execution_forms +from mistraldashboard.action_executions import tables as mistral_tables +from mistraldashboard import api +from mistraldashboard.default import utils +from mistraldashboard import forms as mistral_forms + + +def get_single_action_execution_data(request, **kwargs): + try: + action_execution_id = kwargs['action_execution_id'] + action_execution = api.action_execution_get( + request, + action_execution_id + ) + except Exception: + msg = _('Unable to get action execution "%s".') % action_execution_id + redirect = reverse('horizon:mistral:action_execution:index') + exceptions.handle(request, msg, redirect=redirect) + + return action_execution + + +class OverviewView(generic.TemplateView): + template_name = 'mistral/action_executions/detail.html' + page_title = _("Action Execution Details") + workflow_url = 'horizon:mistral:workflows:detail' + task_execution_url = 'horizon:mistral:tasks:detail' + + def get_context_data(self, **kwargs): + context = super(OverviewView, self).get_context_data(**kwargs) + action_execution = get_single_action_execution_data( + self.request, + **kwargs + ) + if action_execution.workflow_name: + action_execution.workflow_url = reverse( + self.workflow_url, + args=[action_execution.workflow_name]) + if action_execution.task_execution_id: + action_execution.task_execution_url = reverse( + self.task_execution_url, + args=[action_execution.task_execution_id] + ) + if action_execution.input: + action_execution.input = utils.prettyprint(action_execution.input) + if action_execution.output: + action_execution.output = utils.prettyprint( + action_execution.output + ) + if action_execution.state: + action_execution.state = utils.label(action_execution.state) + if action_execution.accepted: + action_execution.accepted = utils.booleanfield( + action_execution.accepted + ) + + breadcrumb = [(action_execution.id, reverse( + 'horizon:mistral:action_executions:detail', + args=[action_execution.id] + ))] + + context["custom_breadcrumb"] = breadcrumb + context['action_execution'] = action_execution + + return context + + +class CodeView(forms.ModalFormView): + template_name = 'mistral/default/code.html' + modal_header = _("Code view") + form_id = "code_view" + form_class = mistral_forms.EmptyForm + cancel_label = "OK" + cancel_url = reverse_lazy("horizon:mistral:action_executions:index") + page_title = _("Code view") + + def get_context_data(self, **kwargs): + context = super(CodeView, self).get_context_data(**kwargs) + column = self.kwargs['column'] + action_execution = get_single_action_execution_data( + self.request, + **self.kwargs + ) + io = {} + + if column == 'input': + io['name'] = _('Input') + io['value'] = utils.prettyprint(action_execution.input) + elif column == 'output': + io['name'] = _('Output') + io['value'] = ( + utils.prettyprint(action_execution.output) + if action_execution.output + else _("No available output yet") + ) + + context['io'] = io + + return context + + +class IndexView(tables.DataTableView): + table_class = mistral_tables.ActionExecutionsTable + template_name = 'mistral/action_executions/index.html' + + def get_data(self): + + return api.action_executions_list(self.request) + + +class UpdateView(forms.ModalFormView): + template_name = 'mistral/action_executions/update.html' + modal_header = _("Update Action Execution") + form_id = "update_action_execution" + form_class = action_execution_forms.UpdateForm + submit_label = _("Update") + success_url = reverse_lazy("horizon:mistral:action_executions:index") + submit_url = "horizon:mistral:action_executions:update" + cancel_url = "horizon:mistral:action_executions:index" + page_title = _("Update Action Execution") + + def get_initial(self): + return {"action_execution_id": self.kwargs["action_execution_id"]} + + def get_context_data(self, **kwargs): + context = super(UpdateView, self).get_context_data(**kwargs) + context['submit_url'] = reverse( + self.submit_url, + args=[self.kwargs["action_execution_id"]] + ) + + return context + + +class FilteredByTaskView(tables.DataTableView): + table_class = mistral_tables.ActionExecutionsTable + template_name = 'mistral/action_executions/filtered.html' + data = {} + + def get_data(self, **kwargs): + try: + task_id = self.kwargs['action_execution_id'] + data = api.action_executions_list(self.request, task_id) + except Exception: + msg = ( + _('Unable to get action execution by task id "%s".') % task_id + ) + redirect = reverse('horizon:mistral:action_executions:index') + exceptions.handle(self.request, msg, redirect=redirect) + + return data diff --git a/mistraldashboard/actions/tables.py b/mistraldashboard/actions/tables.py index ca35056..d3ecc5d 100644 --- a/mistraldashboard/actions/tables.py +++ b/mistraldashboard/actions/tables.py @@ -19,6 +19,7 @@ from horizon import tables from horizon.utils import filters from mistraldashboard import api +from mistraldashboard.default import utils class CreateAction(tables.LinkAction): @@ -92,7 +93,8 @@ class ActionsTable(tables.DataTable): ) is_system = tables.Column( "is_system", - verbose_name=_("Is System") + verbose_name=_("Is System"), + filters=[utils.booleanfield] ) tags = tables.Column( tags_to_string, diff --git a/mistraldashboard/actions/templates/actions/detail.html b/mistraldashboard/actions/templates/actions/detail.html index 52aabdf..18dae19 100644 --- a/mistraldashboard/actions/templates/actions/detail.html +++ b/mistraldashboard/actions/templates/actions/detail.html @@ -1,4 +1,5 @@ -{% extends 'base.html' %} + +{% extends 'mistral/default/base.html' %} {% load i18n %} {% block title %}{% trans "Action Definition" %}{% endblock %} @@ -31,8 +32,7 @@
{{ action.description }}
{% trans "Definition" %}
{{ action.definition }}
- {% endblock %} - +
diff --git a/mistraldashboard/actions/views.py b/mistraldashboard/actions/views.py index b0ca540..a5afb75 100644 --- a/mistraldashboard/actions/views.py +++ b/mistraldashboard/actions/views.py @@ -24,6 +24,7 @@ from horizon import tables from mistraldashboard.actions import forms as mistral_forms from mistraldashboard.actions import tables as mistral_tables from mistraldashboard import api +from mistraldashboard.default import utils class CreateView(forms.ModalFormView): @@ -112,6 +113,14 @@ class DetailView(generic.TemplateView): def get_context_data(self, **kwargs): context = super(DetailView, self).get_context_data(**kwargs) action = self.get_data(self.request, **kwargs) + if action.is_system: + action.is_system = utils.booleanfield(action.is_system) + breadcrumb = [(action.name, reverse( + 'horizon:mistral:actions:detail', + args=[action.id] + ))] + + context["custom_breadcrumb"] = breadcrumb context['action'] = action return context diff --git a/mistraldashboard/api.py b/mistraldashboard/api.py index 304c832..d10f588 100644 --- a/mistraldashboard/api.py +++ b/mistraldashboard/api.py @@ -330,6 +330,49 @@ def action_delete(request, action_name): return mistralclient(request).actions.delete(action_name) +@handle_errors(_("Unable to retrieve action executions list"), []) +def action_executions_list(request, task_execution_id=None): + """Returns all actions executions. + + :param request: Request data + :param task_execution_id: (Optional) Task Execution ID to filter by + """ + + return mistralclient(request).action_executions.list(task_execution_id) + + +@handle_errors(_("Unable to retrieve action execution"), []) +def action_execution_get(request, action_execution_id): + """Get specific action execution. + + :param action_execution_id: Action Execution ID + """ + + return mistralclient(request).action_executions.get(action_execution_id) + + +@handle_errors(_("Unable to delete action execution/s"), []) +def action_execution_delete(request, action_execution_id): + """Delete action execution. + + :param action_execution_id: Action execution ID + """ + + return mistralclient(request).action_executions.delete(action_execution_id) + + +@handle_errors(_("Unable to update action execution"), []) +def action_execution_update(request, id, state=None, output=None): + """Update action execution output and or state. + + :param id: action execution id + :param output: action execution output + :param state: action execution state + """ + + return mistralclient(request).action_executions.update(id, state, output) + + @handle_errors(_("Unable to retrieve cron trigger list"), []) def cron_trigger_list(request): """Returns all cron triggers. diff --git a/mistraldashboard/cron_triggers/templates/cron_triggers/_create.html b/mistraldashboard/cron_triggers/templates/cron_triggers/_create.html index 7f8545c..b523185 100644 --- a/mistraldashboard/cron_triggers/templates/cron_triggers/_create.html +++ b/mistraldashboard/cron_triggers/templates/cron_triggers/_create.html @@ -17,7 +17,7 @@

{% trans "For more info" %}: -

    +
    • diff --git a/mistraldashboard/cron_triggers/templates/cron_triggers/detail.html b/mistraldashboard/cron_triggers/templates/cron_triggers/detail.html index 883d53a..fbfb2df 100644 --- a/mistraldashboard/cron_triggers/templates/cron_triggers/detail.html +++ b/mistraldashboard/cron_triggers/templates/cron_triggers/detail.html @@ -1,4 +1,5 @@ -{% extends 'base.html' %} + +{% extends 'mistral/default/base.html' %} {% load i18n %} {% block title %}{% trans "Cron Trigger Details" %}{% endblock %} @@ -8,7 +9,7 @@ {% trans "Cron Trigger Details" %}