diff --git a/horizon/static/framework/util/tech-debt/modal-form-update-metadata-ctrl.js b/horizon/static/framework/util/tech-debt/modal-form-update-metadata-ctrl.js
deleted file mode 100644
index a2c7994819..0000000000
--- a/horizon/static/framework/util/tech-debt/modal-form-update-metadata-ctrl.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * 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.
- */
-(function () {
- 'use strict';
-
- angular
- .module('horizon.framework.util.tech-debt')
- .controller('hzModalFormUpdateMetadataController', hzModalFormUpdateMetadataController);
-
- hzModalFormUpdateMetadataController.$inject = ['$scope', '$window'];
-
- function hzModalFormUpdateMetadataController($scope, $window) {
- var ctrl = this;
-
- ctrl.tree = null;
- ctrl.available = $window.available_metadata.namespaces;
- ctrl.existing = $window.existing_metadata;
-
- ctrl.saveMetadata = function () {
- var metadata = [];
- angular.forEach(ctrl.tree.getExisting(), function (value, key) {
- metadata.push({
- key: key,
- value: value
-
- });
-
- });
-
- ctrl.metadata = angular.toJson(metadata);
-
- };
-
- }
-
-}());
diff --git a/horizon/templates/horizon/common/_modal_form_update_metadata.html b/horizon/templates/horizon/common/_modal_form_update_metadata.html
deleted file mode 100644
index af654972b3..0000000000
--- a/horizon/templates/horizon/common/_modal_form_update_metadata.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{% extends "horizon/common/_modal_form.html" %}
-
-{% load i18n %}
-
-{% block form_name %}metadataForm{% endblock %}
-{% block form_validation %}novalidate{% endblock %}
-{% block ng_controller %}hzModalFormUpdateMetadataController as metadataCtrl{% endblock %}
-
-{% block modal-body %}
-
-
-{% endblock %}
-
-{% block modal-footer %}
-
-{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/aggregates/constants.py b/openstack_dashboard/dashboards/admin/aggregates/constants.py
index 41e54fe907..4b915c2798 100644
--- a/openstack_dashboard/dashboards/admin/aggregates/constants.py
+++ b/openstack_dashboard/dashboards/admin/aggregates/constants.py
@@ -17,9 +17,5 @@ AGGREGATES_CREATE_URL = 'horizon:admin:aggregates:create'
AGGREGATES_CREATE_VIEW_TEMPLATE = 'admin/aggregates/create.html'
AGGREGATES_MANAGE_HOSTS_URL = 'horizon:admin:aggregates:manage_hosts'
AGGREGATES_MANAGE_HOSTS_TEMPLATE = 'admin/aggregates/manage_hosts.html'
-AGGREGATES_UPDATE_METADATA_URL = 'horizon:admin:aggregates:update_metadata'
-AGGREGATES_UPDATE_METADATA_TEMPLATE = 'admin/aggregates/update_metadata.html'
-AGGREGATES_UPDATE_METADATA_SUBTEMPLATE = \
- 'admin/aggregates/_update_metadata.html'
AGGREGATES_UPDATE_URL = 'horizon:admin:aggregates:update'
AGGREGATES_UPDATE_VIEW_TEMPLATE = 'admin/aggregates/update.html'
diff --git a/openstack_dashboard/dashboards/admin/aggregates/forms.py b/openstack_dashboard/dashboards/admin/aggregates/forms.py
index bd261868c6..07d88704c3 100644
--- a/openstack_dashboard/dashboards/admin/aggregates/forms.py
+++ b/openstack_dashboard/dashboards/admin/aggregates/forms.py
@@ -10,8 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
-
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
@@ -49,32 +47,3 @@ class UpdateAggregateForm(forms.SelfHandlingForm):
exceptions.handle(request,
_('Unable to update the aggregate.'))
return True
-
-
-class UpdateMetadataForm(forms.SelfHandlingForm):
-
- def handle(self, request, data):
- id = self.initial['id']
- old_metadata = self.initial['metadata']
-
- try:
- new_metadata = json.loads(self.data['metadata'])
-
- metadata = dict(
- (item['key'], str(item['value']))
- for item in new_metadata
- )
-
- for key in old_metadata:
- if key not in metadata:
- metadata[key] = None
-
- api.nova.aggregate_set_metadata(request, id, metadata)
- message = _('Metadata successfully updated.')
- messages.success(request, message)
- except Exception:
- msg = _('Unable to update the aggregate metadata.')
- exceptions.handle(request, msg)
-
- return False
- return True
diff --git a/openstack_dashboard/dashboards/admin/aggregates/tables.py b/openstack_dashboard/dashboards/admin/aggregates/tables.py
index dfbbc53098..7d4e61b169 100644
--- a/openstack_dashboard/dashboards/admin/aggregates/tables.py
+++ b/openstack_dashboard/dashboards/admin/aggregates/tables.py
@@ -62,9 +62,19 @@ class ManageHostsAction(tables.LinkAction):
class UpdateMetadataAction(tables.LinkAction):
name = "update-metadata"
verbose_name = _("Update Metadata")
- url = constants.AGGREGATES_UPDATE_METADATA_URL
- classes = ("ajax-modal",)
+ ajax = False
icon = "pencil"
+ attrs = {"ng-controller": "MetadataModalHelperController as modal"}
+
+ def __init__(self, attrs=None, **kwargs):
+ kwargs['preempt'] = True
+ super(UpdateMetadataAction, self).__init__(attrs, **kwargs)
+
+ def get_link_url(self, datum):
+ image_id = self.table.get_object_id(datum)
+ self.attrs['ng-click'] = (
+ "modal.openMetadataModal('aggregate', '%s', true)" % image_id)
+ return "javascript:void(0);"
class UpdateAggregateAction(tables.LinkAction):
diff --git a/openstack_dashboard/dashboards/admin/aggregates/templates/aggregates/_update_metadata.html b/openstack_dashboard/dashboards/admin/aggregates/templates/aggregates/_update_metadata.html
deleted file mode 100644
index 9f2e0c414f..0000000000
--- a/openstack_dashboard/dashboards/admin/aggregates/templates/aggregates/_update_metadata.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends 'horizon/common/_modal_form_update_metadata.html' %}
-{% load i18n %}
-{% load url from future %}
-{% block title %}{% trans "Update Aggregate Metadata" %}{% endblock %}
-
-{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Update Aggregate Metadata") %}
-{% endblock page_header %}
-
-{% block form_action %}{% url 'horizon:admin:aggregates:update_metadata' id %}{% endblock %}
-{% block modal-header %}{% trans "Update Aggregate Metadata" %}{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/aggregates/templates/aggregates/update_metadata.html b/openstack_dashboard/dashboards/admin/aggregates/templates/aggregates/update_metadata.html
deleted file mode 100644
index de3dbfd735..0000000000
--- a/openstack_dashboard/dashboards/admin/aggregates/templates/aggregates/update_metadata.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% block title %}{% trans "Update Aggregate Metadata" %}{% endblock %}
-
-{% block main %}
- {% include 'admin/aggregates/_update_metadata.html' %}
-{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/aggregates/tests.py b/openstack_dashboard/dashboards/admin/aggregates/tests.py
index a716f1f87b..e95b1b17e1 100644
--- a/openstack_dashboard/dashboards/admin/aggregates/tests.py
+++ b/openstack_dashboard/dashboards/admin/aggregates/tests.py
@@ -10,8 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
-
import mock
from django.core.urlresolvers import reverse
@@ -451,82 +449,3 @@ class ManageHostsTests(test.BaseAdminViewTests):
form_data,
addAggregate=False,
cleanAggregates=True)
-
-
-class HostAggregateMetadataTests(test.BaseAdminViewTests):
-
- @test.create_stubs({api.nova: ('aggregate_get',),
- api.glance: ('metadefs_namespace_list',
- 'metadefs_namespace_get')})
- def test_host_aggregate_metadata_get(self):
- aggregate = self.aggregates.first()
- api.nova.aggregate_get(
- IsA(http.HttpRequest),
- str(aggregate.id)
- ).AndReturn(aggregate)
-
- namespaces = self.metadata_defs.list()
-
- api.glance.metadefs_namespace_list(
- IsA(http.HttpRequest),
- filters={'resource_types': ['OS::Nova::Aggregate']}
- ).AndReturn((namespaces, False, False))
-
- for namespace in namespaces:
- api.glance.metadefs_namespace_get(
- IsA(http.HttpRequest),
- namespace.namespace,
- 'OS::Nova::Aggregate'
- ).AndReturn(namespace)
-
- self.mox.ReplayAll()
-
- res = self.client.get(
- reverse(constants.AGGREGATES_UPDATE_METADATA_URL,
- args=[aggregate.id]))
-
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(
- res,
- constants.AGGREGATES_UPDATE_METADATA_TEMPLATE
- )
- self.assertTemplateUsed(
- res,
- constants.AGGREGATES_UPDATE_METADATA_SUBTEMPLATE
- )
- self.assertContains(res, 'namespace_1')
- self.assertContains(res, 'namespace_2')
- self.assertContains(res, 'namespace_3')
- self.assertContains(res, 'namespace_4')
-
- @test.create_stubs({api.nova: ('aggregate_get', 'aggregate_set_metadata')})
- def test_host_aggregate_metadata_update(self):
- aggregate = self.aggregates.first()
- aggregate.metadata = {'key': 'test_key', 'value': 'test_value'}
-
- api.nova.aggregate_get(
- IsA(http.HttpRequest),
- str(aggregate.id)
- ).AndReturn(aggregate)
-
- api.nova.aggregate_set_metadata(
- IsA(http.HttpRequest),
- str(aggregate.id),
- {'value': None, 'key': None, 'test_key': 'test_value'}
- ).AndReturn(None)
-
- self.mox.ReplayAll()
-
- form_data = {"metadata": json.dumps([aggregate.metadata])}
-
- res = self.client.post(
- reverse(constants.AGGREGATES_UPDATE_METADATA_URL,
- args=(aggregate.id,)), form_data)
-
- self.assertEqual(res.status_code, 302)
- self.assertNoFormErrors(res)
- self.assertMessageCount(success=1)
- self.assertRedirectsNoFollow(
- res,
- reverse(constants.AGGREGATES_INDEX_URL)
- )
diff --git a/openstack_dashboard/dashboards/admin/aggregates/urls.py b/openstack_dashboard/dashboards/admin/aggregates/urls.py
index 49650b5c78..50ac748bda 100644
--- a/openstack_dashboard/dashboards/admin/aggregates/urls.py
+++ b/openstack_dashboard/dashboards/admin/aggregates/urls.py
@@ -25,8 +25,6 @@ urlpatterns = patterns(
views.CreateView.as_view(), name='create'),
url(r'^(?P[^/]+)/update/$',
views.UpdateView.as_view(), name='update'),
- url(r'^(?P[^/]+)/update_metadata/$',
- views.UpdateMetadataView.as_view(), name='update_metadata'),
url(r'^(?P[^/]+)/manage_hosts/$',
views.ManageHostsView.as_view(), name='manage_hosts'),
)
diff --git a/openstack_dashboard/dashboards/admin/aggregates/views.py b/openstack_dashboard/dashboards/admin/aggregates/views.py
index fd0b2b270a..515739450e 100644
--- a/openstack_dashboard/dashboards/admin/aggregates/views.py
+++ b/openstack_dashboard/dashboards/admin/aggregates/views.py
@@ -10,16 +10,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
-
-from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import tables
-from horizon.utils import memoized
from horizon import workflows
from openstack_dashboard import api
@@ -101,55 +97,6 @@ class UpdateView(forms.ModalFormView):
return self._object
-class UpdateMetadataView(forms.ModalFormView):
- template_name = constants.AGGREGATES_UPDATE_METADATA_TEMPLATE
- form_class = aggregate_forms.UpdateMetadataForm
- success_url = reverse_lazy(constants.AGGREGATES_INDEX_URL)
- page_title = _("Update Aggregate Metadata")
-
- def get_initial(self):
- aggregate = self.get_object()
- return {'id': self.kwargs["id"], 'metadata': aggregate.metadata}
-
- def get_context_data(self, **kwargs):
- context = super(UpdateMetadataView, self).get_context_data(**kwargs)
-
- aggregate = self.get_object()
- context['existing_metadata'] = json.dumps(aggregate.metadata)
-
- resource_type = 'OS::Nova::Aggregate'
- namespaces = []
- try:
- # metadefs_namespace_list() returns a tuple with list as 1st elem
- namespaces = [
- api.glance.metadefs_namespace_get(self.request, x.namespace,
- resource_type)
- for x in api.glance.metadefs_namespace_list(
- self.request,
- filters={'resource_types': [resource_type]}
- )[0]
- ]
-
- except Exception:
- msg = _('Unable to retrieve available metadata for aggregate.')
- exceptions.handle(self.request, msg)
-
- context['available_metadata'] = json.dumps({'namespaces': namespaces})
- context['id'] = self.kwargs['id']
- return context
-
- @memoized.memoized_method
- def get_object(self):
- aggregate_id = self.kwargs['id']
- try:
- return api.nova.aggregate_get(self.request, aggregate_id)
- except Exception:
- msg = _('Unable to retrieve the aggregate to be '
- 'updated.')
- exceptions.handle(
- self.request, msg, redirect=reverse(INDEX_URL))
-
-
class ManageHostsView(workflows.WorkflowView):
template_name = constants.AGGREGATES_MANAGE_HOSTS_TEMPLATE
workflow_class = aggregate_workflows.ManageAggregateHostsWorkflow
diff --git a/openstack_dashboard/dashboards/admin/flavors/constants.py b/openstack_dashboard/dashboards/admin/flavors/constants.py
index 8d304d06e9..4f6ffcee4e 100644
--- a/openstack_dashboard/dashboards/admin/flavors/constants.py
+++ b/openstack_dashboard/dashboards/admin/flavors/constants.py
@@ -16,6 +16,3 @@ FLAVORS_CREATE_URL = 'horizon:admin:flavors:create'
FLAVORS_CREATE_VIEW_TEMPLATE = 'admin/flavors/create.html'
FLAVORS_UPDATE_URL = 'horizon:admin:flavors:update'
FLAVORS_UPDATE_VIEW_TEMPLATE = 'admin/flavors/update.html'
-FLAVORS_UPDATE_METADATA_URL = 'horizon:admin:flavors:update_metadata'
-FLAVORS_UPDATE_METADATA_TEMPLATE = 'admin/flavors/update_metadata.html'
-FLAVORS_UPDATE_METADATA_SUBTEMPLATE = 'admin/flavors/_update_metadata.html'
diff --git a/openstack_dashboard/dashboards/admin/flavors/forms.py b/openstack_dashboard/dashboards/admin/flavors/forms.py
deleted file mode 100644
index 81057ea386..0000000000
--- a/openstack_dashboard/dashboards/admin/flavors/forms.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# 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.
-
-
-import json
-
-from django.utils.translation import ugettext_lazy as _
-
-from horizon import exceptions
-from horizon import forms
-from horizon import messages
-
-from openstack_dashboard import api
-
-
-class UpdateMetadataForm(forms.SelfHandlingForm):
-
- def handle(self, request, data):
- id = self.initial['id']
- old_metadata = self.initial['metadata']
-
- try:
- new_metadata = json.loads(self.data['metadata'])
-
- metadata = dict(
- (item['key'], str(item['value']))
- for item in new_metadata
- )
- api.nova.flavor_extra_set(request, id, metadata)
-
- remove_keys = [key for key in old_metadata if key not in metadata]
-
- api.nova.flavor_extra_delete(request, id, remove_keys)
-
- message = _('Metadata successfully updated.')
- messages.success(request, message)
- except Exception:
- exceptions.handle(request,
- _('Unable to update the flavor metadata.'))
- return False
- return True
diff --git a/openstack_dashboard/dashboards/admin/flavors/tables.py b/openstack_dashboard/dashboards/admin/flavors/tables.py
index 4b11e8599a..4b68d2e172 100644
--- a/openstack_dashboard/dashboards/admin/flavors/tables.py
+++ b/openstack_dashboard/dashboards/admin/flavors/tables.py
@@ -66,11 +66,29 @@ class UpdateFlavor(tables.LinkAction):
class UpdateMetadata(tables.LinkAction):
- url = "horizon:admin:flavors:update_metadata"
name = "update_metadata"
verbose_name = _("Update Metadata")
- classes = ("ajax-modal",)
+ ajax = False
icon = "pencil"
+ attrs = {"ng-controller": "MetadataModalHelperController as modal"}
+
+ def __init__(self, **kwargs):
+ kwargs['preempt'] = True
+ super(UpdateMetadata, self).__init__(**kwargs)
+
+ def get_link_url(self, datum):
+ obj_id = self.table.get_object_id(datum)
+ self.attrs['ng-click'] = (
+ "modal.openMetadataModal('flavor', '%s', true)" % obj_id)
+ return "javascript:void(0);"
+
+
+class UpdateMetadataColumn(tables.Column):
+ def get_link_url(self, datum):
+ obj_id = self.table.get_object_id(datum)
+ self.link_attrs['ng-click'] = (
+ "modal.openMetadataModal('flavor', '%s', true)" % obj_id)
+ return "javascript:void(0);"
class ModifyAccess(tables.LinkAction):
@@ -138,12 +156,13 @@ class FlavorsTable(tables.DataTable):
verbose_name=_("Public"),
empty_value=False,
filters=(filters.yesno, filters.capfirst))
- extra_specs = tables.Column(get_extra_specs,
- verbose_name=_("Metadata"),
- link="horizon:admin:flavors:update_metadata",
- link_classes=("ajax-modal",),
- empty_value=False,
- filters=(filters.yesno, filters.capfirst))
+ extra_specs = UpdateMetadataColumn(
+ get_extra_specs,
+ verbose_name=_("Metadata"),
+ link=True,
+ empty_value=False,
+ filters=(filters.yesno, filters.capfirst),
+ link_attrs={'ng-controller': 'MetadataModalHelperController as modal'})
class Meta(object):
name = "flavors"
diff --git a/openstack_dashboard/dashboards/admin/flavors/templates/flavors/_update_metadata.html b/openstack_dashboard/dashboards/admin/flavors/templates/flavors/_update_metadata.html
deleted file mode 100644
index 10c77f11f7..0000000000
--- a/openstack_dashboard/dashboards/admin/flavors/templates/flavors/_update_metadata.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends 'horizon/common/_modal_form_update_metadata.html' %}
-{% load i18n %}
-{% load url from future %}
-{% block title %}{% trans "Update Flavor Metadata" %}{% endblock %}
-
-{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Update Flavor Metadata") %}
-{% endblock page_header %}
-
-{% block form_action %}{% url 'horizon:admin:flavors:update_metadata' id %}{% endblock %}
-{% block modal-header %}{% trans "Update Flavor Metadata" %}{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/flavors/templates/flavors/update_metadata.html b/openstack_dashboard/dashboards/admin/flavors/templates/flavors/update_metadata.html
deleted file mode 100644
index f0b6c66489..0000000000
--- a/openstack_dashboard/dashboards/admin/flavors/templates/flavors/update_metadata.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% block title %}{% trans "Update Flavor Metadata" %}{% endblock %}
-
-{% block main %}
- {% include 'admin/flavors/_update_metadata.html' %}
-{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/flavors/tests.py b/openstack_dashboard/dashboards/admin/flavors/tests.py
index b9922f9880..1f7a8d438a 100644
--- a/openstack_dashboard/dashboards/admin/flavors/tests.py
+++ b/openstack_dashboard/dashboards/admin/flavors/tests.py
@@ -10,8 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
-
from django.core.urlresolvers import reverse
from django import http
from mox3.mox import IsA # noqa
@@ -764,117 +762,3 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests):
data = {'eph_gb': -1}
self.generic_update_flavor_invalid_data_form_fails(override_data=data,
error_msg=error)
-
-
-class FlavorUpdateMetadataViewTest(test.BaseAdminViewTests):
- @test.create_stubs({api.nova: ('flavor_get_extras',),
- api.glance: ('metadefs_namespace_list',
- 'metadefs_namespace_get')})
- def test_flavor_metadata_get(self):
- #
- flavor = self.flavors.list()[3]
-
- namespaces = self.metadata_defs.list()
-
- api.nova.flavor_get_extras(
- IsA(http.HttpRequest),
- flavor.id
- ).AndReturn([flavor.extra_specs])
- api.glance.metadefs_namespace_list(
- IsA(http.HttpRequest),
- filters={
- 'resource_types': ['OS::Nova::Flavor']
- }
- ).AndReturn((namespaces, False, False))
-
- for namespace in namespaces:
- api.glance.metadefs_namespace_get(
- IsA(http.HttpRequest),
- namespace.namespace,
- 'OS::Nova::Flavor'
- ).AndReturn(namespace)
-
- self.mox.ReplayAll()
- res = self.client.get(
- reverse(
- constants.FLAVORS_UPDATE_METADATA_URL,
- kwargs={'id': flavor.id}
- )
- )
-
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(
- res,
- constants.FLAVORS_UPDATE_METADATA_TEMPLATE
- )
- self.assertTemplateUsed(
- res,
- constants.FLAVORS_UPDATE_METADATA_SUBTEMPLATE
- )
- self.assertContains(res, 'namespace_1')
- self.assertContains(res, 'namespace_2')
- self.assertContains(res, 'namespace_3')
- self.assertContains(res, 'namespace_4')
-
- @test.create_stubs({api.nova: ('flavor_get_extras',
- 'flavor_extra_set',
- 'flavor_extra_delete')})
- def test_flavor_metadata_update(self):
- #
- flavor = self.flavors.list()[3]
-
- api.nova.flavor_get_extras(
- IsA(http.HttpRequest),
- flavor.id
- ).AndReturn([flavor.extra_specs])
- api.nova.flavor_extra_set(
- IsA(http.HttpRequest),
- flavor.id,
- {'key_mock': 'value_mock'}
- ).AndReturn(None)
- api.nova.flavor_extra_delete(
- IsA(http.HttpRequest),
- flavor.id,
- []
- ).AndReturn(None)
-
- self.mox.ReplayAll()
-
- metadata = [{'value': 'value_mock', 'key': 'key_mock'}]
- formData = {'metadata': json.dumps(metadata)}
-
- res = self.client.post(
- reverse(
- constants.FLAVORS_UPDATE_METADATA_URL,
- kwargs={'id': flavor.id}
- ),
- formData
- )
-
- self.assertEqual(res.status_code, 302)
- self.assertNoFormErrors(res)
- self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
- self.assertMessageCount(success=1)
-
- @test.create_stubs({api.nova: ('flavor_get_extras',)})
- def test_flavor_metadata_get_get_extras_fails(self):
- #
- flavor = self.flavors.list()[3]
-
- api.nova.flavor_get_extras(
- IsA(http.HttpRequest),
- flavor.id
- ).AndRaise(self.exceptions.nova)
-
- self.mox.ReplayAll()
-
- res = self.client.get(
- reverse(
- constants.FLAVORS_UPDATE_METADATA_URL,
- kwargs={'id': flavor.id}
- )
- )
-
- self.assertEqual(res.status_code, 302)
- self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
- self.assertMessageCount(error=1)
diff --git a/openstack_dashboard/dashboards/admin/flavors/urls.py b/openstack_dashboard/dashboards/admin/flavors/urls.py
index daf563bfe6..1e3e52563c 100644
--- a/openstack_dashboard/dashboards/admin/flavors/urls.py
+++ b/openstack_dashboard/dashboards/admin/flavors/urls.py
@@ -26,7 +26,5 @@ urlpatterns = patterns(
'openstack_dashboard.dashboards.admin.flavors.views',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^create/$', views.CreateView.as_view(), name='create'),
- url(r'^(?P[^/]+)/update_metadata/$',
- views.UpdateMetadataView.as_view(), name='update_metadata'),
url(r'^(?P[^/]+)/update/$', views.UpdateView.as_view(), name='update'),
)
diff --git a/openstack_dashboard/dashboards/admin/flavors/views.py b/openstack_dashboard/dashboards/admin/flavors/views.py
index fec58e5983..70b8ac4083 100644
--- a/openstack_dashboard/dashboards/admin/flavors/views.py
+++ b/openstack_dashboard/dashboards/admin/flavors/views.py
@@ -16,22 +16,15 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
-
-from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
-from horizon import forms
from horizon import tables
-from horizon.utils import memoized
from horizon import workflows
from openstack_dashboard import api
-from openstack_dashboard.dashboards.admin.flavors \
- import forms as project_forms
from openstack_dashboard.dashboards.admin.flavors \
import tables as project_tables
from openstack_dashboard.dashboards.admin.flavors \
@@ -88,54 +81,3 @@ class UpdateView(workflows.WorkflowView):
'disk_gb': flavor.disk,
'swap_mb': flavor.swap or 0,
'eph_gb': getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral', None)}
-
-
-class UpdateMetadataView(forms.ModalFormView):
- template_name = "admin/flavors/update_metadata.html"
- form_class = project_forms.UpdateMetadataForm
- success_url = reverse_lazy('horizon:admin:flavors:index')
- page_title = _("Update Flavor Metadata")
-
- def get_initial(self):
- extra_specs_dict = self.get_object()
- return {'id': self.kwargs["id"], 'metadata': extra_specs_dict}
-
- def get_context_data(self, **kwargs):
- context = super(UpdateMetadataView, self).get_context_data(**kwargs)
-
- extra_specs_dict = self.get_object()
-
- context['existing_metadata'] = json.dumps(extra_specs_dict)
-
- resource_type = 'OS::Nova::Flavor'
-
- namespaces = []
- try:
- # metadefs_namespace_list() returns a tuple with list as 1st elem
- namespaces = [
- api.glance.metadefs_namespace_get(self.request, x.namespace,
- resource_type)
- for x in api.glance.metadefs_namespace_list(
- self.request,
- filters={'resource_types': [resource_type]}
- )[0]
- ]
-
- except Exception:
- msg = _('Unable to retrieve available metadata for flavors.')
- exceptions.handle(self.request, msg)
-
- context['available_metadata'] = json.dumps({'namespaces': namespaces})
- context['id'] = self.kwargs['id']
- return context
-
- @memoized.memoized_method
- def get_object(self):
- flavor_id = self.kwargs['id']
- try:
- extra_specs = api.nova.flavor_get_extras(self.request, flavor_id)
- return dict((i.key, i.value) for i in extra_specs)
- except Exception:
- msg = _('Unable to retrieve the flavor metadata.')
- exceptions.handle(self.request, msg,
- redirect=reverse(INDEX_URL))
diff --git a/openstack_dashboard/dashboards/admin/images/forms.py b/openstack_dashboard/dashboards/admin/images/forms.py
index b6603a2ea3..fdbbede46a 100644
--- a/openstack_dashboard/dashboards/admin/images/forms.py
+++ b/openstack_dashboard/dashboards/admin/images/forms.py
@@ -16,16 +16,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-
-import json
-
-from django.utils.translation import ugettext_lazy as _
-
-from horizon import exceptions
-from horizon import forms
-from horizon import messages
-
-from openstack_dashboard import api
from openstack_dashboard.dashboards.project.images.images \
import forms as images_forms
@@ -36,32 +26,3 @@ class AdminCreateImageForm(images_forms.CreateImageForm):
class AdminUpdateImageForm(images_forms.UpdateImageForm):
pass
-
-
-class UpdateMetadataForm(forms.SelfHandlingForm):
-
- def handle(self, request, data):
- id = self.initial['id']
- old_metadata = self.initial['metadata']
-
- try:
- new_metadata = json.loads(self.data['metadata'])
-
- metadata = dict(
- (item['key'], str(item['value']))
- for item in new_metadata
- )
-
- remove_props = [key for key in old_metadata if key not in metadata]
-
- api.glance.image_update_properties(request,
- id,
- remove_props,
- **metadata)
- message = _('Metadata successfully updated.')
- messages.success(request, message)
- except Exception:
- exceptions.handle(request,
- _('Unable to update the image metadata.'))
- return False
- return True
diff --git a/openstack_dashboard/dashboards/admin/images/tables.py b/openstack_dashboard/dashboards/admin/images/tables.py
index a44aca96b6..c23e08ab7d 100644
--- a/openstack_dashboard/dashboards/admin/images/tables.py
+++ b/openstack_dashboard/dashboards/admin/images/tables.py
@@ -41,11 +41,21 @@ class AdminEditImage(project_tables.EditImage):
class UpdateMetadata(tables.LinkAction):
- url = "horizon:admin:images:update_metadata"
name = "update_metadata"
verbose_name = _("Update Metadata")
- classes = ("ajax-modal",)
+ ajax = False
icon = "pencil"
+ attrs = {"ng-controller": "MetadataModalHelperController as modal"}
+
+ def __init__(self, attrs=None, **kwargs):
+ kwargs['preempt'] = True
+ super(UpdateMetadata, self).__init__(attrs, **kwargs)
+
+ def get_link_url(self, datum):
+ image_id = self.table.get_object_id(datum)
+ self.attrs['ng-click'] = (
+ "modal.openMetadataModal('image', '%s', true)" % image_id)
+ return "javascript:void(0);"
class UpdateRow(tables.Row):
diff --git a/openstack_dashboard/dashboards/admin/images/templates/images/_update_metadata.html b/openstack_dashboard/dashboards/admin/images/templates/images/_update_metadata.html
deleted file mode 100644
index 6ff460c6e2..0000000000
--- a/openstack_dashboard/dashboards/admin/images/templates/images/_update_metadata.html
+++ /dev/null
@@ -1 +0,0 @@
-{% extends 'horizon/common/_modal_form_update_metadata.html' %}
diff --git a/openstack_dashboard/dashboards/admin/images/templates/images/update_metadata.html b/openstack_dashboard/dashboards/admin/images/templates/images/update_metadata.html
deleted file mode 100644
index e6515c6deb..0000000000
--- a/openstack_dashboard/dashboards/admin/images/templates/images/update_metadata.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% block title %}{% trans "Update Image Metadata" %}{% endblock %}
-
-{% block main %}
- {% include 'admin/images/_update_metadata.html' %}
-{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/images/tests.py b/openstack_dashboard/dashboards/admin/images/tests.py
index fc327b4932..d4298fb804 100644
--- a/openstack_dashboard/dashboards/admin/images/tests.py
+++ b/openstack_dashboard/dashboards/admin/images/tests.py
@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
-
from django.conf import settings
from django.core.urlresolvers import reverse
from django import http
@@ -26,10 +24,6 @@ from openstack_dashboard.test import helpers as test
from openstack_dashboard.dashboards.admin.images import tables
-IMAGE_METADATA_URL = reverse('horizon:admin:images:update_metadata',
- kwargs={
- "id": "007e7d55-fe1e-4c5c-bf08-44b4a4964822"})
-
class ImageCreateViewTest(test.BaseAdminViewTests):
@test.create_stubs({api.glance: ('image_list_detailed',)})
@@ -138,64 +132,6 @@ class ImagesViewTest(test.BaseAdminViewTests):
1)
self.assertContains(res, 'test_tenant', 2, 200)
- @test.create_stubs({api.glance: ('image_get',
- 'metadefs_namespace_list',
- 'metadefs_namespace_get')})
- def test_images_metadata_get(self):
- image = self.images.first()
-
- api.glance.image_get(
- IsA(http.HttpRequest),
- image.id
- ).AndReturn(image)
-
- namespaces = self.metadata_defs.list()
-
- api.glance.metadefs_namespace_list(IsA(http.HttpRequest), filters={
- 'resource_types': ['OS::Glance::Image']}).AndReturn(
- (namespaces, False, False))
-
- for namespace in namespaces:
- api.glance.metadefs_namespace_get(
- IsA(http.HttpRequest),
- namespace.namespace,
- 'OS::Glance::Image'
- ).AndReturn(namespace)
-
- self.mox.ReplayAll()
- res = self.client.get(IMAGE_METADATA_URL)
-
- self.assertTemplateUsed(res, 'admin/images/update_metadata.html')
- self.assertContains(res, 'namespace_1')
- self.assertContains(res, 'namespace_2')
- self.assertContains(res, 'namespace_3')
- self.assertContains(res, 'namespace_4')
-
- @test.create_stubs({api.glance: ('image_get', 'image_update_properties')})
- def test_images_metadata_update(self):
- image = self.images.first()
-
- api.glance.image_get(
- IsA(http.HttpRequest),
- image.id
- ).AndReturn(image)
- api.glance.image_update_properties(
- IsA(http.HttpRequest), image.id, ['image_type'],
- hw_machine_type='mock_value').AndReturn(None)
-
- self.mox.ReplayAll()
-
- metadata = [{"value": "mock_value", "key": "hw_machine_type"}]
- formData = {"metadata": json.dumps(metadata)}
-
- res = self.client.post(IMAGE_METADATA_URL, formData)
-
- self.assertNoFormErrors(res)
- self.assertMessageCount(success=1)
- self.assertRedirectsNoFollow(
- res, reverse('horizon:admin:images:index')
- )
-
@override_settings(API_RESULT_PAGE_SIZE=2)
@test.create_stubs({api.glance: ('image_list_detailed',),
api.keystone: ('tenant_list',)})
diff --git a/openstack_dashboard/dashboards/admin/images/urls.py b/openstack_dashboard/dashboards/admin/images/urls.py
index 73995a1b96..b8db5fa772 100644
--- a/openstack_dashboard/dashboards/admin/images/urls.py
+++ b/openstack_dashboard/dashboards/admin/images/urls.py
@@ -28,8 +28,6 @@ urlpatterns = patterns(
url(r'^create/$', views.CreateView.as_view(), name='create'),
url(r'^(?P[^/]+)/update/$',
views.UpdateView.as_view(), name='update'),
- url(r'^(?P[^/]+)/update_metadata/$',
- views.UpdateMetadataView.as_view(), name='update_metadata'),
url(r'^(?P[^/]+)/detail/$',
views.DetailView.as_view(), name='detail')
)
diff --git a/openstack_dashboard/dashboards/admin/images/views.py b/openstack_dashboard/dashboards/admin/images/views.py
index 8ad26540dd..1eaa6a9de9 100644
--- a/openstack_dashboard/dashboards/admin/images/views.py
+++ b/openstack_dashboard/dashboards/admin/images/views.py
@@ -16,21 +16,16 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
import logging
from oslo_utils import units
-import six
-from django import conf
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
-from horizon import forms
from horizon import tables
-from horizon.utils import memoized
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.images.images import views
@@ -149,81 +144,3 @@ class DetailView(views.DetailView):
context["url"] = reverse('horizon:admin:images:index')
context["actions"] = table.render_row_actions(context["image"])
return context
-
-
-class UpdateMetadataView(forms.ModalFormView):
- template_name = "admin/images/update_metadata.html"
- modal_header = _("Update Image")
- form_id = "update_image_form"
- form_class = project_forms.UpdateMetadataForm
- submit_url = "horizon:admin:images:update_metadata"
- success_url = reverse_lazy('horizon:admin:images:index')
- page_title = _("Update Image Metadata")
-
- def get_initial(self):
- image = self.get_object()
- return {'id': self.kwargs["id"], 'metadata': image.properties}
-
- def get_context_data(self, **kwargs):
- context = super(UpdateMetadataView, self).get_context_data(**kwargs)
-
- image = self.get_object()
- reserved_props = getattr(conf.settings,
- 'IMAGE_RESERVED_CUSTOM_PROPERTIES', [])
- image.properties = dict((k, v)
- for (k, v) in six.iteritems(image.properties)
- if k not in reserved_props)
- context['existing_metadata'] = json.dumps(image.properties)
- args = (self.kwargs['id'],)
- context['submit_url'] = reverse(self.submit_url, args=args)
-
- resource_type = 'OS::Glance::Image'
- namespaces = []
- try:
- # metadefs_namespace_list() returns a tuple with list as 1st elem
- available_namespaces = [x.namespace for x in
- api.glance.metadefs_namespace_list(
- self.request,
- filters={"resource_types":
- [resource_type]}
- )[0]]
- for namespace in available_namespaces:
- details = api.glance.metadefs_namespace_get(self.request,
- namespace,
- resource_type)
- # Filter out reserved custom properties from namespace
- if reserved_props:
- if hasattr(details, 'properties'):
- details.properties = dict(
- (k, v)
- for (k, v) in six.iteritems(details.properties)
- if k not in reserved_props
- )
-
- if hasattr(details, 'objects'):
- for obj in details.objects:
- obj['properties'] = dict(
- (k, v)
- for (k, v) in six.iteritems(obj['properties'])
- if k not in reserved_props
- )
-
- namespaces.append(details)
-
- except Exception:
- msg = _('Unable to retrieve available properties for image.')
- exceptions.handle(self.request, msg)
-
- context['available_metadata'] = json.dumps({'namespaces': namespaces})
- context['id'] = self.kwargs['id']
- return context
-
- @memoized.memoized_method
- def get_object(self):
- image_id = self.kwargs['id']
- try:
- return api.glance.image_get(self.request, image_id)
- except Exception:
- msg = _('Unable to retrieve the image to be updated.')
- exceptions.handle(self.request, msg,
- redirect=reverse('horizon:admin:images:index'))