Modify to use API v2

Change-Id: Iacaab88d7ce8618aa7331e8cb7f23c69191e5f49
Implements: blueprint mistral-ui
This commit is contained in:
Kirill Izotov 2014-09-12 16:28:26 +07:00
parent 8fb902e2a3
commit bb03d06ebe
33 changed files with 456 additions and 97 deletions

View File

@ -22,7 +22,7 @@ SERVICE_TYPE = 'workflow'
def mistralclient(request):
return mistral_client.Client(
return mistral_client.client(
username=request.user.username,
auth_token=request.user.token.id,
project_id=request.user.tenant_id,

View File

@ -18,18 +18,13 @@ from django.utils.translation import ugettext_lazy as _
import horizon
class Default(horizon.Panel):
name = _("Default")
slug = 'default'
urls = 'mistraldashboard.workbooks.urls'
nav = False
from mistraldashboard.default.panel import Default
class MistralDashboard(horizon.Dashboard):
name = _("Mistral")
slug = "mistral"
panels = ('default', 'workbooks', 'executions',)
panels = ('default', 'workbooks', 'workflows', 'executions', 'tasks',)
default_panel = 'default'
roles = ('admin',)

View File

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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
class Default(horizon.Panel):
name = _("Default")
slug = 'default'
urls = 'mistraldashboard.workbooks.urls'
nav = False

View File

@ -0,0 +1,2 @@
{% load humanize %}
<time datatime="{{ datetime|date:'c' }}">{{ datetime|naturaltime }}</time>

View File

@ -0,0 +1 @@
<span class="label {{ type }}">{{ label }}</span>

View File

@ -0,0 +1,9 @@
{% if short %}
<div class="codeblock" tabindex="-1">
<pre lang="json" class="short">{{ short }}</pre>
<pre lang="json" class="full">{{ full }}</pre>
{% else %}
<div class="codeblock">
<pre lang="json" class="short">{{ full }}</pre>
{% endif %}
</div>

View File

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block css %}
{% include "_stylesheets.html" %}
{% load compress %}
{% compress css %}
<link href='{{ STATIC_URL }}mistraldashboard/scss/style.scss' type='text/scss' media='screen' rel='stylesheet' />
{% endcompress %}
{% endblock %}

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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.template.loader import render_to_string
import iso8601
import json
TYPES = {
'SUCCESS': 'label-success',
'ERROR': 'label-important'
}
def label(x):
return render_to_string("mistral/default/_label.html",
{"label": x,
"type": TYPES.get(x)})
def humantime(x):
return render_to_string("mistral/default/_humantime.html",
{"datetime": iso8601.parse_date(x)})
def prettyprint(x):
short = None
full = json.dumps(json.loads(x), indent=4, ensure_ascii=False)
lines = full.split('\n')
if (len(lines) > 5):
short = '\n'.join(lines[:5] + ['...'])
return render_to_string("mistral/default/_prettyprint.html",
{"full": full, "short": short})

View File

@ -15,28 +15,34 @@
# limitations under the License.
from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
from horizon import tables
TYPES = {
'SUCCESS': 'label-success',
'ERROR': 'label-important'
}
def label(x):
return render_to_string("mistral/executions/_label.html",
{"label": x,
"type": TYPES.get(x)})
from mistraldashboard.default.utils import label
from mistraldashboard.default.utils import humantime
from mistraldashboard.default.utils import prettyprint
class ExecutionsTable(tables.DataTable):
id = tables.Column("id",
verbose_name=_("ID"),
link=("horizon:mistral:executions:tasks"))
wb_name = tables.Column("workbook_name", verbose_name=_("Workbook"))
id = tables.Column("id", verbose_name=_("ID")) # ,
# link=("horizon:mistral:executions:tasks"))
workflow_name = tables.Column("workflow_name", verbose_name=_("Workflow"))
input = tables.Column("input",
verbose_name=_("Input"),
filters=[prettyprint])
output = tables.Column("output",
verbose_name=_("Output"),
filters=[prettyprint])
created_at = tables.Column("created_at",
verbose_name=_("Created at"),
filters=[humantime])
updated_at = tables.Column("updated_at",
verbose_name=_("Updated at"),
filters=[humantime])
state = tables.Column("state", verbose_name=_("State"), filters=[label])
class Meta:
@ -47,8 +53,13 @@ class ExecutionsTable(tables.DataTable):
class TaskTable(tables.DataTable):
id = tables.Column("id", verbose_name=_("ID"))
name = tables.Column("name", verbose_name=_("Name"))
parameters = tables.Column("parameters", verbose_name=_("Parameters"))
output = tables.Column("output", verbose_name=_("Output"))
created_at = tables.Column("created_at", verbose_name=_("Created at"))
updated_at = tables.Column("updated_at", verbose_name=_("Updated at"))
state = tables.Column("state", verbose_name=_("State"), filters=[label])
class Meta:

View File

@ -1 +0,0 @@
<span class="label {{ type }}">{{ label }}</span>

View File

@ -1,4 +1,4 @@
{% extends 'base.html' %}
{% extends 'mistral/default/base.html' %}
{% load i18n %}
{% block title %}{% trans "Executions" %}{% endblock %}

View File

@ -27,7 +27,7 @@ class IndexView(tables.DataTableView):
def get_data(self):
client = api.mistralclient(self.request)
return client.executions.list(None)
return client.executions.list()
class TaskView(tables.DataTableView):
@ -36,4 +36,4 @@ class TaskView(tables.DataTableView):
def get_data(self):
client = api.mistralclient(self.request)
return client.tasks.list(None, self.kwargs['execution_id'])
return client.tasks.list()

View File

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 = _("Tasks")
slug = 'tasks'
dashboard.MistralDashboard.register(Tasks)

View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 tables
from mistraldashboard.default.utils import label
from mistraldashboard.default.utils import humantime
from mistraldashboard.default.utils import prettyprint
class TaskTable(tables.DataTable):
id = tables.Column("id", verbose_name=_("ID"))
name = tables.Column("name", verbose_name=_("Name"))
parameters = tables.Column("parameters",
verbose_name=_("Parameters"),
filters=[prettyprint])
output = tables.Column("output",
verbose_name=_("Output"),
filters=[prettyprint])
created_at = tables.Column("created_at",
verbose_name=_("Created at"),
filters=[humantime])
updated_at = tables.Column("updated_at",
verbose_name=_("Updated at"),
filters=[humantime])
state = tables.Column("state", verbose_name=_("State"), filters=[label])
class Meta:
name = "tasks"
verbose_name = _("Tasks")

View File

@ -0,0 +1,11 @@
{% extends 'mistral/default/base.html' %}
{% load i18n %}
{% block title %}{% trans "Tasks" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Tasks") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 patterns # noqa
from django.conf.urls import url # noqa
from mistraldashboard.tasks.views import IndexView
urlpatterns = patterns(
'',
url(r'^$', IndexView.as_view(), name='index'),
)

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 horizon import tables
from mistraldashboard import api
from mistraldashboard.tasks.tables import TaskTable
class IndexView(tables.DataTableView):
table_class = TaskTable
template_name = 'mistral/tasks/index.html'
def get_data(self):
client = api.mistralclient(self.request)
return client.tasks.list()

View File

@ -19,15 +19,8 @@ from django.utils.translation import ugettext_lazy as _
from horizon import tables
class ExecuteWorkflow(tables.LinkAction):
name = "execute"
verbose_name = _("Execute")
url = "horizon:mistral:workbooks:execute"
classes = ("ajax-modal", "btn-edit")
def tags_to_string(workbook):
return ', '.join(workbook.tags)
return ', '.join(workbook.tags) if workbook.tags else None
class WorkbooksTable(tables.DataTable):
@ -41,4 +34,3 @@ class WorkbooksTable(tables.DataTable):
class Meta:
name = "workbooks"
verbose_name = _("Workbooks")
row_actions = (ExecuteWorkflow,)

View File

@ -1,11 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Execute workbook" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Execute workbook") %}
{% endblock page_header %}
{% block main %}
{% include 'mistral/workbooks/_execute.html' %}
{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends 'base.html' %}
{% extends 'mistral/default/base.html' %}
{% load i18n %}
{% block title %}{% trans "Workbooks" %}{% endblock %}

View File

@ -18,12 +18,10 @@ from django.conf.urls import patterns # noqa
from django.conf.urls import url # noqa
from mistraldashboard.workbooks.views import IndexView
from mistraldashboard.workbooks.views import ExecuteView
WORKBOOKS = r'^(?P<workbook_name>[^/]+)/%s$'
urlpatterns = patterns(
'',
url(r'^$', IndexView.as_view(), name='index'),
url(WORKBOOKS % 'execute', ExecuteView.as_view(), name='execute'),
)

View File

@ -14,14 +14,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from django.core.urlresolvers import reverse_lazy
from horizon import tables
from horizon import forms
from mistraldashboard import api
from mistraldashboard.workbooks.tables import WorkbooksTable
from mistraldashboard.workbooks.forms import ExecuteForm
class IndexView(tables.DataTableView):
@ -30,19 +26,3 @@ class IndexView(tables.DataTableView):
def get_data(self):
return api.mistralclient(self.request).workbooks.list()
class ExecuteView(forms.ModalFormView):
form_class = ExecuteForm
template_name = 'mistral/workbooks/execute.html'
success_url = reverse_lazy("horizon:mistral:executions:index")
def get_context_data(self, **kwargs):
context = super(ExecuteView, self).get_context_data(**kwargs)
context["workbook_name"] = self.kwargs['workbook_name']
return context
def get_initial(self, **kwargs):
return {
'workbook_name': self.kwargs['workbook_name']
}

View File

View File

@ -16,7 +16,6 @@
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
import yaml
from horizon import exceptions
from horizon import forms
@ -26,29 +25,17 @@ from mistraldashboard import api
class ExecuteForm(forms.SelfHandlingForm):
workbook_name = forms.CharField(label=_("Workbook"),
workflow_name = forms.CharField(label=_("Workflow"),
required=True,
widget=forms.TextInput(
attrs={'readonly': 'readonly'}))
task = forms.ChoiceField(label=_("Task"),
required=True,
help_text=_("Task to start the execution"))
context = forms.CharField(label=_("Context"),
required=False,
initial="{}",
widget=forms.widgets.Textarea())
def __init__(self, request, *args, **kwargs):
super(ExecuteForm, self).__init__(request, *args, **kwargs)
client = api.mistralclient(request)
workbook_definition = client.workbooks.get_definition(
kwargs['initial']['workbook_name'])
workbook = yaml.safe_load(workbook_definition)
task_choices = [('', _("Select a task"))]
for task in workbook['Workflow']['tasks']:
task_choices.append((task, task))
self.fields['task'].choices = task_choices
workflow_input = forms.CharField(label=_("Input"),
required=False,
initial="{}",
widget=forms.widgets.Textarea())
task_name = forms.CharField(label=_("Task name"),
required=False,
widget=forms.TextInput())
def handle(self, request, data):
try:
@ -58,6 +45,6 @@ class ExecuteForm(forms.SelfHandlingForm):
messages.success(request, msg)
return True
except Exception:
msg = _('Failed to execute workbook "%s".') % data['workbook_name']
redirect = reverse('horizon:mistral:workbooks:index')
msg = _('Failed to execute workflow "%s".') % data['workflow_name']
redirect = reverse('horizon:mistral:workflows:index')
exceptions.handle(request, msg, redirect=redirect)

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 Workflows(horizon.Panel):
name = _("Workflows")
slug = 'workflows'
dashboard.MistralDashboard.register(Workflows)

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 tables
class ExecuteWorkflow(tables.LinkAction):
name = "execute"
verbose_name = _("Execute")
url = "horizon:mistral:workflows:execute"
classes = ("ajax-modal", "btn-edit")
def tags_to_string(workflow):
return ', '.join(workflow.tags) if workflow.tags else None
class WorkbooksTable(tables.DataTable):
name = tables.Column("name", verbose_name=_("Name"))
description = tables.Column("description", verbose_name=_("Description"))
tags = tables.Column(tags_to_string, verbose_name=_("Tags"))
def get_object_id(self, datum):
return datum.name
class Meta:
name = "workflows"
verbose_name = _("Workflows")
row_actions = (ExecuteWorkflow,)

View File

@ -3,7 +3,7 @@
{% load url from future %}
{% block form_id %}execute_form{% endblock %}
{% block form_action %}{% url 'horizon:mistral:workbooks:execute' workbook_name %}{% endblock %}
{% block form_action %}{% url 'horizon:mistral:workflows:execute' workflow_name %}{% endblock %}
{% block modal-header %}{% trans "Execute" %}{% endblock %}
@ -15,11 +15,11 @@
</div>
<div class="right">
<h3>{% trans "Description:" %}</h3>
<p>{% trans "From here you can execute a workbook." %}</p>
<p>{% trans "From here you can execute a workflow." %}</p>
</div>
{% endblock %}
{% block modal-footer %}
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Execute" %}" />
<a href="{% url 'horizon:mistral:workbooks:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
<a href="{% url 'horizon:mistral:workflows:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'mistral/default/base.html' %}
{% load i18n %}
{% block title %}{% trans "Execute workflow" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Execute workflow") %}
{% endblock page_header %}
{% block main %}
{% include 'mistral/workflows/_execute.html' %}
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'mistral/default/base.html' %}
{% load i18n %}
{% block title %}{% trans "Workflows" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Workflows") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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 patterns # noqa
from django.conf.urls import url # noqa
from mistraldashboard.workflows.views import IndexView
from mistraldashboard.workflows.views import ExecuteView
WORKFLOWS = r'^(?P<workflow_name>[^/]+)/%s$'
urlpatterns = patterns(
'',
url(r'^$', IndexView.as_view(), name='index'),
url(WORKFLOWS % 'execute', ExecuteView.as_view(), name='execute'),
)

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - StackStorm, Inc.
#
# 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_lazy
from horizon import tables
from horizon import forms
from mistraldashboard import api
from mistraldashboard.workflows.tables import WorkbooksTable
from mistraldashboard.workflows.forms import ExecuteForm
class IndexView(tables.DataTableView):
table_class = WorkbooksTable
template_name = 'mistral/workflows/index.html'
def get_data(self):
return api.mistralclient(self.request).workflows.list()
class ExecuteView(forms.ModalFormView):
form_class = ExecuteForm
template_name = 'mistral/workflows/execute.html'
success_url = reverse_lazy("horizon:mistral:executions:index")
def get_context_data(self, **kwargs):
context = super(ExecuteView, self).get_context_data(**kwargs)
context["workflow_name"] = self.kwargs['workflow_name']
return context
def get_initial(self, **kwargs):
return {
'workflow_name': self.kwargs['workflow_name']
}