summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.zuul.yaml35
-rw-r--r--doc/source/configuration/settings.rst39
-rw-r--r--horizon/locale/cs/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/de/LC_MESSAGES/django.po17
-rw-r--r--horizon/locale/de/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/en_AU/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/en_GB/LC_MESSAGES/djangojs.po33
-rw-r--r--horizon/locale/eo/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/es/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/fr/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/id/LC_MESSAGES/djangojs.po33
-rw-r--r--horizon/locale/it/LC_MESSAGES/djangojs.po27
-rw-r--r--horizon/locale/ja/LC_MESSAGES/djangojs.po33
-rw-r--r--horizon/locale/ko_KR/LC_MESSAGES/django.po14
-rw-r--r--horizon/locale/ko_KR/LC_MESSAGES/djangojs.po32
-rw-r--r--horizon/locale/pt_BR/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/ru/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/tr_TR/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/zh_CN/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/locale/zh_TW/LC_MESSAGES/djangojs.po21
-rw-r--r--horizon/static/framework/widgets/load-edit/load-edit.directive.js51
-rw-r--r--horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js15
-rw-r--r--horizon/static/framework/widgets/load-edit/load-edit.html38
-rw-r--r--horizon/static/framework/widgets/metadata/display/display.scss5
-rw-r--r--horizon/static/framework/widgets/metadata/display/metadata-display.controller.js7
-rw-r--r--horizon/static/framework/widgets/metadata/display/metadata-display.html2
-rw-r--r--openstack_auth/locale/de/LC_MESSAGES/django.po89
-rw-r--r--openstack_auth/locale/eo/LC_MESSAGES/django.po85
-rw-r--r--openstack_auth/locale/ko_KR/LC_MESSAGES/django.po85
-rw-r--r--openstack_dashboard/api/cinder.py8
-rw-r--r--openstack_dashboard/api/microversions.py25
-rw-r--r--openstack_dashboard/api/neutron.py197
-rw-r--r--openstack_dashboard/api/nova.py25
-rw-r--r--openstack_dashboard/api/rest/neutron.py19
-rw-r--r--openstack_dashboard/api/rest/nova.py5
-rw-r--r--openstack_dashboard/dashboards/admin/instances/tests.py6
-rw-r--r--openstack_dashboard/dashboards/admin/instances/urls.py1
-rw-r--r--openstack_dashboard/dashboards/admin/instances/views.py5
-rw-r--r--openstack_dashboard/dashboards/admin/volumes/tables.py6
-rw-r--r--openstack_dashboard/dashboards/project/floating_ips/tests.py11
-rw-r--r--openstack_dashboard/dashboards/project/floating_ips/workflows.py28
-rw-r--r--openstack_dashboard/dashboards/project/instances/console.py3
-rw-r--r--openstack_dashboard/dashboards/project/instances/tests.py2
-rw-r--r--openstack_dashboard/dashboards/project/instances/views.py11
-rw-r--r--openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js2
-rw-r--r--openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html12
-rw-r--r--openstack_dashboard/dashboards/project/volumes/forms.py15
-rw-r--r--openstack_dashboard/dashboards/project/volumes/tables.py12
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/_show_transfer.html10
-rw-r--r--openstack_dashboard/dashboards/project/volumes/tests.py15
-rw-r--r--openstack_dashboard/dashboards/project/volumes/views.py8
-rw-r--r--openstack_dashboard/enabled/_1500_project_trunks_panel.py3
-rw-r--r--openstack_dashboard/local/local_settings.py.example4
-rw-r--r--openstack_dashboard/locale/cs/LC_MESSAGES/djangojs.po40
-rw-r--r--openstack_dashboard/locale/de/LC_MESSAGES/django.po30
-rw-r--r--openstack_dashboard/locale/de/LC_MESSAGES/djangojs.po76
-rw-r--r--openstack_dashboard/locale/en_AU/LC_MESSAGES/djangojs.po35
-rw-r--r--openstack_dashboard/locale/en_GB/LC_MESSAGES/django.po10
-rw-r--r--openstack_dashboard/locale/en_GB/LC_MESSAGES/djangojs.po264
-rw-r--r--openstack_dashboard/locale/es/LC_MESSAGES/djangojs.po23
-rw-r--r--openstack_dashboard/locale/fr/LC_MESSAGES/djangojs.po39
-rw-r--r--openstack_dashboard/locale/id/LC_MESSAGES/django.po10
-rw-r--r--openstack_dashboard/locale/id/LC_MESSAGES/djangojs.po268
-rw-r--r--openstack_dashboard/locale/it/LC_MESSAGES/djangojs.po33
-rw-r--r--openstack_dashboard/locale/ja/LC_MESSAGES/django.po19
-rw-r--r--openstack_dashboard/locale/ja/LC_MESSAGES/djangojs.po34
-rw-r--r--openstack_dashboard/locale/ko_KR/LC_MESSAGES/djangojs.po31
-rw-r--r--openstack_dashboard/locale/pt_BR/LC_MESSAGES/djangojs.po39
-rw-r--r--openstack_dashboard/locale/ru/LC_MESSAGES/djangojs.po40
-rw-r--r--openstack_dashboard/locale/tr_TR/LC_MESSAGES/djangojs.po38
-rw-r--r--openstack_dashboard/locale/zh_CN/LC_MESSAGES/djangojs.po34
-rw-r--r--openstack_dashboard/locale/zh_TW/LC_MESSAGES/djangojs.po34
-rw-r--r--openstack_dashboard/settings.py18
-rw-r--r--openstack_dashboard/static/app/core/openstack-service-api/neutron.service.js55
-rw-r--r--openstack_dashboard/static/app/core/openstack-service-api/neutron.service.spec.js76
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/actions.module.js37
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/actions.module.spec.js25
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/create.action.service.js169
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/create.action.service.spec.js170
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/create.workflow.service.js68
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/delete.action.service.js126
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/delete.action.service.spec.js273
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/edit.action.service.js148
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/edit.action.service.spec.js180
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/edit.workflow.service.js62
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/ports-extra.service.js142
-rw-r--r--openstack_dashboard/static/app/core/trunks/actions/ports-extra.service.spec.js112
-rw-r--r--openstack_dashboard/static/app/core/trunks/panel.html5
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-details.controller.js89
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-details.controller.spec.js64
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-details.help.html17
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-details.html53
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-parent-port.controller.js125
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-parent-port.controller.spec.js119
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-parent-port.help.html25
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-parent-port.html159
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-subports.controller.js152
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-subports.controller.spec.js169
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-subports.help.html65
-rw-r--r--openstack_dashboard/static/app/core/trunks/steps/trunk-subports.html176
-rw-r--r--openstack_dashboard/static/app/core/trunks/trunks.module.js23
-rw-r--r--openstack_dashboard/static/app/core/trunks/trunks.module.spec.js2
-rw-r--r--openstack_dashboard/static/app/core/trunks/trunks.service.js40
-rw-r--r--openstack_dashboard/static/app/core/trunks/trunks.service.spec.js5
-rw-r--r--openstack_dashboard/static/dashboard/scss/components/_messages.scss2
-rw-r--r--openstack_dashboard/static/js/horizon.networktopology.js7
-rw-r--r--openstack_dashboard/test/api_tests/microversions_tests.py108
-rw-r--r--openstack_dashboard/test/api_tests/neutron_rest_tests.py27
-rw-r--r--openstack_dashboard/test/api_tests/neutron_tests.py189
-rw-r--r--openstack_dashboard/test/api_tests/nova_tests.py19
-rw-r--r--openstack_dashboard/test/test_data/neutron_data.py1
-rw-r--r--openstack_dashboard/test/test_data/nova_data.py32
-rw-r--r--openstack_dashboard/test/tests/utils.py34
-rw-r--r--openstack_dashboard/utils/config.py68
-rw-r--r--openstack_dashboard/utils/config_types.py213
-rwxr-xr-xopenstack_dashboard/utils/settings.py13
-rw-r--r--releasenotes/notes/bp-mks-console-support-a943797a8bad14ca.yaml4
-rw-r--r--releasenotes/notes/bp-neutron-trunk-ui-queens-1d59df887b9a079a.yaml8
-rw-r--r--releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po25
-rw-r--r--releasenotes/source/locale/id/LC_MESSAGES/releasenotes.po22
-rw-r--r--requirements.txt4
-rw-r--r--setup.cfg4
-rw-r--r--tox.ini25
123 files changed, 4872 insertions, 1283 deletions
diff --git a/.zuul.yaml b/.zuul.yaml
index 397e099..fab5a13 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -7,6 +7,7 @@
7 - ^releasenotes/.*$ 7 - ^releasenotes/.*$
8 - ^horizon/locale/.*$ 8 - ^horizon/locale/.*$
9 - ^openstack_dashboard/locale/.*$ 9 - ^openstack_dashboard/locale/.*$
10 - ^openstack_auth/locale/.*$
10 11
11- job: 12- job:
12 name: horizon-openstack-tox-py27dj18 13 name: horizon-openstack-tox-py27dj18
@@ -27,11 +28,41 @@
27 tox_envlist: py27dj110 28 tox_envlist: py27dj110
28 29
29- job: 30- job:
31 name: horizon-openstack-tox-py35dj20
32 parent: horizon-openstack-tox-base
33 vars:
34 tox_envlist: py35dj20
35
36- job:
30 name: horizon-selenium-headless 37 name: horizon-selenium-headless
31 parent: horizon-openstack-tox-base 38 parent: horizon-openstack-tox-base
32 vars: 39 vars:
33 tox_envlist: selenium-headless 40 tox_envlist: selenium-headless
34 41
42- job:
43 name: horizon-dsvm-tempest-plugin
44 parent: devstack-tempest
45 required-projects:
46 - name: openstack/horizon
47 - name: openstack/tempest
48 - name: openstack/tempest-horizon
49 irrelevant-files:
50 - ^.*\.rst$
51 - ^doc/.*$
52 - ^releasenotes/.*$
53 - ^horizon/locale/.*$
54 - ^openstack_dashboard/locale/.*$
55 - ^openstack_auth/locale/.*$
56 vars:
57 devstack_localrc:
58 TEMPEST_PLUGINS: "'{{ ansible_user_dir }}/src/git.openstack.org/openstack/tempest-horizon'"
59 devstack_services:
60 horizon: true
61 tempest: true
62 tempest_concurrency: 2
63 tempest_test_regex: horizon
64 tox_venvlist: all
65
35- project: 66- project:
36 name: openstack/horizon 67 name: openstack/horizon
37 check: 68 check:
@@ -39,10 +70,14 @@
39 - horizon-openstack-tox-py27dj110 70 - horizon-openstack-tox-py27dj110
40 - horizon-openstack-tox-py27dj19 71 - horizon-openstack-tox-py27dj19
41 - horizon-openstack-tox-py27dj18 72 - horizon-openstack-tox-py27dj18
73 - horizon-openstack-tox-py35dj20:
74 voting: false
42 - horizon-selenium-headless 75 - horizon-selenium-headless
76 - horizon-dsvm-tempest-plugin
43 gate: 77 gate:
44 jobs: 78 jobs:
45 - horizon-openstack-tox-py27dj110 79 - horizon-openstack-tox-py27dj110
46 - horizon-openstack-tox-py27dj19 80 - horizon-openstack-tox-py27dj19
47 - horizon-openstack-tox-py27dj18 81 - horizon-openstack-tox-py27dj18
48 - horizon-selenium-headless 82 - horizon-selenium-headless
83 - horizon-dsvm-tempest-plugin
diff --git a/doc/source/configuration/settings.rst b/doc/source/configuration/settings.rst
index b8de5bb..791cc11 100644
--- a/doc/source/configuration/settings.rst
+++ b/doc/source/configuration/settings.rst
@@ -768,6 +768,28 @@ will be from the beginning of the current month until the current date. The
768legacy behaviour is not recommended for large deployments as Horizon suffers 768legacy behaviour is not recommended for large deployments as Horizon suffers
769significant lag in this case. 769significant lag in this case.
770 770
771POLICY_DIRS
772-----------
773
774.. versionadded:: 13.0.0(Queens)
775
776Default: ``{}``
777
778Specifies a list of policy directories per service types. The directories
779are relative to `POLICY_FILES_PATH`_. Services whose additional policies
780are defined here must be defined in `POLICY_FILES`_ too. Otherwise,
781additional policies specified in ``POLICY_DIRS`` are not loaded.
782
783Example:
784
785.. code-block:: python
786
787 {
788 'identity': ['keystone_policy.d'],
789 'compute': ['nova_policy.d'],
790 'network': ['neutron_policy.d'],
791 }
792
771POLICY_FILES 793POLICY_FILES
772------------ 794------------
773 795
@@ -1426,6 +1448,17 @@ The commom value for this setting is ``HTTP_X_REAL_IP`` or
1426If not present, then ``REMOTE_ADDR`` header is used. (``REMOTE_ADDR`` is the 1448If not present, then ``REMOTE_ADDR`` header is used. (``REMOTE_ADDR`` is the
1427field of Django HttpRequest object which contains IP address of the client.) 1449field of Django HttpRequest object which contains IP address of the client.)
1428 1450
1451TOKEN_DELETION_DISABLED
1452~~~~~~~~~~~~~~~~~~~~~~~
1453
1454.. versionadded:: 10.0.0(Newton)
1455
1456Default: ``False``
1457
1458This setting allows deployers to control whether a token is deleted on log out.
1459This can be helpful when there are often long running processes being run
1460in the Horizon environment.
1461
1429TOKEN_TIMEOUT_MARGIN 1462TOKEN_TIMEOUT_MARGIN
1430~~~~~~~~~~~~~~~~~~~~ 1463~~~~~~~~~~~~~~~~~~~~
1431 1464
@@ -1864,11 +1897,15 @@ CONSOLE_TYPE
1864 1897
1865 Added the ``SERIAL`` option 1898 Added the ``SERIAL`` option
1866 1899
1900.. versionchanged:: 2017.11(Queens)
1901
1902 Added the ``MKS`` option
1903
1867Default: ``"AUTO"`` 1904Default: ``"AUTO"``
1868 1905
1869This setting specifies the type of in-browser console used to access the VMs. 1906This setting specifies the type of in-browser console used to access the VMs.
1870Valid values are ``"AUTO"``, ``"VNC"``, ``"SPICE"``, ``"RDP"``, 1907Valid values are ``"AUTO"``, ``"VNC"``, ``"SPICE"``, ``"RDP"``,
1871``"SERIAL"``, and ``None``. 1908``"SERIAL"``, ``"MKS"``, and ``None``.
1872 1909
1873ENABLE_FLAVOR_EDIT 1910ENABLE_FLAVOR_EDIT
1874~~~~~~~~~~~~~~~~~~ 1911~~~~~~~~~~~~~~~~~~
diff --git a/horizon/locale/cs/LC_MESSAGES/djangojs.po b/horizon/locale/cs/LC_MESSAGES/djangojs.po
index b844ff5..ad28ee6 100644
--- a/horizon/locale/cs/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/cs/LC_MESSAGES/djangojs.po
@@ -5,9 +5,9 @@
5# Zbyněk Schwarz <zbynek.schwarz@gmail.com>, 2016. #zanata 5# Zbyněk Schwarz <zbynek.schwarz@gmail.com>, 2016. #zanata
6msgid "" 6msgid ""
7msgstr "" 7msgstr ""
8"Project-Id-Version: horizon 12.0.0.0b3.dev66\n" 8"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-06-20 13:30+0000\n" 10"POT-Creation-Date: 2017-12-01 00:01+0000\n"
11"MIME-Version: 1.0\n" 11"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 12"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 13"Content-Transfer-Encoding: 8bit\n"
@@ -134,9 +134,6 @@ msgstr "Současné využití"
134msgid "Custom" 134msgid "Custom"
135msgstr "Vlastní" 135msgstr "Vlastní"
136 136
137msgid "Customization Script"
138msgstr "Přizpůsobovací skript"
139
140msgid "Danger" 137msgid "Danger"
141msgstr "Nebezpečí" 138msgstr "Nebezpečí"
142 139
@@ -230,9 +227,6 @@ msgstr "Neplatný typ, očekáváno {$schema.type$}"
230msgid "Keyword failed: '{$title$}'" 227msgid "Keyword failed: '{$title$}'"
231msgstr "Klíčové slovo selhalo: '{$title$}'" 228msgstr "Klíčové slovo selhalo: '{$title$}'"
232 229
233msgid "Load script from a file"
234msgstr "Načíst skript ze souboru"
235
236msgid "Loading" 230msgid "Loading"
237msgstr "Načítání" 231msgstr "Načítání"
238 232
@@ -320,14 +314,6 @@ msgstr "Vyžadováno"
320msgid "Roles" 314msgid "Roles"
321msgstr "Role" 315msgstr "Role"
322 316
323#. Strings between {$ and $} should be left untranslated.
324msgid ""
325"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
326"| bytes $}"
327msgstr ""
328"Velikost skriptu: {$ (scriptLength || 0) | bytes $} z {$ config."
329"MAX_SCRIPT_SIZE | bytes $}"
330
331msgid "Search in current results" 317msgid "Search in current results"
332msgstr "Hledat v aktuálních výsledcích" 318msgstr "Hledat v aktuálních výsledcích"
333 319
@@ -366,9 +352,6 @@ msgstr "Činnost nelze provést. Řádek obsahuje chybu chybějící informace."
366msgid "The data in this field is invalid" 352msgid "The data in this field is invalid"
367msgstr "Data v tomto poli jsou neplatná" 353msgstr "Data v tomto poli jsou neplatná"
368 354
369msgid "The script is larger than the maximum size"
370msgstr "Skript je větší než maximální velikost"
371
372msgid "There was a problem communicating with the server, please try again." 355msgid "There was a problem communicating with the server, please try again."
373msgstr "Při komunikaci se serverem nastal problém, zkuste to znovu." 356msgstr "Při komunikaci se serverem nastal problém, zkuste to znovu."
374 357
diff --git a/horizon/locale/de/LC_MESSAGES/django.po b/horizon/locale/de/LC_MESSAGES/django.po
index 0f3cc14..3f7ce7b 100644
--- a/horizon/locale/de/LC_MESSAGES/django.po
+++ b/horizon/locale/de/LC_MESSAGES/django.po
@@ -4,16 +4,17 @@
4# Robert Simai <robert.simai@suse.com>, 2016. #zanata 4# Robert Simai <robert.simai@suse.com>, 2016. #zanata
5# Adriano Perri <adriano.perri@telekom.de>, 2017. #zanata 5# Adriano Perri <adriano.perri@telekom.de>, 2017. #zanata
6# Frank Kloeker <eumel@arcor.de>, 2017. #zanata 6# Frank Kloeker <eumel@arcor.de>, 2017. #zanata
7# Robert Simai <robert.simai@suse.com>, 2017. #zanata
7msgid "" 8msgid ""
8msgstr "" 9msgstr ""
9"Project-Id-Version: horizon 13.0.0.0b2.dev82\n" 10"Project-Id-Version: horizon 13.0.0.0b3.dev2\n"
10"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 11"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
11"POT-Creation-Date: 2017-11-15 05:06+0000\n" 12"POT-Creation-Date: 2017-12-07 18:16+0000\n"
12"MIME-Version: 1.0\n" 13"MIME-Version: 1.0\n"
13"Content-Type: text/plain; charset=UTF-8\n" 14"Content-Type: text/plain; charset=UTF-8\n"
14"Content-Transfer-Encoding: 8bit\n" 15"Content-Transfer-Encoding: 8bit\n"
15"PO-Revision-Date: 2017-10-13 09:31+0000\n" 16"PO-Revision-Date: 2017-12-08 01:50+0000\n"
16"Last-Translator: Adriano Perri <adriano.perri@telekom.de>\n" 17"Last-Translator: Robert Simai <robert.simai@suse.com>\n"
17"Language-Team: German\n" 18"Language-Team: German\n"
18"Language: de\n" 19"Language: de\n"
19"X-Generator: Zanata 3.9.6\n" 20"X-Generator: Zanata 3.9.6\n"
@@ -38,6 +39,14 @@ msgstr[0] "%(size)d Byte"
38msgstr[1] "%(size)d Bytes" 39msgstr[1] "%(size)d Bytes"
39 40
40#, python-format 41#, python-format
42msgid "%(usedphrase)s <span> %(used)s </span>(No Limit)"
43msgstr "%(usedphrase)s <span> %(used)s </span>(kein Limit)"
44
45#, python-format
46msgid "%(usedphrase)s <span> %(used)s </span>of<span> %(available)s </span>"
47msgstr "%(usedphrase)s <span> %(used)s </span>von<span> %(available)s </span>"
48
49#, python-format
41msgid "%s EB" 50msgid "%s EB"
42msgstr "%s EB" 51msgstr "%s EB"
43 52
diff --git a/horizon/locale/de/LC_MESSAGES/djangojs.po b/horizon/locale/de/LC_MESSAGES/djangojs.po
index 4388163..ae3abaf 100644
--- a/horizon/locale/de/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/de/LC_MESSAGES/djangojs.po
@@ -5,9 +5,9 @@
5# Robert Simai <robert.simai@suse.com>, 2017. #zanata 5# Robert Simai <robert.simai@suse.com>, 2017. #zanata
6msgid "" 6msgid ""
7msgstr "" 7msgstr ""
8"Project-Id-Version: horizon 12.0.0.0rc2.dev209\n" 8"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-10-21 13:30+0000\n" 10"POT-Creation-Date: 2017-12-01 00:01+0000\n"
11"MIME-Version: 1.0\n" 11"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 12"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 13"Content-Transfer-Encoding: 8bit\n"
@@ -136,9 +136,6 @@ msgstr "Aktuelle Verwendung"
136msgid "Custom" 136msgid "Custom"
137msgstr "Anpassen" 137msgstr "Anpassen"
138 138
139msgid "Customization Script"
140msgstr "Anpassungsskript"
141
142msgid "Danger" 139msgid "Danger"
143msgstr "Gefahr" 140msgstr "Gefahr"
144 141
@@ -234,9 +231,6 @@ msgstr "Ungültiger Typ, erwartet wird {$schema.type$}"
234msgid "Keyword failed: '{$title$}'" 231msgid "Keyword failed: '{$title$}'"
235msgstr "Schlüsselwort fehlgeschlagen: '{$title$}'" 232msgstr "Schlüsselwort fehlgeschlagen: '{$title$}'"
236 233
237msgid "Load script from a file"
238msgstr "Skript aus einer Datei laden"
239
240msgid "Loading" 234msgid "Loading"
241msgstr "Ladevorgang" 235msgstr "Ladevorgang"
242 236
@@ -324,14 +318,6 @@ msgstr "Erforderlich"
324msgid "Roles" 318msgid "Roles"
325msgstr "Rollen" 319msgstr "Rollen"
326 320
327#. Strings between {$ and $} should be left untranslated.
328msgid ""
329"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
330"| bytes $}"
331msgstr ""
332"Skriptumfang: {$ (scriptLength || 0) | bytes $} von {$ config."
333"MAX_SCRIPT_SIZE | bytes $}"
334
335msgid "Search in current results" 321msgid "Search in current results"
336msgstr "Suche in den Ergebnissen" 322msgstr "Suche in den Ergebnissen"
337 323
@@ -372,9 +358,6 @@ msgstr ""
372msgid "The data in this field is invalid" 358msgid "The data in this field is invalid"
373msgstr "Die Daten in diesem Feld sind ungültig" 359msgstr "Die Daten in diesem Feld sind ungültig"
374 360
375msgid "The script is larger than the maximum size"
376msgstr "Das Skript ist größer als die maximal zulässige Größe"
377
378msgid "There was a problem communicating with the server, please try again." 361msgid "There was a problem communicating with the server, please try again."
379msgstr "" 362msgstr ""
380"Es gab ein Problem bei der Kommunikation mit dem Server. Bitte versuchen Sie " 363"Es gab ein Problem bei der Kommunikation mit dem Server. Bitte versuchen Sie "
diff --git a/horizon/locale/en_AU/LC_MESSAGES/djangojs.po b/horizon/locale/en_AU/LC_MESSAGES/djangojs.po
index 3be092f..f87a3ee 100644
--- a/horizon/locale/en_AU/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/en_AU/LC_MESSAGES/djangojs.po
@@ -5,9 +5,9 @@
5# Tom Fifield <tom@openstack.org>, 2017. #zanata 5# Tom Fifield <tom@openstack.org>, 2017. #zanata
6msgid "" 6msgid ""
7msgstr "" 7msgstr ""
8"Project-Id-Version: horizon 12.0.0.0rc2.dev100\n" 8"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-09-16 22:35+0000\n" 10"POT-Creation-Date: 2017-12-01 00:01+0000\n"
11"MIME-Version: 1.0\n" 11"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 12"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 13"Content-Transfer-Encoding: 8bit\n"
@@ -136,9 +136,6 @@ msgstr "Current Usage"
136msgid "Custom" 136msgid "Custom"
137msgstr "Custom" 137msgstr "Custom"
138 138
139msgid "Customization Script"
140msgstr "Customisation Script"
141
142msgid "Danger" 139msgid "Danger"
143msgstr "Danger" 140msgstr "Danger"
144 141
@@ -231,9 +228,6 @@ msgstr "Invalid type, expected {$schema.type$}"
231msgid "Keyword failed: '{$title$}'" 228msgid "Keyword failed: '{$title$}'"
232msgstr "Keyword failed: '{$title$}'" 229msgstr "Keyword failed: '{$title$}'"
233 230
234msgid "Load script from a file"
235msgstr "Load script from a file"
236
237msgid "Loading" 231msgid "Loading"
238msgstr "Loading" 232msgstr "Loading"
239 233
@@ -321,14 +315,6 @@ msgstr "Required"
321msgid "Roles" 315msgid "Roles"
322msgstr "Roles" 316msgstr "Roles"
323 317
324#. Strings between {$ and $} should be left untranslated.
325msgid ""
326"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
327"| bytes $}"
328msgstr ""
329"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
330"| bytes $}"
331
332msgid "Search in current results" 318msgid "Search in current results"
333msgstr "Search in current results" 319msgstr "Search in current results"
334 320
@@ -369,9 +355,6 @@ msgstr ""
369msgid "The data in this field is invalid" 355msgid "The data in this field is invalid"
370msgstr "The data in this field is invalid" 356msgstr "The data in this field is invalid"
371 357
372msgid "The script is larger than the maximum size"
373msgstr "The script is larger than the maximum size"
374
375msgid "There was a problem communicating with the server, please try again." 358msgid "There was a problem communicating with the server, please try again."
376msgstr "There was a problem communicating with the server, please try again." 359msgstr "There was a problem communicating with the server, please try again."
377 360
diff --git a/horizon/locale/en_GB/LC_MESSAGES/djangojs.po b/horizon/locale/en_GB/LC_MESSAGES/djangojs.po
index 13a87f0c..5d82416 100644
--- a/horizon/locale/en_GB/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/en_GB/LC_MESSAGES/djangojs.po
@@ -6,13 +6,13 @@
6# Andi Chandler <andi@gowling.com>, 2017. #zanata 6# Andi Chandler <andi@gowling.com>, 2017. #zanata
7msgid "" 7msgid ""
8msgstr "" 8msgstr ""
9"Project-Id-Version: horizon 12.0.0.0rc2.dev175\n" 9"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
10"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 10"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
11"POT-Creation-Date: 2017-10-14 12:29+0000\n" 11"POT-Creation-Date: 2017-12-01 00:01+0000\n"
12"MIME-Version: 1.0\n" 12"MIME-Version: 1.0\n"
13"Content-Type: text/plain; charset=UTF-8\n" 13"Content-Type: text/plain; charset=UTF-8\n"
14"Content-Transfer-Encoding: 8bit\n" 14"Content-Transfer-Encoding: 8bit\n"
15"PO-Revision-Date: 2017-10-14 11:39+0000\n" 15"PO-Revision-Date: 2017-11-30 09:22+0000\n"
16"Last-Translator: Andi Chandler <andi@gowling.com>\n" 16"Last-Translator: Andi Chandler <andi@gowling.com>\n"
17"Language-Team: English (United Kingdom)\n" 17"Language-Team: English (United Kingdom)\n"
18"Language: en-GB\n" 18"Language: en-GB\n"
@@ -131,15 +131,18 @@ msgstr "Confirm %s"
131msgid "Confirm Delete Foobars" 131msgid "Confirm Delete Foobars"
132msgstr "Confirm Delete Foobars" 132msgstr "Confirm Delete Foobars"
133 133
134#. Strings between {$ and $} should be left untranslated.
135msgid ""
136"Content size: {$ (textBytes || 0) | bytes $} of {$ ::maxBytes | bytes $}"
137msgstr ""
138"Content size: {$ (textBytes || 0) | bytes $} of {$ ::maxBytes | bytes $}"
139
134msgid "Current Usage" 140msgid "Current Usage"
135msgstr "Current Usage" 141msgstr "Current Usage"
136 142
137msgid "Custom" 143msgid "Custom"
138msgstr "Custom" 144msgstr "Custom"
139 145
140msgid "Customization Script"
141msgstr "Customisation Script"
142
143msgid "Danger" 146msgid "Danger"
144msgstr "Danger" 147msgstr "Danger"
145 148
@@ -235,8 +238,8 @@ msgstr "Invalid type, expected {$schema.type$}"
235msgid "Keyword failed: '{$title$}'" 238msgid "Keyword failed: '{$title$}'"
236msgstr "Keyword failed: '{$title$}'" 239msgstr "Keyword failed: '{$title$}'"
237 240
238msgid "Load script from a file" 241msgid "Load {$ ::title $} from a file"
239msgstr "Load script from a file" 242msgstr "Load {$ ::title $} from a file"
240 243
241msgid "Loading" 244msgid "Loading"
242msgstr "Loading" 245msgstr "Loading"
@@ -325,14 +328,6 @@ msgstr "Required"
325msgid "Roles" 328msgid "Roles"
326msgstr "Roles" 329msgstr "Roles"
327 330
328#. Strings between {$ and $} should be left untranslated.
329msgid ""
330"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
331"| bytes $}"
332msgstr ""
333"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
334"| bytes $}"
335
336msgid "Search in current results" 331msgid "Search in current results"
337msgstr "Search in current results" 332msgstr "Search in current results"
338 333
@@ -370,12 +365,12 @@ msgstr ""
370"The action cannot be performed. The contents of this row have errors or are " 365"The action cannot be performed. The contents of this row have errors or are "
371"missing information." 366"missing information."
372 367
368msgid "The content is larger than the maximum byte size"
369msgstr "The content is larger than the maximum byte size"
370
373msgid "The data in this field is invalid" 371msgid "The data in this field is invalid"
374msgstr "The data in this field is invalid" 372msgstr "The data in this field is invalid"
375 373
376msgid "The script is larger than the maximum size"
377msgstr "The script is larger than the maximum size"
378
379msgid "There was a problem communicating with the server, please try again." 374msgid "There was a problem communicating with the server, please try again."
380msgstr "There was a problem communicating with the server, please try again." 375msgstr "There was a problem communicating with the server, please try again."
381 376
diff --git a/horizon/locale/eo/LC_MESSAGES/djangojs.po b/horizon/locale/eo/LC_MESSAGES/djangojs.po
index f5a53d1..f135c3c 100644
--- a/horizon/locale/eo/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/eo/LC_MESSAGES/djangojs.po
@@ -1,9 +1,9 @@
1# Georg Hennemann <georg.hennemann@t-systems.com>, 2017. #zanata 1# Georg Hennemann <georg.hennemann@t-systems.com>, 2017. #zanata
2msgid "" 2msgid ""
3msgstr "" 3msgstr ""
4"Project-Id-Version: horizon 13.0.0.0b2.dev122\n" 4"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
5"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 5"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
6"POT-Creation-Date: 2017-11-26 10:36+0000\n" 6"POT-Creation-Date: 2017-12-01 00:01+0000\n"
7"MIME-Version: 1.0\n" 7"MIME-Version: 1.0\n"
8"Content-Type: text/plain; charset=UTF-8\n" 8"Content-Type: text/plain; charset=UTF-8\n"
9"Content-Transfer-Encoding: 8bit\n" 9"Content-Transfer-Encoding: 8bit\n"
@@ -134,9 +134,6 @@ msgstr "Nuna Uzado"
134msgid "Custom" 134msgid "Custom"
135msgstr "Propra" 135msgstr "Propra"
136 136
137msgid "Customization Script"
138msgstr "tajlorado skripto"
139
140msgid "Danger" 137msgid "Danger"
141msgstr "Danĝero" 138msgstr "Danĝero"
142 139
@@ -232,9 +229,6 @@ msgstr "Nevalida tipo, supozita {$schema.type$}"
232msgid "Keyword failed: '{$title$}'" 229msgid "Keyword failed: '{$title$}'"
233msgstr "Klavavorto malsukcesis: '{$title$}'" 230msgstr "Klavavorto malsukcesis: '{$title$}'"
234 231
235msgid "Load script from a file"
236msgstr "Elŝuti scripton de dosiero"
237
238msgid "Loading" 232msgid "Loading"
239msgstr "Ŝargi" 233msgstr "Ŝargi"
240 234
@@ -319,14 +313,6 @@ msgstr "Bezonata"
319msgid "Roles" 313msgid "Roles"
320msgstr "Roloj" 314msgstr "Roloj"
321 315
322#. Strings between {$ and $} should be left untranslated.
323msgid ""
324"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
325"| bytes $}"
326msgstr ""
327"Skriptgrandeco: {$ (scriptLength || 0) | bajtoj $} of {$ config."
328"MAX_SCRIPT_SIZE | bajtoj $}"
329
330msgid "Search in current results" 316msgid "Search in current results"
331msgstr "Ŝercu in nunaj resultoj" 317msgstr "Ŝercu in nunaj resultoj"
332 318
@@ -367,9 +353,6 @@ msgstr ""
367msgid "The data in this field is invalid" 353msgid "The data in this field is invalid"
368msgstr "La datumoj en ĉi tiu datumkampo estas nevalida " 354msgstr "La datumoj en ĉi tiu datumkampo estas nevalida "
369 355
370msgid "The script is larger than the maximum size"
371msgstr "La skripto estas pli granda ol la maksimuma grandeco"
372
373msgid "There was a problem communicating with the server, please try again." 356msgid "There was a problem communicating with the server, please try again."
374msgstr "Estis komunikada eraro kum servilo, bonvolu provu denove" 357msgstr "Estis komunikada eraro kum servilo, bonvolu provu denove"
375 358
diff --git a/horizon/locale/es/LC_MESSAGES/djangojs.po b/horizon/locale/es/LC_MESSAGES/djangojs.po
index 233ee30..942b3fe 100644
--- a/horizon/locale/es/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/es/LC_MESSAGES/djangojs.po
@@ -7,9 +7,9 @@
7# Zeus Arias Lucero <zeusariaslucero@gmail.com>, 2017. #zanata 7# Zeus Arias Lucero <zeusariaslucero@gmail.com>, 2017. #zanata
8msgid "" 8msgid ""
9msgstr "" 9msgstr ""
10"Project-Id-Version: horizon 12.0.0.0rc2.dev100\n" 10"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
11"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 11"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
12"POT-Creation-Date: 2017-09-16 22:35+0000\n" 12"POT-Creation-Date: 2017-12-01 00:01+0000\n"
13"MIME-Version: 1.0\n" 13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n" 14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: 8bit\n" 15"Content-Transfer-Encoding: 8bit\n"
@@ -126,9 +126,6 @@ msgstr "Uso actual"
126msgid "Custom" 126msgid "Custom"
127msgstr "Personalizar" 127msgstr "Personalizar"
128 128
129msgid "Customization Script"
130msgstr "Script de personalización"
131
132msgid "Danger" 129msgid "Danger"
133msgstr "Peligro" 130msgstr "Peligro"
134 131
@@ -203,9 +200,6 @@ msgstr "Entero obligatorio"
203msgid "Invalid type, expected {$schema.type$}" 200msgid "Invalid type, expected {$schema.type$}"
204msgstr "Tipo inválido, se esperaba {$schema.type$}" 201msgstr "Tipo inválido, se esperaba {$schema.type$}"
205 202
206msgid "Load script from a file"
207msgstr "Leer Script desde un fichero"
208
209msgid "Loading" 203msgid "Loading"
210msgstr "Cargando" 204msgstr "Cargando"
211 205
@@ -290,14 +284,6 @@ msgstr "Obligatorio"
290msgid "Roles" 284msgid "Roles"
291msgstr "Roles" 285msgstr "Roles"
292 286
293#. Strings between {$ and $} should be left untranslated.
294msgid ""
295"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
296"| bytes $}"
297msgstr ""
298"Tamaño Script: {$ (scriptLength || 0) | bytes $} of {$ config."
299"MAX_SCRIPT_SIZE | bytes $}"
300
301msgid "Search in current results" 287msgid "Search in current results"
302msgstr "Buscar entre los resultados" 288msgstr "Buscar entre los resultados"
303 289
@@ -338,9 +324,6 @@ msgstr ""
338msgid "The data in this field is invalid" 324msgid "The data in this field is invalid"
339msgstr "El dato en este campo es inválido" 325msgstr "El dato en este campo es inválido"
340 326
341msgid "The script is larger than the maximum size"
342msgstr "El Script es mayor que el tamaño máximo"
343
344msgid "There was a problem communicating with the server, please try again." 327msgid "There was a problem communicating with the server, please try again."
345msgstr "" 328msgstr ""
346"Ha ocurrido un problema en la comunicación con el servidor, inténtelo de " 329"Ha ocurrido un problema en la comunicación con el servidor, inténtelo de "
diff --git a/horizon/locale/fr/LC_MESSAGES/djangojs.po b/horizon/locale/fr/LC_MESSAGES/djangojs.po
index bcbfff5..c826ef2 100644
--- a/horizon/locale/fr/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/fr/LC_MESSAGES/djangojs.po
@@ -8,9 +8,9 @@
8# Loic Nicolle <loic.nicolle@orange.com>, 2017. #zanata 8# Loic Nicolle <loic.nicolle@orange.com>, 2017. #zanata
9msgid "" 9msgid ""
10msgstr "" 10msgstr ""
11"Project-Id-Version: horizon 12.0.0.0rc2.dev209\n" 11"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
12"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 12"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
13"POT-Creation-Date: 2017-10-21 13:30+0000\n" 13"POT-Creation-Date: 2017-12-01 00:01+0000\n"
14"MIME-Version: 1.0\n" 14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n" 15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n" 16"Content-Transfer-Encoding: 8bit\n"
@@ -141,9 +141,6 @@ msgstr "Utilisation actuelle"
141msgid "Custom" 141msgid "Custom"
142msgstr "Personnalisé" 142msgstr "Personnalisé"
143 143
144msgid "Customization Script"
145msgstr "Script de personnalisation"
146
147msgid "Danger" 144msgid "Danger"
148msgstr "Danger" 145msgstr "Danger"
149 146
@@ -239,9 +236,6 @@ msgstr "Type invalide, {$schema.type$} attendu"
239msgid "Keyword failed: '{$title$}'" 236msgid "Keyword failed: '{$title$}'"
240msgstr "Le mot clé a échoué : '{$title$}'" 237msgstr "Le mot clé a échoué : '{$title$}'"
241 238
242msgid "Load script from a file"
243msgstr "Charger un script depuis un fichier"
244
245msgid "Loading" 239msgid "Loading"
246msgstr "Chargement..." 240msgstr "Chargement..."
247 241
@@ -329,14 +323,6 @@ msgstr "Requis"
329msgid "Roles" 323msgid "Roles"
330msgstr "Rôles" 324msgstr "Rôles"
331 325
332#. Strings between {$ and $} should be left untranslated.
333msgid ""
334"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
335"| bytes $}"
336msgstr ""
337"Taille du script : {$ (scriptLength || 0) | bytes $} sur {$ config."
338"MAX_SCRIPT_SIZE | bytes $}"
339
340msgid "Search in current results" 326msgid "Search in current results"
341msgstr "Rechercher dans les résultats courants" 327msgstr "Rechercher dans les résultats courants"
342 328
@@ -377,9 +363,6 @@ msgstr ""
377msgid "The data in this field is invalid" 363msgid "The data in this field is invalid"
378msgstr "Les données de ce champ sont invalides" 364msgstr "Les données de ce champ sont invalides"
379 365
380msgid "The script is larger than the maximum size"
381msgstr "Le script est plus grand que la taille maximale"
382
383msgid "There was a problem communicating with the server, please try again." 366msgid "There was a problem communicating with the server, please try again."
384msgstr "Problème de communication avec le serveur, veuillez réessayer." 367msgstr "Problème de communication avec le serveur, veuillez réessayer."
385 368
diff --git a/horizon/locale/id/LC_MESSAGES/djangojs.po b/horizon/locale/id/LC_MESSAGES/djangojs.po
index e4dfd64..9f763be 100644
--- a/horizon/locale/id/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/id/LC_MESSAGES/djangojs.po
@@ -3,13 +3,13 @@
3# suhartono <cloudsuhartono@gmail.com>, 2017. #zanata 3# suhartono <cloudsuhartono@gmail.com>, 2017. #zanata
4msgid "" 4msgid ""
5msgstr "" 5msgstr ""
6"Project-Id-Version: horizon 12.0.0.0rc2.dev175\n" 6"Project-Id-Version: horizon 13.0.0.0b2.dev169\n"
7"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 7"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
8"POT-Creation-Date: 2017-10-14 12:29+0000\n" 8"POT-Creation-Date: 2017-12-02 13:46+0000\n"
9"MIME-Version: 1.0\n" 9"MIME-Version: 1.0\n"
10"Content-Type: text/plain; charset=UTF-8\n" 10"Content-Type: text/plain; charset=UTF-8\n"
11"Content-Transfer-Encoding: 8bit\n" 11"Content-Transfer-Encoding: 8bit\n"
12"PO-Revision-Date: 2017-10-15 01:25+0000\n" 12"PO-Revision-Date: 2017-12-03 04:19+0000\n"
13"Last-Translator: suhartono <cloudsuhartono@gmail.com>\n" 13"Last-Translator: suhartono <cloudsuhartono@gmail.com>\n"
14"Language-Team: Indonesian\n" 14"Language-Team: Indonesian\n"
15"Language: id\n" 15"Language: id\n"
@@ -128,15 +128,18 @@ msgstr "Memastikan %s"
128msgid "Confirm Delete Foobars" 128msgid "Confirm Delete Foobars"
129msgstr "Confirm Delete Foobars (konfirmasi hapus foobar)" 129msgstr "Confirm Delete Foobars (konfirmasi hapus foobar)"
130 130
131#. Strings between {$ and $} should be left untranslated.
132msgid ""
133"Content size: {$ (textBytes || 0) | bytes $} of {$ ::maxBytes | bytes $}"
134msgstr ""
135"Ukuran konten: {$ (textBytes || 0) | bytes $} of {$ ::maxBytes | bytes $}"
136
131msgid "Current Usage" 137msgid "Current Usage"
132msgstr "Penggunaan saat ini" 138msgstr "Penggunaan saat ini"
133 139
134msgid "Custom" 140msgid "Custom"
135msgstr "Custom" 141msgstr "Custom"
136 142
137msgid "Customization Script"
138msgstr "kustomisasi skrip"
139
140msgid "Danger" 143msgid "Danger"
141msgstr "Danger" 144msgstr "Danger"
142 145
@@ -231,8 +234,8 @@ msgstr "Tipe invalid, diharapkan {$schema.type$}"
231msgid "Keyword failed: '{$title$}'" 234msgid "Keyword failed: '{$title$}'"
232msgstr "Keyword gagal:'{$title$}'" 235msgstr "Keyword gagal:'{$title$}'"
233 236
234msgid "Load script from a file" 237msgid "Load {$ ::title $} from a file"
235msgstr "Load skrip dari file" 238msgstr "Load {$ ::title $} dari file"
236 239
237msgid "Loading" 240msgid "Loading"
238msgstr "Pemuatan" 241msgstr "Pemuatan"
@@ -321,14 +324,6 @@ msgstr "Wajib"
321msgid "Roles" 324msgid "Roles"
322msgstr "Aturan" 325msgstr "Aturan"
323 326
324#. Strings between {$ and $} should be left untranslated.
325msgid ""
326"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
327"| bytes $}"
328msgstr ""
329"Ukuran skrip: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
330"| bytes $}"
331
332msgid "Search in current results" 327msgid "Search in current results"
333msgstr "Cari dalam hasil saat ini" 328msgstr "Cari dalam hasil saat ini"
334 329
@@ -366,12 +361,12 @@ msgstr ""
366"Tindakan tidak dapat dilakukan. Konten baris ini memiliki kesalahan atau " 361"Tindakan tidak dapat dilakukan. Konten baris ini memiliki kesalahan atau "
367"informasi hilang." 362"informasi hilang."
368 363
364msgid "The content is larger than the maximum byte size"
365msgstr "Konten lebih besar dari ukuran byte maksimum"
366
369msgid "The data in this field is invalid" 367msgid "The data in this field is invalid"
370msgstr "Data dalam field ini tidak valid" 368msgstr "Data dalam field ini tidak valid"
371 369
372msgid "The script is larger than the maximum size"
373msgstr "Skrip lebih besar dari ukuran maksimum"
374
375msgid "There was a problem communicating with the server, please try again." 370msgid "There was a problem communicating with the server, please try again."
376msgstr "Ada masalah komunikasi dengan server, mohon di coba kembali." 371msgstr "Ada masalah komunikasi dengan server, mohon di coba kembali."
377 372
diff --git a/horizon/locale/it/LC_MESSAGES/djangojs.po b/horizon/locale/it/LC_MESSAGES/djangojs.po
index fccea5a..b194975 100644
--- a/horizon/locale/it/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/it/LC_MESSAGES/djangojs.po
@@ -4,17 +4,17 @@
4# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata 4# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
5msgid "" 5msgid ""
6msgstr "" 6msgstr ""
7"Project-Id-Version: horizon 11.0.0.0b3.dev48\n" 7"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
8"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 8"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
9"POT-Creation-Date: 2016-12-23 01:32+0000\n" 9"POT-Creation-Date: 2017-12-01 00:01+0000\n"
10"MIME-Version: 1.0\n" 10"MIME-Version: 1.0\n"
11"Content-Type: text/plain; charset=UTF-8\n" 11"Content-Type: text/plain; charset=UTF-8\n"
12"Content-Transfer-Encoding: 8bit\n" 12"Content-Transfer-Encoding: 8bit\n"
13"PO-Revision-Date: 2016-03-28 03:49+0000\n" 13"PO-Revision-Date: 2016-04-07 07:16+0000\n"
14"Last-Translator: Alessandra <alessandra@translated.net>\n" 14"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
15"Language-Team: Italian\n" 15"Language-Team: Italian\n"
16"Language: it\n" 16"Language: it\n"
17"X-Generator: Zanata 3.7.3\n" 17"X-Generator: Zanata 3.9.6\n"
18"Plural-Forms: nplurals=2; plural=(n != 1)\n" 18"Plural-Forms: nplurals=2; plural=(n != 1)\n"
19 19
20#, python-format 20#, python-format
@@ -101,9 +101,6 @@ msgstr "Utilizzo attuale"
101msgid "Custom" 101msgid "Custom"
102msgstr "Personalizzato" 102msgstr "Personalizzato"
103 103
104msgid "Customization Script"
105msgstr "Script di personalizzazione"
106
107msgid "Danger" 104msgid "Danger"
108msgstr "Pericolo" 105msgstr "Pericolo"
109 106
@@ -172,9 +169,6 @@ msgstr "Informazioni"
172msgid "Integer required" 169msgid "Integer required"
173msgstr "Numero intero richiesto" 170msgstr "Numero intero richiesto"
174 171
175msgid "Load script from a file"
176msgstr "Carica script da un file"
177
178msgid "Loading" 172msgid "Loading"
179msgstr "Caricamento" 173msgstr "Caricamento"
180 174
@@ -256,14 +250,6 @@ msgstr "Richiesto"
256msgid "Roles" 250msgid "Roles"
257msgstr "Ruoli" 251msgstr "Ruoli"
258 252
259#. Strings between {$ and $} should be left untranslated.
260msgid ""
261"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
262"| bytes $}"
263msgstr ""
264"Dimensione script: {$ (scriptLength || 0) | bytes $} of {$ config."
265"MAX_SCRIPT_SIZE | bytes $}"
266
267msgid "Search in current results" 253msgid "Search in current results"
268msgstr "Cerca nei risultati correnti" 254msgstr "Cerca nei risultati correnti"
269 255
@@ -301,9 +287,6 @@ msgstr ""
301"L'azione non può essere eseguita. Il contenuto di questa riga contiene o " 287"L'azione non può essere eseguita. Il contenuto di questa riga contiene o "
302"errori o informazioni mancanti" 288"errori o informazioni mancanti"
303 289
304msgid "The script is larger than the maximum size"
305msgstr "Lo script è maggiore della dimensione massima"
306
307msgid "There was a problem communicating with the server, please try again." 290msgid "There was a problem communicating with the server, please try again."
308msgstr "Si è verificato un errore di comunicazione con il server, riprova." 291msgstr "Si è verificato un errore di comunicazione con il server, riprova."
309 292
diff --git a/horizon/locale/ja/LC_MESSAGES/djangojs.po b/horizon/locale/ja/LC_MESSAGES/djangojs.po
index 9bbd37a..17ae06c 100644
--- a/horizon/locale/ja/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/ja/LC_MESSAGES/djangojs.po
@@ -5,13 +5,13 @@
5# Yuko Katabami <yukokatabami@gmail.com>, 2017. #zanata 5# Yuko Katabami <yukokatabami@gmail.com>, 2017. #zanata
6msgid "" 6msgid ""
7msgstr "" 7msgstr ""
8"Project-Id-Version: horizon 12.0.0.0b4.dev51\n" 8"Project-Id-Version: horizon 13.0.0.0b2.dev168\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-08-07 12:40+0000\n" 10"POT-Creation-Date: 2017-12-02 05:07+0000\n"
11"MIME-Version: 1.0\n" 11"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 12"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 13"Content-Transfer-Encoding: 8bit\n"
14"PO-Revision-Date: 2017-08-07 01:16+0000\n" 14"PO-Revision-Date: 2017-12-01 08:22+0000\n"
15"Last-Translator: Akihiro Motoki <amotoki@gmail.com>\n" 15"Last-Translator: Akihiro Motoki <amotoki@gmail.com>\n"
16"Language-Team: Japanese\n" 16"Language-Team: Japanese\n"
17"Language: ja\n" 17"Language: ja\n"
@@ -130,15 +130,19 @@ msgstr "%sの確認"
130msgid "Confirm Delete Foobars" 130msgid "Confirm Delete Foobars"
131msgstr "Foobar の削除の確認" 131msgstr "Foobar の削除の確認"
132 132
133#. Strings between {$ and $} should be left untranslated.
134msgid ""
135"Content size: {$ (textBytes || 0) | bytes $} of {$ ::maxBytes | bytes $}"
136msgstr ""
137"コンテンツのサイズ: {$ ::maxBytes | bytes $} 中 {$ (textBytes || 0) | bytes "
138"$}"
139
133msgid "Current Usage" 140msgid "Current Usage"
134msgstr "現在使用中" 141msgstr "現在使用中"
135 142
136msgid "Custom" 143msgid "Custom"
137msgstr "カスタム" 144msgstr "カスタム"
138 145
139msgid "Customization Script"
140msgstr "カスタマイズスクリプト"
141
142msgid "Danger" 146msgid "Danger"
143msgstr "危険" 147msgstr "危険"
144 148
@@ -230,9 +234,6 @@ msgstr "無効な種別です。期待値: {$schema.type$}"
230msgid "Keyword failed: '{$title$}'" 234msgid "Keyword failed: '{$title$}'"
231msgstr "キーワードでエラーが発生しました: '{$title$}'" 235msgstr "キーワードでエラーが発生しました: '{$title$}'"
232 236
233msgid "Load script from a file"
234msgstr "ファイルからのスクリプト読み込み"
235
236msgid "Loading" 237msgid "Loading"
237msgstr "読み込み中" 238msgstr "読み込み中"
238 239
@@ -320,14 +321,6 @@ msgstr "必須"
320msgid "Roles" 321msgid "Roles"
321msgstr "ロール" 322msgstr "ロール"
322 323
323#. Strings between {$ and $} should be left untranslated.
324msgid ""
325"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
326"| bytes $}"
327msgstr ""
328"スクリプトのサイズ: {$ config.MAX_SCRIPT_SIZE | bytes $} 中 {$ (scriptLength "
329"|| 0) | bytes $}"
330
331msgid "Search in current results" 324msgid "Search in current results"
332msgstr "現在の結果内の検索" 325msgstr "現在の結果内の検索"
333 326
@@ -364,12 +357,12 @@ msgid ""
364msgstr "" 357msgstr ""
365"操作を実行できません。この行の内容にエラーがあるか、情報が見つかりません。" 358"操作を実行できません。この行の内容にエラーがあるか、情報が見つかりません。"
366 359
360msgid "The content is larger than the maximum byte size"
361msgstr "コンテンツが最大サイズを超えています。"
362
367msgid "The data in this field is invalid" 363msgid "The data in this field is invalid"
368msgstr "このフィールドのデータは無効です。" 364msgstr "このフィールドのデータは無効です。"
369 365
370msgid "The script is larger than the maximum size"
371msgstr "スクリプトが最大サイズを超えています。"
372
373msgid "There was a problem communicating with the server, please try again." 366msgid "There was a problem communicating with the server, please try again."
374msgstr "サーバーとの通信中に問題がありました。再度お試しください。" 367msgstr "サーバーとの通信中に問題がありました。再度お試しください。"
375 368
diff --git a/horizon/locale/ko_KR/LC_MESSAGES/django.po b/horizon/locale/ko_KR/LC_MESSAGES/django.po
index d0a77d4..ee42b0a 100644
--- a/horizon/locale/ko_KR/LC_MESSAGES/django.po
+++ b/horizon/locale/ko_KR/LC_MESSAGES/django.po
@@ -4,13 +4,13 @@
4# Sungjin Kang <gang.sungjin@gmail.com>, 2017. #zanata 4# Sungjin Kang <gang.sungjin@gmail.com>, 2017. #zanata
5msgid "" 5msgid ""
6msgstr "" 6msgstr ""
7"Project-Id-Version: horizon 13.0.0.0b2.dev82\n" 7"Project-Id-Version: horizon 13.0.0.0b3.dev2\n"
8"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 8"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
9"POT-Creation-Date: 2017-11-15 05:06+0000\n" 9"POT-Creation-Date: 2017-12-07 18:16+0000\n"
10"MIME-Version: 1.0\n" 10"MIME-Version: 1.0\n"
11"Content-Type: text/plain; charset=UTF-8\n" 11"Content-Type: text/plain; charset=UTF-8\n"
12"Content-Transfer-Encoding: 8bit\n" 12"Content-Transfer-Encoding: 8bit\n"
13"PO-Revision-Date: 2017-10-17 02:57+0000\n" 13"PO-Revision-Date: 2017-12-05 02:24+0000\n"
14"Last-Translator: ByungYeol Woo <wby1089@gmail.com>\n" 14"Last-Translator: ByungYeol Woo <wby1089@gmail.com>\n"
15"Language-Team: Korean (South Korea)\n" 15"Language-Team: Korean (South Korea)\n"
16"Language: ko-KR\n" 16"Language: ko-KR\n"
@@ -35,6 +35,14 @@ msgid_plural "%(size)d Bytes"
35msgstr[0] "%(size)d 바이트" 35msgstr[0] "%(size)d 바이트"
36 36
37#, python-format 37#, python-format
38msgid "%(usedphrase)s <span> %(used)s </span>(No Limit)"
39msgstr "%(usedphrase)s <span> %(used)s </span>(제한 없음)"
40
41#, python-format
42msgid "%(usedphrase)s <span> %(used)s </span>of<span> %(available)s </span>"
43msgstr "%(usedphrase)s <span> %(used)s </span>of<span> %(available)s </span>"
44
45#, python-format
38msgid "%s EB" 46msgid "%s EB"
39msgstr "%s EB" 47msgstr "%s EB"
40 48
diff --git a/horizon/locale/ko_KR/LC_MESSAGES/djangojs.po b/horizon/locale/ko_KR/LC_MESSAGES/djangojs.po
index e20c591..ad9264f 100644
--- a/horizon/locale/ko_KR/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/ko_KR/LC_MESSAGES/djangojs.po
@@ -1,22 +1,17 @@
1# Sungjin Kang <gang.sungjin@gmail.com>, 2015. #zanata 1# Sungjin Kang <gang.sungjin@gmail.com>, 2015. #zanata
2# Andrea Young Oak Li <youli@redhat.com>, 2016. #zanata
3# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
4# Ian Y. Choi <ianyrchoi@gmail.com>, 2016. #zanata 2# Ian Y. Choi <ianyrchoi@gmail.com>, 2016. #zanata
5# Jun-Sik Shin <jsshin@smartx.kr>, 2016. #zanata
6# Nalee Jang <nalee999@gmail.com>, 2016. #zanata
7# Sungjin Kang <gang.sungjin@gmail.com>, 2016. #zanata 3# Sungjin Kang <gang.sungjin@gmail.com>, 2016. #zanata
8# Wonil Choi <wonil0522@gmail.com>, 2017. #zanata 4# Sungjin Kang <gang.sungjin@gmail.com>, 2017. #zanata
9# bryan tak <neos346@gmail.com>, 2017. #zanata
10msgid "" 5msgid ""
11msgstr "" 6msgstr ""
12"Project-Id-Version: horizon 12.0.0.0b3.dev201\n" 7"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
13"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 8"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
14"POT-Creation-Date: 2017-07-18 14:39+0000\n" 9"POT-Creation-Date: 2017-12-01 00:01+0000\n"
15"MIME-Version: 1.0\n" 10"MIME-Version: 1.0\n"
16"Content-Type: text/plain; charset=UTF-8\n" 11"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n" 12"Content-Transfer-Encoding: 8bit\n"
18"PO-Revision-Date: 2017-07-19 06:35+0000\n" 13"PO-Revision-Date: 2017-08-03 06:03+0000\n"
19"Last-Translator: bryan tak <neos346@gmail.com>\n" 14"Last-Translator: Ian Y. Choi <ianyrchoi@gmail.com>\n"
20"Language-Team: Korean (South Korea)\n" 15"Language-Team: Korean (South Korea)\n"
21"Language: ko-KR\n" 16"Language: ko-KR\n"
22"X-Generator: Zanata 3.9.6\n" 17"X-Generator: Zanata 3.9.6\n"
@@ -142,9 +137,6 @@ msgstr "현재 사용량"
142msgid "Custom" 137msgid "Custom"
143msgstr "사용자 지정" 138msgstr "사용자 지정"
144 139
145msgid "Customization Script"
146msgstr "사용자 정의 스크립트"
147
148msgid "Danger" 140msgid "Danger"
149msgstr "위험" 141msgstr "위험"
150 142
@@ -236,9 +228,6 @@ msgstr "잘못된 유형, 예상값 {$schema.type$}"
236msgid "Keyword failed: '{$title$}'" 228msgid "Keyword failed: '{$title$}'"
237msgstr "키워드 실패: '{$title$}'" 229msgstr "키워드 실패: '{$title$}'"
238 230
239msgid "Load script from a file"
240msgstr "파일에서 스크립트 읽어오기"
241
242msgid "Loading" 231msgid "Loading"
243msgstr "불러오는 중" 232msgstr "불러오는 중"
244 233
@@ -326,14 +315,6 @@ msgstr "필요"
326msgid "Roles" 315msgid "Roles"
327msgstr "역할" 316msgstr "역할"
328 317
329#. Strings between {$ and $} should be left untranslated.
330msgid ""
331"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
332"| bytes $}"
333msgstr ""
334"스크립트 크기: {$ config.MAX_SCRIPT_SIZE | bytes $} 중 {$ (scriptLength || "
335"0) | bytes $}"
336
337msgid "Search in current results" 318msgid "Search in current results"
338msgstr "현재 결과에서 검색" 319msgstr "현재 결과에서 검색"
339 320
@@ -373,9 +354,6 @@ msgstr ""
373msgid "The data in this field is invalid" 354msgid "The data in this field is invalid"
374msgstr "해당 필드의 데이터에 오류가 있습니다." 355msgstr "해당 필드의 데이터에 오류가 있습니다."
375 356
376msgid "The script is larger than the maximum size"
377msgstr "스크립트가 최대 크기보다 큽니다"
378
379msgid "There was a problem communicating with the server, please try again." 357msgid "There was a problem communicating with the server, please try again."
380msgstr "서버와의 통신에 문제가 발생하였으니, 다시 시도하세요." 358msgstr "서버와의 통신에 문제가 발생하였으니, 다시 시도하세요."
381 359
diff --git a/horizon/locale/pt_BR/LC_MESSAGES/djangojs.po b/horizon/locale/pt_BR/LC_MESSAGES/djangojs.po
index 73c7f7f..4997409 100644
--- a/horizon/locale/pt_BR/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/pt_BR/LC_MESSAGES/djangojs.po
@@ -8,9 +8,9 @@
8# Marcio <marciofoz@gmail.com>, 2017. #zanata 8# Marcio <marciofoz@gmail.com>, 2017. #zanata
9msgid "" 9msgid ""
10msgstr "" 10msgstr ""
11"Project-Id-Version: horizon 12.0.0.0rc2.dev234\n" 11"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
12"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 12"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
13"POT-Creation-Date: 2017-10-25 02:59+0000\n" 13"POT-Creation-Date: 2017-12-01 00:01+0000\n"
14"MIME-Version: 1.0\n" 14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n" 15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n" 16"Content-Transfer-Encoding: 8bit\n"
@@ -140,9 +140,6 @@ msgstr "Uso atual"
140msgid "Custom" 140msgid "Custom"
141msgstr "Customizado" 141msgstr "Customizado"
142 142
143msgid "Customization Script"
144msgstr "Script de customização"
145
146msgid "Danger" 143msgid "Danger"
147msgstr "Perigo" 144msgstr "Perigo"
148 145
@@ -238,9 +235,6 @@ msgstr "Tipo inválido, esperado {$schema.type$}"
238msgid "Keyword failed: '{$title$}'" 235msgid "Keyword failed: '{$title$}'"
239msgstr "Palavra-chave falhou: '{title$}'" 236msgstr "Palavra-chave falhou: '{title$}'"
240 237
241msgid "Load script from a file"
242msgstr "Carregar script a partir de um arquivo"
243
244msgid "Loading" 238msgid "Loading"
245msgstr "Carregando" 239msgstr "Carregando"
246 240
@@ -328,14 +322,6 @@ msgstr "Requerido"
328msgid "Roles" 322msgid "Roles"
329msgstr "Papéis" 323msgstr "Papéis"
330 324
331#. Strings between {$ and $} should be left untranslated.
332msgid ""
333"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
334"| bytes $}"
335msgstr ""
336"Tamanho do script: {$ (scriptLength || 0) | bytes $} de {$ config."
337"MAX_SCRIPT_SIZE | bytes $}"
338
339msgid "Search in current results" 325msgid "Search in current results"
340msgstr "Procurar nos resultados atuais" 326msgstr "Procurar nos resultados atuais"
341 327
@@ -376,9 +362,6 @@ msgstr ""
376msgid "The data in this field is invalid" 362msgid "The data in this field is invalid"
377msgstr "A informação neste campo é inválida" 363msgstr "A informação neste campo é inválida"
378 364
379msgid "The script is larger than the maximum size"
380msgstr "O script é maior que o tamanho máximo"
381
382msgid "There was a problem communicating with the server, please try again." 365msgid "There was a problem communicating with the server, please try again."
383msgstr "" 366msgstr ""
384"Houve um problema ao comunicar-se com o servidor, por favor tente novamente." 367"Houve um problema ao comunicar-se com o servidor, por favor tente novamente."
diff --git a/horizon/locale/ru/LC_MESSAGES/djangojs.po b/horizon/locale/ru/LC_MESSAGES/djangojs.po
index 7d17579..dbeccdc 100644
--- a/horizon/locale/ru/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/ru/LC_MESSAGES/djangojs.po
@@ -22,9 +22,9 @@
22# Ilya Alekseyev <ilyaalekseyev@acm.org>, 2017. #zanata 22# Ilya Alekseyev <ilyaalekseyev@acm.org>, 2017. #zanata
23msgid "" 23msgid ""
24msgstr "" 24msgstr ""
25"Project-Id-Version: horizon 12.0.0.0b4.dev8\n" 25"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
26"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 26"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
27"POT-Creation-Date: 2017-07-29 12:07+0000\n" 27"POT-Creation-Date: 2017-12-01 00:01+0000\n"
28"MIME-Version: 1.0\n" 28"MIME-Version: 1.0\n"
29"Content-Type: text/plain; charset=UTF-8\n" 29"Content-Type: text/plain; charset=UTF-8\n"
30"Content-Transfer-Encoding: 8bit\n" 30"Content-Transfer-Encoding: 8bit\n"
@@ -157,9 +157,6 @@ msgstr "Использовано на текущий момент"
157msgid "Custom" 157msgid "Custom"
158msgstr "Выборочный" 158msgstr "Выборочный"
159 159
160msgid "Customization Script"
161msgstr "Скрипт настройки"
162
163msgid "Danger" 160msgid "Danger"
164msgstr "Опасность" 161msgstr "Опасность"
165 162
@@ -253,9 +250,6 @@ msgstr "Неправильный тип, ожидается {$schema.type$}"
253msgid "Keyword failed: '{$title$}'" 250msgid "Keyword failed: '{$title$}'"
254msgstr "Ошибка ключевого слова: '{$title$}'" 251msgstr "Ошибка ключевого слова: '{$title$}'"
255 252
256msgid "Load script from a file"
257msgstr "Загрузить скрипт из файла"
258
259msgid "Loading" 253msgid "Loading"
260msgstr "Загрузка" 254msgstr "Загрузка"
261 255
@@ -343,14 +337,6 @@ msgstr "Требуется"
343msgid "Roles" 337msgid "Roles"
344msgstr "Роли" 338msgstr "Роли"
345 339
346#. Strings between {$ and $} should be left untranslated.
347msgid ""
348"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
349"| bytes $}"
350msgstr ""
351"Размер скрипта: {$ (scriptLength || 0) | bytes $} из {$ config."
352"MAX_SCRIPT_SIZE | bytes $}"
353
354msgid "Search in current results" 340msgid "Search in current results"
355msgstr "Поиск в текущих результатах" 341msgstr "Поиск в текущих результатах"
356 342
@@ -391,9 +377,6 @@ msgstr ""
391msgid "The data in this field is invalid" 377msgid "The data in this field is invalid"
392msgstr "Данные в этом поле неверны" 378msgstr "Данные в этом поле неверны"
393 379
394msgid "The script is larger than the maximum size"
395msgstr "Размер скрипта больше максимально допустимого размера"
396
397msgid "There was a problem communicating with the server, please try again." 380msgid "There was a problem communicating with the server, please try again."
398msgstr "Обнаружена проблема при соединении с сервером. Повторите попытку." 381msgstr "Обнаружена проблема при соединении с сервером. Повторите попытку."
399 382
diff --git a/horizon/locale/tr_TR/LC_MESSAGES/djangojs.po b/horizon/locale/tr_TR/LC_MESSAGES/djangojs.po
index a0885b5..577de1e 100644
--- a/horizon/locale/tr_TR/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/tr_TR/LC_MESSAGES/djangojs.po
@@ -5,9 +5,9 @@
5# yasemin demiral <yasemin.demiral@tubitak.gov.tr>, 2017. #zanata 5# yasemin demiral <yasemin.demiral@tubitak.gov.tr>, 2017. #zanata
6msgid "" 6msgid ""
7msgstr "" 7msgstr ""
8"Project-Id-Version: horizon 12.0.0.0rc2.dev28\n" 8"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-08-16 18:19+0000\n" 10"POT-Creation-Date: 2017-12-01 00:01+0000\n"
11"MIME-Version: 1.0\n" 11"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 12"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 13"Content-Transfer-Encoding: 8bit\n"
@@ -134,9 +134,6 @@ msgstr "Mevcut Kullanım"
134msgid "Custom" 134msgid "Custom"
135msgstr "Özel" 135msgstr "Özel"
136 136
137msgid "Customization Script"
138msgstr "Özelleştirme Scripti"
139
140msgid "Danger" 137msgid "Danger"
141msgstr "Tehlike" 138msgstr "Tehlike"
142 139
@@ -229,9 +226,6 @@ msgstr "Geçersiz tür, beklenen {$schema.type$}"
229msgid "Keyword failed: '{$title$}'" 226msgid "Keyword failed: '{$title$}'"
230msgstr "Anahtar sözcük başarısız: '{$title$}'" 227msgstr "Anahtar sözcük başarısız: '{$title$}'"
231 228
232msgid "Load script from a file"
233msgstr "Scripti dosyadan yükle"
234
235msgid "Loading" 229msgid "Loading"
236msgstr "Yükleniyor" 230msgstr "Yükleniyor"
237 231
@@ -319,14 +313,6 @@ msgstr "Zorunlu"
319msgid "Roles" 313msgid "Roles"
320msgstr "Roller" 314msgstr "Roller"
321 315
322#. Strings between {$ and $} should be left untranslated.
323msgid ""
324"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
325"| bytes $}"
326msgstr ""
327"Script boyutu: {$ (scriptLength || 0) | bytes $} / {$ config.MAX_SCRIPT_SIZE "
328"| bytes $}"
329
330msgid "Search in current results" 316msgid "Search in current results"
331msgstr "Şu andaki sonuçlar içinde Ara" 317msgstr "Şu andaki sonuçlar içinde Ara"
332 318
@@ -367,9 +353,6 @@ msgstr ""
367msgid "The data in this field is invalid" 353msgid "The data in this field is invalid"
368msgstr "Bu alandaki veri geçersiz" 354msgstr "Bu alandaki veri geçersiz"
369 355
370msgid "The script is larger than the maximum size"
371msgstr "Script maksimum boyuttan büyük"
372
373msgid "There was a problem communicating with the server, please try again." 356msgid "There was a problem communicating with the server, please try again."
374msgstr "Sunucu ile iletişimde bir sorun var, lütfen tekrar deneyiniz." 357msgstr "Sunucu ile iletişimde bir sorun var, lütfen tekrar deneyiniz."
375 358
diff --git a/horizon/locale/zh_CN/LC_MESSAGES/djangojs.po b/horizon/locale/zh_CN/LC_MESSAGES/djangojs.po
index 1197c6d..704327b 100644
--- a/horizon/locale/zh_CN/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/zh_CN/LC_MESSAGES/djangojs.po
@@ -14,9 +14,9 @@
14# Tony <tfu@redhat.com>, 2017. #zanata 14# Tony <tfu@redhat.com>, 2017. #zanata
15msgid "" 15msgid ""
16msgstr "" 16msgstr ""
17"Project-Id-Version: horizon 12.0.0.0rc2.dev35\n" 17"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
18"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 18"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
19"POT-Creation-Date: 2017-08-17 21:12+0000\n" 19"POT-Creation-Date: 2017-12-01 00:01+0000\n"
20"MIME-Version: 1.0\n" 20"MIME-Version: 1.0\n"
21"Content-Type: text/plain; charset=UTF-8\n" 21"Content-Type: text/plain; charset=UTF-8\n"
22"Content-Transfer-Encoding: 8bit\n" 22"Content-Transfer-Encoding: 8bit\n"
@@ -143,9 +143,6 @@ msgstr "当前用量"
143msgid "Custom" 143msgid "Custom"
144msgstr "定制" 144msgstr "定制"
145 145
146msgid "Customization Script"
147msgstr "自定义脚本"
148
149msgid "Danger" 146msgid "Danger"
150msgstr "危险" 147msgstr "危险"
151 148
@@ -237,9 +234,6 @@ msgstr "非法的类型, 应该为 {$schema.type$}"
237msgid "Keyword failed: '{$title$}'" 234msgid "Keyword failed: '{$title$}'"
238msgstr "关键字失败: '{$title$}'" 235msgstr "关键字失败: '{$title$}'"
239 236
240msgid "Load script from a file"
241msgstr "从文件载入脚本"
242
243msgid "Loading" 237msgid "Loading"
244msgstr "加载中" 238msgstr "加载中"
245 239
@@ -327,14 +321,6 @@ msgstr "必须"
327msgid "Roles" 321msgid "Roles"
328msgstr "角色" 322msgstr "角色"
329 323
330#. Strings between {$ and $} should be left untranslated.
331msgid ""
332"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
333"| bytes $}"
334msgstr ""
335"脚本大小: {$ (scriptLength || 0) | bytes $} / {$ config.MAX_SCRIPT_SIZE | "
336"bytes $} (最大)"
337
338msgid "Search in current results" 324msgid "Search in current results"
339msgstr "在当前结果中搜索" 325msgstr "在当前结果中搜索"
340 326
@@ -373,9 +359,6 @@ msgstr "不能执行该操作。该行的内容有错或是缺少信息。"
373msgid "The data in this field is invalid" 359msgid "The data in this field is invalid"
374msgstr "该域中的此数据非法" 360msgstr "该域中的此数据非法"
375 361
376msgid "The script is larger than the maximum size"
377msgstr "脚本大小超出最大值"
378
379msgid "There was a problem communicating with the server, please try again." 362msgid "There was a problem communicating with the server, please try again."
380msgstr "与服务器通信出现问题,请再试一次。" 363msgstr "与服务器通信出现问题,请再试一次。"
381 364
diff --git a/horizon/locale/zh_TW/LC_MESSAGES/djangojs.po b/horizon/locale/zh_TW/LC_MESSAGES/djangojs.po
index 9291546..32bdb9b 100644
--- a/horizon/locale/zh_TW/LC_MESSAGES/djangojs.po
+++ b/horizon/locale/zh_TW/LC_MESSAGES/djangojs.po
@@ -5,9 +5,9 @@
5# Gene Kuo <gene@openstack.org>, 2017. #zanata 5# Gene Kuo <gene@openstack.org>, 2017. #zanata
6msgid "" 6msgid ""
7msgstr "" 7msgstr ""
8"Project-Id-Version: horizon 12.0.0.0rc2.dev100\n" 8"Project-Id-Version: horizon 13.0.0.0b2.dev161\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-09-16 22:35+0000\n" 10"POT-Creation-Date: 2017-12-01 00:01+0000\n"
11"MIME-Version: 1.0\n" 11"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 12"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 13"Content-Transfer-Encoding: 8bit\n"
@@ -134,9 +134,6 @@ msgstr "目前使用量"
134msgid "Custom" 134msgid "Custom"
135msgstr "自訂" 135msgstr "自訂"
136 136
137msgid "Customization Script"
138msgstr "客製化腳本"
139
140msgid "Danger" 137msgid "Danger"
141msgstr "危險" 138msgstr "危險"
142 139
@@ -228,9 +225,6 @@ msgstr "無效的類型,預期為 {$schema.type$}"
228msgid "Keyword failed: '{$title$}'" 225msgid "Keyword failed: '{$title$}'"
229msgstr "關鍵字錯誤: '{$title$}'" 226msgstr "關鍵字錯誤: '{$title$}'"
230 227
231msgid "Load script from a file"
232msgstr "從檔案載入腳本"
233
234msgid "Loading" 228msgid "Loading"
235msgstr "讀取中" 229msgstr "讀取中"
236 230
@@ -318,14 +312,6 @@ msgstr "需要"
318msgid "Roles" 312msgid "Roles"
319msgstr "角色" 313msgstr "角色"
320 314
321#. Strings between {$ and $} should be left untranslated.
322msgid ""
323"Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE "
324"| bytes $}"
325msgstr ""
326"Script 大小:{$ (scriptLength || 0) | bytes $},共 {$ config.MAX_SCRIPT_SIZE "
327"| bytes $}"
328
329msgid "Search in current results" 315msgid "Search in current results"
330msgstr "在目前結果中搜尋" 316msgstr "在目前結果中搜尋"
331 317
@@ -364,9 +350,6 @@ msgstr "無法執行動作。這行的內容有錯或者缺少資訊。"
364msgid "The data in this field is invalid" 350msgid "The data in this field is invalid"
365msgstr "此欄位的輸入無效" 351msgstr "此欄位的輸入無效"
366 352
367msgid "The script is larger than the maximum size"
368msgstr "該 Script 的大小大於大小上限"
369
370msgid "There was a problem communicating with the server, please try again." 353msgid "There was a problem communicating with the server, please try again."
371msgstr "與伺服器間的通訊有問題,請再試一次。" 354msgstr "與伺服器間的通訊有問題,請再試一次。"
372 355
diff --git a/horizon/static/framework/widgets/load-edit/load-edit.directive.js b/horizon/static/framework/widgets/load-edit/load-edit.directive.js
index 620dcbf..902c11f 100644
--- a/horizon/static/framework/widgets/load-edit/load-edit.directive.js
+++ b/horizon/static/framework/widgets/load-edit/load-edit.directive.js
@@ -18,15 +18,18 @@
18 18
19 /** 19 /**
20 * @ngdoc directive 20 * @ngdoc directive
21 * @name horizon.framework.widgets:loadEdit 21 * @name horizon.framework.widgets:load-edit
22 * @scope 22 * @scope
23 * @element 23 * @element
24 * @description 24 * @description
25 * The 'loadEdit' directive supports and validates size of the script entered 25 * The 'load-edit' directive supports and validates size of the text entered
26 * 26 *
27 * @param {object} config 27 * @param {object} title
28 * @param {object} userInput 28 * @param {object} model
29 * @param {object} maxBytes
29 * @param {object} key 30 * @param {object} key
31 * @param {object} required
32 * @param {object} rows
30 * 33 *
31 * See configuration.html for example usage. 34 * See configuration.html for example usage.
32 */ 35 */
@@ -44,9 +47,12 @@
44 var directive = { 47 var directive = {
45 restrict: 'E', 48 restrict: 'E',
46 scope: { 49 scope: {
47 config: '=', 50 title: '@',
48 userInput: '=', 51 model: '=',
49 key: '@' 52 maxBytes: '@',
53 key: '@',
54 required: '=',
55 rows: '@'
50 }, 56 },
51 link: link, 57 link: link,
52 templateUrl: basePath + 'load-edit.html' 58 templateUrl: basePath + 'load-edit.html'
@@ -65,13 +71,13 @@
65 /* HTML5 file API is supported by IE10+, Chrome, FireFox and Safari (on Mac). 71 /* HTML5 file API is supported by IE10+, Chrome, FireFox and Safari (on Mac).
66 * 72 *
67 * If HTML5 file API is not supported by user's browser, remove the option 73 * If HTML5 file API is not supported by user's browser, remove the option
68 * to upload a script via file upload. 74 * to upload a text via file upload.
69 */ 75 */
70 $scope.config.fileApiSupported = !!FileReader; 76 $scope.fileApiSupported = !!FileReader;
71 77
72 /* Angular won't fire change events when the <textarea> is in invalid 78 /* Angular won't fire change events when the <textarea> is in invalid
73 * status, so we have to use jQuery/jqLite to watch for <textarea> changes. 79 * status, so we have to use jQuery/jqLite to watch for <textarea> changes.
74 * If there are changes, we call the onScriptChange function to update the 80 * If there are changes, we call the onTextareaChange function to update the
75 * size stats and perform validation. 81 * size stats and perform validation.
76 */ 82 */
77 textarea.on('input propertychange', onTextareaChange); 83 textarea.on('input propertychange', onTextareaChange);
@@ -80,7 +86,7 @@
80 /* onchange event occurs when a control loses the input focus and 86 /* onchange event occurs when a control loses the input focus and
81 * its value has been modified since gaining focus so we need to clear 87 * its value has been modified since gaining focus so we need to clear
82 * up the fileInput.val() when the textContent field is modified as to 88 * up the fileInput.val() when the textContent field is modified as to
83 * allow reloading the same script. 89 * allow reloading the same text.
84 */ 90 */
85 var textContentWatcher = $scope.$watch(function () { 91 var textContentWatcher = $scope.$watch(function () {
86 return $scope.textContent; 92 return $scope.textContent;
@@ -100,12 +106,12 @@
100 * invalid status, so we have to use jQuery or jqLite to get the length 106 * invalid status, so we have to use jQuery or jqLite to get the length
101 * of the <textarea> content. 107 * of the <textarea> content.
102 */ 108 */
103 $scope.scriptLength = textarea.val().length; 109 $scope.textBytes = getStrByte(textarea.val());
104 $scope.userInput[$scope.key] = $scope.textContent; 110 $scope.model = $scope.textContent;
105 if ($scope.scriptLength > 0) { 111 if ($scope.textBytes > 0) {
106 $scope.scriptModified = true; 112 $scope.textModified = true;
107 } else { 113 } else {
108 $scope.scriptModified = false; 114 $scope.textModified = false;
109 } 115 }
110 }); 116 });
111 } 117 }
@@ -121,18 +127,25 @@
121 function updateTextArea(fileContents) { 127 function updateTextArea(fileContents) {
122 $scope.textContent = fileContents; 128 $scope.textContent = fileContents;
123 129
124 /* Once the DOM manipulation is done, update the scriptLength, so that 130 /* Once the DOM manipulation is done, update the textBytes, so that
125 * user knows the length of the script loaded into the <textarea>. 131 * user knows the bytes of the text loaded into the <textarea>.
126 */ 132 */
127 $timeout(function () { 133 $timeout(function () {
128 onTextareaChange(); 134 onTextareaChange();
129 $scope.scriptModified = false; 135 $scope.textModified = false;
130 }, 250, false); 136 }, 250, false);
131 137
132 // Focus the <textarea> element after injecting the code into it. 138 // Focus the <textarea> element after injecting the code into it.
133 textarea.focus(); 139 textarea.focus();
134 } 140 }
135 141
142 /* The length property for string shows only number of character.
143 * If text includes multibyte string, it doesn't mean number of bytes.
144 * So to count bytes, convert to Blob object and get its size.
145 */
146 function getStrByte(str) {
147 return (new Blob([str], {type: "text/plain"})).size;
148 }
136 } 149 }
137 } 150 }
138})(); 151})();
diff --git a/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js b/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js
index c4f4504..b085140 100644
--- a/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js
+++ b/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js
@@ -37,9 +37,10 @@
37 $scope = $injector.get('$rootScope').$new(); 37 $scope = $injector.get('$rootScope').$new();
38 $q = $injector.get('$q'); 38 $q = $injector.get('$q');
39 $compile = $injector.get('$compile'); 39 $compile = $injector.get('$compile');
40 key = 'inputKey'; 40 key = 'elementKey';
41 element = $compile( 41 element = $compile(
42 '<load-edit config="{}" user-input="{}" key="' + key + '"></load-edit>' 42 '<load-edit title="{}" model="{}" max-bytes="{}" key="' + key + '" ' +
43 'required="true" rows="8"></load-edit>'
43 )($scope); 44 )($scope);
44 $scope.$apply(); 45 $scope.$apply();
45 })); 46 }));
@@ -51,20 +52,20 @@
51 textarea = element.find('textarea'); 52 textarea = element.find('textarea');
52 }); 53 });
53 54
54 it('should set scriptModified to true when textarea has content', function () { 55 it('should set textModified to true when textarea has content', function () {
55 textarea.val('any value'); 56 textarea.val('any value');
56 textarea.trigger('propertychange'); 57 textarea.trigger('propertychange');
57 $scope.$apply(); 58 $scope.$apply();
58 59
59 expect(element.isolateScope().scriptModified).toBe(true); 60 expect(element.isolateScope().textModified).toBe(true);
60 }); 61 });
61 62
62 it('should set scriptModified to false when textarea has no content', function () { 63 it('should set textModified to false when textarea has no content', function () {
63 textarea.val(''); 64 textarea.val('');
64 textarea.trigger('propertychange'); 65 textarea.trigger('propertychange');
65 $scope.$apply(); 66 $scope.$apply();
66 67
67 expect(element.isolateScope().scriptModified).toBe(false); 68 expect(element.isolateScope().textModified).toBe(false);
68 }); 69 });
69 70
70 it('should set userInput to the value of the textarea', function() { 71 it('should set userInput to the value of the textarea', function() {
@@ -72,7 +73,7 @@
72 textarea.trigger('input'); 73 textarea.trigger('input');
73 $scope.$apply(); 74 $scope.$apply();
74 75
75 expect(element.isolateScope().userInput[key]).toBe('user input'); 76 expect(element.isolateScope().model).toBe('user input');
76 }); 77 });
77 }); 78 });
78 79
diff --git a/horizon/static/framework/widgets/load-edit/load-edit.html b/horizon/static/framework/widgets/load-edit/load-edit.html
index 74f88da..4fe2cf8 100644
--- a/horizon/static/framework/widgets/load-edit/load-edit.html
+++ b/horizon/static/framework/widgets/load-edit/load-edit.html
@@ -1,30 +1,32 @@
1<div class="form-group" ng-class="{ 'has-error': scriptLength >= config.MAX_SCRIPT_SIZE }"> 1<div class="form-group" ng-show="fileApiSupported">
2 <label for="customization-script" class="control-label"> 2 <label for="load-{$ ::key $}" translate>Load {$ ::title $} from a file</label>
3 <span translate>Customization Script</span> 3 <input id="load-{$ ::key $}" type="file">
4 <span ng-show="scriptModified" 4</div>
5
6<div class="form-group" ng-class="{ 'has-error': textBytes >= maxBytes }">
7 <label for="{$ ::key $}" class="control-label">
8 <span>{$ ::title $}</span>
9 <span class="hz-icon-required fa fa-asterisk" ng-if="required"></span>
10 <span ng-show="textModified"
5 translate> 11 translate>
6 (Modified)</span> 12 (Modified)</span>
7 </label> 13 </label>
8 <span class="pull-right" ng-class="{ 'text-danger': scriptLength >= config.MAX_SCRIPT_SIZE }"> 14 <span class="pull-right" ng-class="{ 'text-danger': textBytes >= maxBytes }">
9 <span translate translate-comment="Strings between {$ and $} should be left untranslated."> 15 <span translate translate-comment="Strings between {$ and $} should be left untranslated.">
10 Script size: {$ (scriptLength || 0) | bytes $} of {$ config.MAX_SCRIPT_SIZE | bytes $} 16 Content size: {$ (textBytes || 0) | bytes $} of {$ ::maxBytes | bytes $}
11 </span> 17 </span>
12 </span> 18 </span>
13 <textarea class="form-control" 19 <textarea class="form-control"
14 rows="8" 20 id="{$ ::key $}"
15 id="customization-script" 21 name="{$ ::key $}"
16 name="customization-script" 22 ng-maxlength="::maxBytes"
17 ng-maxlength="config.MAX_SCRIPT_SIZE" 23 ng-model="textContent"
18 ng-model="textContent"> 24 ng-required="required"
25 rows="{$ ::rows $}">
19 </textarea> 26 </textarea>
20 <span class="help-block" 27 <span class="help-block"
21 ng-show="scriptLength >= config.MAX_SCRIPT_SIZE" 28 ng-show="textBytes >= maxBytes"
22 translate> 29 translate>
23 The script is larger than the maximum size 30 The content is larger than the maximum byte size
24 </span> 31 </span>
25</div> 32</div>
26
27<div class="form-group" ng-show="config.fileApiSupported">
28 <label for="load-script" translate>Load script from a file</label>
29 <input id="load-script" type="file">
30</div>
diff --git a/horizon/static/framework/widgets/metadata/display/display.scss b/horizon/static/framework/widgets/metadata/display/display.scss
index 7f9dcbf..88809b1 100644
--- a/horizon/static/framework/widgets/metadata/display/display.scss
+++ b/horizon/static/framework/widgets/metadata/display/display.scss
@@ -3,9 +3,10 @@
3 .selector-item { 3 .selector-item {
4 padding: $padding-base-vertical $padding-base-horizontal; 4 padding: $padding-base-vertical $padding-base-horizontal;
5 color: $link-color; 5 color: $link-color;
6 cursor: pointer;
7 border-radius: $nav-pills-border-radius; 6 border-radius: $nav-pills-border-radius;
8 7 &.clickable {
8 cursor: pointer;
9 }
9 &.active { 10 &.active {
10 background: $nav-pills-active-link-hover-bg; 11 background: $nav-pills-active-link-hover-bg;
11 color: $nav-pills-active-link-hover-color; 12 color: $nav-pills-active-link-hover-color;
diff --git a/horizon/static/framework/widgets/metadata/display/metadata-display.controller.js b/horizon/static/framework/widgets/metadata/display/metadata-display.controller.js
index 6d1a2d1..30ea0c5 100644
--- a/horizon/static/framework/widgets/metadata/display/metadata-display.controller.js
+++ b/horizon/static/framework/widgets/metadata/display/metadata-display.controller.js
@@ -76,6 +76,13 @@
76 return true; // break 76 return true; // break
77 } 77 }
78 }); 78 });
79
80 ctrl.count = 0;
81 ctrl.tree.flatTree.some(function (i) {
82 if (ctrl.listFilter(i)) {
83 ctrl.count += 1;
84 }
85 });
79 } 86 }
80 } 87 }
81})(); 88})();
diff --git a/horizon/static/framework/widgets/metadata/display/metadata-display.html b/horizon/static/framework/widgets/metadata/display/metadata-display.html
index d03e658..6148896 100644
--- a/horizon/static/framework/widgets/metadata/display/metadata-display.html
+++ b/horizon/static/framework/widgets/metadata/display/metadata-display.html
@@ -4,7 +4,7 @@
4 <div class="selector-item" 4 <div class="selector-item"
5 ng-repeat="item in ctrl.tree.flatTree | filter: ctrl.listFilter" 5 ng-repeat="item in ctrl.tree.flatTree | filter: ctrl.listFilter"
6 ng-click="ctrl.onSelect(item)" 6 ng-click="ctrl.onSelect(item)"
7 ng-class="{ active: ctrl.selected === item }"> 7 ng-class="{ active: ctrl.selected === item, clickable: ctrl.count > 1 }">
8 <span ng-bind="::item.label"></span> 8 <span ng-bind="::item.label"></span>
9 </div> 9 </div>
10 </div> 10 </div>
diff --git a/openstack_auth/locale/de/LC_MESSAGES/django.po b/openstack_auth/locale/de/LC_MESSAGES/django.po
new file mode 100644
index 0000000..9066527
--- /dev/null
+++ b/openstack_auth/locale/de/LC_MESSAGES/django.po
@@ -0,0 +1,89 @@
1# Robert Simai <robert.simai@suse.com>, 2017. #zanata
2msgid ""
3msgstr ""
4"Project-Id-Version: horizon 13.0.0.0b3.dev2\n"
5"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
6"POT-Creation-Date: 2017-12-07 18:17+0000\n"
7"MIME-Version: 1.0\n"
8"Content-Type: text/plain; charset=UTF-8\n"
9"Content-Transfer-Encoding: 8bit\n"
10"PO-Revision-Date: 2017-12-08 01:54+0000\n"
11"Last-Translator: Robert Simai <robert.simai@suse.com>\n"
12"Language-Team: German\n"
13"Language: de\n"
14"X-Generator: Zanata 3.9.6\n"
15"Plural-Forms: nplurals=2; plural=(n != 1)\n"
16
17msgid "An error occurred authenticating. Please try again later."
18msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal."
19
20msgid "Authenticate using"
21msgstr "Authentifizieren mit"
22
23msgid "Could not find service provider ID on Keystone."
24msgstr "Dienstanbieter ID in Keystone nicht gefunden."
25
26msgid "Domain"
27msgstr "Domäne"
28
29msgid "Invalid credentials."
30msgstr "Unzureichende Berechtigung."
31
32msgid "K2K Federation not setup for this session"
33msgstr "K2K Verbund ist für diese Sitzung nicht eingerichtet"
34
35msgid ""
36"No authentication backend could be determined to handle the provided "
37"credentials."
38msgstr ""
39"Es konnte kein Authentifizierungsbackend für die angegebene Legitimierung "
40"gefunden werden."
41
42msgid "Password"
43msgstr "Passwort"
44
45#, python-format
46msgid "Please consider changing your password, it will expire in %s minutes"
47msgstr "Bitte ändern Sie Ihr Passwort. Es läuft in %s Minuten ab."
48
49#, python-format
50msgid "Project switch failed for user \"%(username)s\"."
51msgstr "Projektumschaltung für Benutzer \"%(username)s\" fehlgeschlagen."
52
53msgid "Region"
54msgstr "Region"
55
56#, python-format
57msgid "Service provider authentication failed. %s"
58msgstr "Dienstanbieter Authentifizierung fehlgeschlagen. %s"
59
60#, python-format
61msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
62msgstr ""
63"Umschalten zum Keystone Anbieter \"%(keystone_provider)s\" erfolgreich."
64
65#, python-format
66msgid "Switch to project \"%(project_name)s\" successful."
67msgstr "Umschalten zum Projekt \"%(project_name)s\" erfolgreich."
68
69msgid "The authentication token issued by the Identity service has expired."
70msgstr ""
71"Das vom Identitätsdienst ausgegebene Authentifizierungs-Token ist abgelaufen."
72
73msgid "Unable to establish connection to keystone endpoint."
74msgstr "Es kann keine Verbindung zum Keystone Endpunkt aufgebaut werden."
75
76msgid "Unable to retrieve authorized domains."
77msgstr "Autorisierte Domänen können nicht abgerufen werden."
78
79msgid "Unable to retrieve authorized projects."
80msgstr "Autorisierte Projekte können nicht abgerufen werden."
81
82msgid "User Name"
83msgstr "Benutzername"
84
85msgid "You are not authorized for any projects or domains."
86msgstr "Sie sind nicht autorisiert für irgendein Projekt oder eine Domäne."
87
88msgid "You are not authorized for any projects."
89msgstr "Sie sind für kein Projekt berechtigt."
diff --git a/openstack_auth/locale/eo/LC_MESSAGES/django.po b/openstack_auth/locale/eo/LC_MESSAGES/django.po
new file mode 100644
index 0000000..0dd60cb
--- /dev/null
+++ b/openstack_auth/locale/eo/LC_MESSAGES/django.po
@@ -0,0 +1,85 @@
1# Georg Hennemann <georg.hennemann@t-systems.com>, 2017. #zanata
2msgid ""
3msgstr ""
4"Project-Id-Version: horizon 13.0.0.0b2.dev141\n"
5"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
6"POT-Creation-Date: 2017-11-28 23:44+0000\n"
7"MIME-Version: 1.0\n"
8"Content-Type: text/plain; charset=UTF-8\n"
9"Content-Transfer-Encoding: 8bit\n"
10"PO-Revision-Date: 2017-11-28 03:29+0000\n"
11"Last-Translator: Georg Hennemann <georg.hennemann@t-systems.com>\n"
12"Language-Team: Esperanto\n"
13"Language: eo\n"
14"X-Generator: Zanata 3.9.6\n"
15"Plural-Forms: nplurals=2; plural=(n != 1)\n"
16
17msgid "An error occurred authenticating. Please try again later."
18msgstr "Eraro okazis dum aŭtentigado. Bonvolu provu denove poste."
19
20msgid "Authenticate using"
21msgstr "Aŭtentigu uzante"
22
23msgid "Could not find service provider ID on Keystone."
24msgstr "Neebla trovi serva provizanto ID en Keystone."
25
26msgid "Domain"
27msgstr "Domajno"
28
29msgid "Invalid credentials."
30msgstr "Maljusta legitimaĵo."
31
32msgid "K2K Federation not setup for this session"
33msgstr "K2K Federacio ne establita por tiu seanco"
34
35msgid ""
36"No authentication backend could be determined to handle the provided "
37"credentials."
38msgstr "Nebla difini aŭtentiga servo por trakti la provizitajn legitimaĵojn."
39
40msgid "Password"
41msgstr "Pasvorto"
42
43#, python-format
44msgid "Please consider changing your password, it will expire in %s minutes"
45msgstr "Bonvolu konsideru ŝanĝi vian pasvorton, ĝi malvalidas en %s minutoj"
46
47#, python-format
48msgid "Project switch failed for user \"%(username)s\"."
49msgstr "Projekto ŝanĝo malsukcesis por uzanto \"%(username)s\"."
50
51msgid "Region"
52msgstr "Regiono"
53
54#, python-format
55msgid "Service provider authentication failed. %s"
56msgstr "Servo provizanto aŭtentigado malsukcesis. %s"
57
58#, python-format
59msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
60msgstr "Ŝanĝo al Keystone Provizanto \"%(keystone_provider)s\"sukcesis."
61
62#, python-format
63msgid "Switch to project \"%(project_name)s\" successful."
64msgstr "Ŝanĝi al projekto \"%(project_name)s\" sukcesis."
65
66msgid "The authentication token issued by the Identity service has expired."
67msgstr "The authentication token issued by the Identity service has expired."
68
69msgid "Unable to establish connection to keystone endpoint."
70msgstr "Neebla konekti al keystone finpunkto."
71
72msgid "Unable to retrieve authorized domains."
73msgstr "Neebla trovi rajtigitaj domajnoj."
74
75msgid "Unable to retrieve authorized projects."
76msgstr "Neebla trovi rajtigitaj projektoj."
77
78msgid "User Name"
79msgstr "Uzanto Nomo"
80
81msgid "You are not authorized for any projects or domains."
82msgstr "Vi ne estas rajtigita pri iujn projektojn au domajnojn."
83
84msgid "You are not authorized for any projects."
85msgstr "Vi ne estas rajtigita pri iujn projektojn."
diff --git a/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po b/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po
new file mode 100644
index 0000000..989e56a
--- /dev/null
+++ b/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po
@@ -0,0 +1,85 @@
1# ByungYeol Woo <wby1089@gmail.com>, 2017. #zanata
2msgid ""
3msgstr ""
4"Project-Id-Version: horizon 13.0.0.0b3.dev2\n"
5"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
6"POT-Creation-Date: 2017-12-07 18:17+0000\n"
7"MIME-Version: 1.0\n"
8"Content-Type: text/plain; charset=UTF-8\n"
9"Content-Transfer-Encoding: 8bit\n"
10"PO-Revision-Date: 2017-12-05 02:33+0000\n"
11"Last-Translator: ByungYeol Woo <wby1089@gmail.com>\n"
12"Language-Team: Korean (South Korea)\n"
13"Language: ko-KR\n"
14"X-Generator: Zanata 3.9.6\n"
15"Plural-Forms: nplurals=1; plural=0\n"
16
17msgid "An error occurred authenticating. Please try again later."
18msgstr "인증 도중 오류가 발생했습니다. 잠시 후 다시 시도하세요."
19
20msgid "Authenticate using"
21msgstr "인증 사용"
22
23msgid "Could not find service provider ID on Keystone."
24msgstr "키스톤에서 서비스 제공자 ID를 찾을 수 없습니다."
25
26msgid "Domain"
27msgstr "도메인"
28
29msgid "Invalid credentials."
30msgstr "올바르지 않은 자격증명."
31
32msgid "K2K Federation not setup for this session"
33msgstr "이 세션에는 K2K 페더레이션이 설정되지 않았습니다."
34
35msgid ""
36"No authentication backend could be determined to handle the provided "
37"credentials."
38msgstr "제공된 자격증명을 처리할 수 있는 인증 백엔드를 정할 수 없습니다."
39
40msgid "Password"
41msgstr "비밀번호"
42
43#, python-format
44msgid "Please consider changing your password, it will expire in %s minutes"
45msgstr "암호는 %s 분 후에 만료되므로 변경해 주시기 바랍니다."
46
47#, python-format
48msgid "Project switch failed for user \"%(username)s\"."
49msgstr "사용자 \"%(username)s\"의 프로젝트 전환이 실패했습니다."
50
51msgid "Region"
52msgstr "지역"
53
54#, python-format
55msgid "Service provider authentication failed. %s"
56msgstr "서비스 제공자 인증이 실패됨. %s"
57
58#, python-format
59msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
60msgstr "키스톤 제공자 \"%(keystone_provider)s\" 로의 변경이 성공하였습니다."
61
62#, python-format
63msgid "Switch to project \"%(project_name)s\" successful."
64msgstr "프로젝트 \"%(project_name)s\" 로 전환에 성공하였습니다."
65
66msgid "The authentication token issued by the Identity service has expired."
67msgstr "Identity 서비스에서 발급한 인증 토큰이 만료되었습니다."
68
69msgid "Unable to establish connection to keystone endpoint."
70msgstr "키스톤 엔드포인트에 연결할 수 없습니다."
71
72msgid "Unable to retrieve authorized domains."
73msgstr "인가된 도메인을 가져올 수 없습니다."
74
75msgid "Unable to retrieve authorized projects."
76msgstr "인가된 프로젝트를 가져올 수 없습니다."
77
78msgid "User Name"
79msgstr "사용자 이름"
80
81msgid "You are not authorized for any projects or domains."
82msgstr "모든 프로젝트나 도메인에 대한 권한이 없습니다."
83
84msgid "You are not authorized for any projects."
85msgstr "모든 프로젝트에 대한 권한이 없습니다."
diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py
index 5a69f87..5242a93 100644
--- a/openstack_dashboard/api/cinder.py
+++ b/openstack_dashboard/api/cinder.py
@@ -231,7 +231,7 @@ def cinderclient(request_auth_params, version=None):
231 return c 231 return c
232 232
233 233
234def get_microversion(request, feature): 234def get_microversion(request, features):
235 for service_name in ('volume', 'volumev2', 'volumev3'): 235 for service_name in ('volume', 'volumev2', 'volumev3'):
236 try: 236 try:
237 cinder_url = base.url_for(request, service_name) 237 cinder_url = base.url_for(request, service_name)
@@ -241,8 +241,8 @@ def get_microversion(request, feature):
241 else: 241 else:
242 return None 242 return None
243 min_ver, max_ver = cinder_client.get_server_version(cinder_url) 243 min_ver, max_ver = cinder_client.get_server_version(cinder_url)
244 return (microversions.get_microversion_for_feature( 244 return (microversions.get_microversion_for_features(
245 'cinder', feature, api_versions.APIVersion, min_ver, max_ver)) 245 'cinder', features, api_versions.APIVersion, min_ver, max_ver))
246 246
247 247
248def _replace_v2_parameters(data): 248def _replace_v2_parameters(data):
@@ -1061,7 +1061,7 @@ def pool_list(request, detailed=False):
1061 1061
1062@profiler.trace 1062@profiler.trace
1063def message_list(request, search_opts=None): 1063def message_list(request, search_opts=None):
1064 version = get_microversion(request, 'message_list') 1064 version = get_microversion(request, ['message_list'])
1065 if version is None: 1065 if version is None:
1066 LOG.warning("insufficient microversion for message_list") 1066 LOG.warning("insufficient microversion for message_list")
1067 return [] 1067 return []
diff --git a/openstack_dashboard/api/microversions.py b/openstack_dashboard/api/microversions.py
index 58af79a..2a770d8 100644
--- a/openstack_dashboard/api/microversions.py
+++ b/openstack_dashboard/api/microversions.py
@@ -30,6 +30,7 @@ MICROVERSION_FEATURES = {
30 "nova": { 30 "nova": {
31 "locked_attribute": ["2.9", "2.42"], 31 "locked_attribute": ["2.9", "2.42"],
32 "instance_description": ["2.19", "2.42"], 32 "instance_description": ["2.19", "2.42"],
33 "remote_console_mks": ["2.8", "2.53"]
33 }, 34 },
34 "cinder": { 35 "cinder": {
35 "consistency_groups": ["2.0", "3.10"], 36 "consistency_groups": ["2.0", "3.10"],
@@ -41,17 +42,31 @@ MICROVERSION_FEATURES = {
41# NOTE(robcresswell): Since each client implements their own wrapper class for 42# NOTE(robcresswell): Since each client implements their own wrapper class for
42# API objects, we'll need to allow that to be passed in. In the future this 43# API objects, we'll need to allow that to be passed in. In the future this
43# should be replaced by some common handling in Oslo. 44# should be replaced by some common handling in Oslo.
44def get_microversion_for_feature(service, feature, wrapper_class, 45def get_microversion_for_features(service, features, wrapper_class,
45 min_ver, max_ver): 46 min_ver, max_ver):
46 """Retrieves that highest known functional microversion for a feature""" 47 """Retrieves that highest known functional microversion for features"""
48 if not features:
49 return None
50 # Convert a single feature string into a list for backward compatiblity.
51 if isinstance(features, str):
52 features = [features]
47 try: 53 try:
48 service_features = MICROVERSION_FEATURES[service] 54 service_features = MICROVERSION_FEATURES[service]
49 except KeyError: 55 except KeyError:
50 LOG.debug("'%s' could not be found in the MICROVERSION_FEATURES dict", 56 LOG.debug("'%s' could not be found in the MICROVERSION_FEATURES dict",
51 service) 57 service)
52 return None 58 return None
53 feature_versions = service_features[feature] 59
54 for version in reversed(feature_versions): 60 feature_versions = set(service_features[features[0]])
61 for feature in features[1:]:
62 feature_versions &= set(service_features[feature])
63 if not feature_versions:
64 return None
65
66 # Sort version candidates from larger versins
67 feature_versions = sorted(feature_versions, reverse=True,
68 key=lambda v: [int(i) for i in v.split('.')])
69 for version in feature_versions:
55 microversion = wrapper_class(version) 70 microversion = wrapper_class(version)
56 if microversion.matches(min_ver, max_ver): 71 if microversion.matches(min_ver, max_ver):
57 return microversion 72 return microversion
diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py
index e526c82..15f5481 100644
--- a/openstack_dashboard/api/neutron.py
+++ b/openstack_dashboard/api/neutron.py
@@ -29,6 +29,7 @@ from django.conf import settings
29from django.utils.translation import ugettext_lazy as _ 29from django.utils.translation import ugettext_lazy as _
30from neutronclient.common import exceptions as neutron_exc 30from neutronclient.common import exceptions as neutron_exc
31from neutronclient.v2_0 import client as neutron_client 31from neutronclient.v2_0 import client as neutron_client
32from novaclient import exceptions as nova_exc
32import six 33import six
33 34
34from horizon import exceptions 35from horizon import exceptions
@@ -625,7 +626,7 @@ class FloatingIpManager(object):
625 self.client.update_floatingip(floating_ip_id, 626 self.client.update_floatingip(floating_ip_id,
626 {'floatingip': update_dict}) 627 {'floatingip': update_dict})
627 628
628 def _get_reachable_subnets(self, ports): 629 def _get_reachable_subnets(self, ports, fetch_router_ports=False):
629 if not is_enabled_by_config('enable_fip_topology_check', True): 630 if not is_enabled_by_config('enable_fip_topology_check', True):
630 # All subnets are reachable from external network 631 # All subnets are reachable from external network
631 return set( 632 return set(
@@ -637,10 +638,15 @@ class FloatingIpManager(object):
637 if (r.external_gateway_info and 638 if (r.external_gateway_info and
638 r.external_gateway_info.get('network_id') 639 r.external_gateway_info.get('network_id')
639 in ext_net_ids)] 640 in ext_net_ids)]
640 reachable_subnets = set([p.fixed_ips[0]['subnet_id'] for p in ports 641 if fetch_router_ports:
641 if ((p.device_owner in 642 router_ports = port_list(self.request,
642 ROUTER_INTERFACE_OWNERS) 643 device_owner=ROUTER_INTERFACE_OWNERS)
643 and (p.device_id in gw_routers))]) 644 else:
645 router_ports = [p for p in ports
646 if p.device_owner in ROUTER_INTERFACE_OWNERS]
647 reachable_subnets = set([p.fixed_ips[0]['subnet_id']
648 for p in router_ports
649 if p.device_id in gw_routers])
644 # we have to include any shared subnets as well because we may not 650 # we have to include any shared subnets as well because we may not
645 # have permission to see the router interface to infer connectivity 651 # have permission to see the router interface to infer connectivity
646 shared = set([s.id for n in network_list(self.request, shared=True) 652 shared = set([s.id for n in network_list(self.request, shared=True)
@@ -688,33 +694,6 @@ class FloatingIpManager(object):
688 return port_list(self.request, **search_opts) 694 return port_list(self.request, **search_opts)
689 695
690 @profiler.trace 696 @profiler.trace
691 def get_target_by_instance(self, instance_id, target_list=None):
692 """Returns a FloatingIpTarget object of floating IP association.
693
694 :param instance_id: ID of target VM instance
695 :param target_list: (optional) a list returned by list_targets().
696 If specified, looking up is done against the specified list
697 to save extra API calls to a back-end. Otherwise a target
698 information is retrieved from a back-end inside the method.
699 """
700 if target_list is not None:
701 targets = [target for target in target_list
702 if target['instance_id'] == instance_id]
703 if not targets:
704 return None
705 return targets[0]
706 else:
707 # In Neutron one port can have multiple ip addresses, so this
708 # method picks up the first one and generate target id.
709 ports = self._target_ports_by_instance(instance_id)
710 if not ports:
711 return None
712 # TODO(amotoki): Avoid using p.fixed_ips[0].
713 # Extract all IPv4 addresses instead
714 return FloatingIpTarget(
715 ports[0], ports[0].fixed_ips[0]['ip_address'], '')
716
717 @profiler.trace
718 def list_targets_by_instance(self, instance_id, target_list=None): 697 def list_targets_by_instance(self, instance_id, target_list=None):
719 """Returns a list of FloatingIpTarget objects of FIP association. 698 """Returns a list of FloatingIpTarget objects of FIP association.
720 699
@@ -725,16 +704,33 @@ class FloatingIpManager(object):
725 is retrieved from a back-end inside the method. 704 is retrieved from a back-end inside the method.
726 """ 705 """
727 if target_list is not None: 706 if target_list is not None:
707 # We assume that target_list was returned by list_targets()
708 # so we can assume checks for subnet reachability and IP version
709 # have been done already. We skip all checks here.
728 return [target for target in target_list 710 return [target for target in target_list
729 if target['instance_id'] == instance_id] 711 if target['instance_id'] == instance_id]
730 else: 712 else:
731 ports = self._target_ports_by_instance(instance_id) 713 ports = self._target_ports_by_instance(instance_id)
732 # TODO(amotoki): Avoid using p.fixed_ips[0]. 714 reachable_subnets = self._get_reachable_subnets(
733 # Extract all IPv4 addresses instead 715 ports, fetch_router_ports=True)
734 # TODO(amotoki): Replace a label with an empty string 716 name = self._get_server_name(instance_id)
735 # with a real server name. 717 targets = []
736 return [FloatingIpTarget(p, p.fixed_ips[0]['ip_address'], '') 718 for p in ports:
737 for p in ports] 719 for ip in p.fixed_ips:
720 if ip['subnet_id'] not in reachable_subnets:
721 continue
722 # Floating IPs can only target IPv4 addresses.
723 if netaddr.IPAddress(ip['ip_address']).version != 4:
724 continue
725 targets.append(FloatingIpTarget(p, ip['ip_address'], name))
726 return targets
727
728 def _get_server_name(self, server_id):
729 try:
730 server = nova.server_get(self.request, server_id)
731 return server.name
732 except nova_exc.NotFound:
733 return ''
738 734
739 def is_simple_associate_supported(self): 735 def is_simple_associate_supported(self):
740 """Returns True if the default floating IP pool is enabled.""" 736 """Returns True if the default floating IP pool is enabled."""
@@ -825,6 +821,13 @@ def list_resources_with_long_filters(list_method,
825 821
826 822
827@profiler.trace 823@profiler.trace
824def trunk_show(request, trunk_id):
825 LOG.debug("trunk_show(): trunk_id=%s", trunk_id)
826 trunk = neutronclient(request).show_trunk(trunk_id).get('trunk')
827 return Trunk(trunk)
828
829
830@profiler.trace
828def trunk_list(request, **params): 831def trunk_list(request, **params):
829 LOG.debug("trunk_list(): params=%s", params) 832 LOG.debug("trunk_list(): params=%s", params)
830 trunks = neutronclient(request).list_trunks(**params).get('trunks') 833 trunks = neutronclient(request).list_trunks(**params).get('trunks')
@@ -832,15 +835,122 @@ def trunk_list(request, **params):
832 835
833 836
834@profiler.trace 837@profiler.trace
838def trunk_create(request, **params):
839 LOG.debug("trunk_create(): params=%s", params)
840 if 'project_id' not in params:
841 params['project_id'] = request.user.project_id
842 body = {'trunk': params}
843 trunk = neutronclient(request).create_trunk(body=body).get('trunk')
844 return Trunk(trunk)
845
846
847@profiler.trace
835def trunk_delete(request, trunk_id): 848def trunk_delete(request, trunk_id):
836 LOG.debug("trunk_delete(): trunk_id=%s", trunk_id) 849 LOG.debug("trunk_delete(): trunk_id=%s", trunk_id)
837 neutronclient(request).delete_trunk(trunk_id) 850 neutronclient(request).delete_trunk(trunk_id)
838 851
839 852
853def _prepare_body_update_trunk(prop_diff):
854 """Prepare body for PUT /v2.0/trunks/TRUNK_ID."""
855 return {'trunk': prop_diff}
856
857
858def _prepare_body_remove_subports(subports):
859 """Prepare body for PUT /v2.0/trunks/TRUNK_ID/remove_subports."""
860 return {'sub_ports': [{'port_id': sp['port_id']} for sp in subports]}
861
862
863def _prepare_body_add_subports(subports):
864 """Prepare body for PUT /v2.0/trunks/TRUNK_ID/add_subports."""
865 return {'sub_ports': subports}
866
867
840@profiler.trace 868@profiler.trace
841def trunk_show(request, trunk_id): 869def trunk_update(request, trunk_id, old_trunk, new_trunk):
842 LOG.debug("trunk_show(): trunk_id=%s", trunk_id) 870 """Handle update to a trunk in (at most) three neutron calls.
843 trunk = neutronclient(request).show_trunk(trunk_id).get('trunk') 871
872 The JavaScript side should know only about the old and new state of a
873 trunk. However it should not know anything about how the old and new are
874 meant to be diffed and sent to neutron. We handle that here.
875
876 This code was adapted from Heat, see: https://review.openstack.org/442496
877
878 Call #1) Update all changed properties but 'sub_ports'.
879 PUT /v2.0/trunks/TRUNK_ID
880 openstack network trunk set
881
882 Call #2) Delete subports not needed anymore.
883 PUT /v2.0/trunks/TRUNK_ID/remove_subports
884 openstack network trunk unset --subport
885
886 Call #3) Create new subports.
887 PUT /v2.0/trunks/TRUNK_ID/add_subports
888 openstack network trunk set --subport
889
890 A single neutron port cannot be two subports at the same time (ie.
891 have two segmentation (type, ID)s on the same trunk or to belong to
892 two trunks). Therefore we have to delete old subports before creating
893 new ones to avoid conflicts.
894 """
895 LOG.debug("trunk_update(): trunk_id=%s", trunk_id)
896
897 # NOTE(bence romsics): We want to do set operations on the subports,
898 # however we receive subports represented as dicts. In Python
899 # mutable objects like dicts are not hashable so they cannot be
900 # inserted into sets. So we convert subport dicts to (immutable)
901 # frozensets in order to do the set operations.
902 def dict2frozenset(d):
903 """Convert a dict to a frozenset.
904
905 Create an immutable equivalent of a dict, so it's hashable
906 therefore can be used as an element of a set or a key of another
907 dictionary.
908 """
909 return frozenset(d.items())
910
911 # cf. neutron_lib/api/definitions/trunk.py
912 updatable_props = ('admin_state_up', 'description', 'name')
913 prop_diff = {
914 k: new_trunk[k]
915 for k in updatable_props
916 if old_trunk[k] != new_trunk[k]}
917
918 subports_old = {dict2frozenset(d): d
919 for d in old_trunk.get('sub_ports', [])}
920 subports_new = {dict2frozenset(d): d
921 for d in new_trunk.get('sub_ports', [])}
922
923 old_set = set(subports_old.keys())
924 new_set = set(subports_new.keys())
925
926 delete = old_set - new_set
927 create = new_set - old_set
928
929 dicts_delete = [subports_old[fs] for fs in delete]
930 dicts_create = [subports_new[fs] for fs in create]
931
932 trunk = old_trunk
933 if prop_diff:
934 LOG.debug('trunk_update(): update properties of trunk %s: %s',
935 trunk_id, prop_diff)
936 body = _prepare_body_update_trunk(prop_diff)
937 trunk = neutronclient(request).update_trunk(
938 trunk_id, body=body).get('trunk')
939
940 if dicts_delete:
941 LOG.debug('trunk_update(): delete subports of trunk %s: %s',
942 trunk_id, dicts_delete)
943 body = _prepare_body_remove_subports(dicts_delete)
944 trunk = neutronclient(request).trunk_remove_subports(
945 trunk_id, body=body)
946
947 if dicts_create:
948 LOG.debug('trunk_update(): create subports of trunk %s: %s',
949 trunk_id, dicts_create)
950 body = _prepare_body_add_subports(dicts_create)
951 trunk = neutronclient(request).trunk_add_subports(
952 trunk_id, body=body)
953
844 return Trunk(trunk) 954 return Trunk(trunk)
845 955
846 956
@@ -1413,11 +1523,6 @@ def floating_ip_target_list(request):
1413 return FloatingIpManager(request).list_targets() 1523 return FloatingIpManager(request).list_targets()
1414 1524
1415 1525
1416def floating_ip_target_get_by_instance(request, instance_id, cache=None):
1417 return FloatingIpManager(request).get_target_by_instance(
1418 instance_id, cache)
1419
1420
1421def floating_ip_target_list_by_instance(request, instance_id, cache=None): 1526def floating_ip_target_list_by_instance(request, instance_id, cache=None):
1422 return FloatingIpManager(request).list_targets_by_instance( 1527 return FloatingIpManager(request).list_targets_by_instance(
1423 instance_id, cache) 1528 instance_id, cache)
diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py
index 58ca1ef..b58f278 100644
--- a/openstack_dashboard/api/nova.py
+++ b/openstack_dashboard/api/nova.py
@@ -58,15 +58,15 @@ CACERT = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
58 58
59 59
60@memoized 60@memoized
61def get_microversion(request, feature): 61def get_microversion(request, features):
62 client = novaclient(request) 62 client = novaclient(request)
63 min_ver, max_ver = api_versions._get_server_version_range(client) 63 min_ver, max_ver = api_versions._get_server_version_range(client)
64 return (microversions.get_microversion_for_feature( 64 return (microversions.get_microversion_for_features(
65 'nova', feature, api_versions.APIVersion, min_ver, max_ver)) 65 'nova', features, api_versions.APIVersion, min_ver, max_ver))
66 66
67 67
68def is_feature_available(request, feature): 68def is_feature_available(request, features):
69 return bool(get_microversion(request, feature)) 69 return bool(get_microversion(request, features))
70 70
71 71
72class VNCConsole(base.APIDictWrapper): 72class VNCConsole(base.APIDictWrapper):
@@ -101,6 +101,14 @@ class SerialConsole(base.APIDictWrapper):
101 _attrs = ['url', 'type'] 101 _attrs = ['url', 'type']
102 102
103 103
104class MKSConsole(base.APIDictWrapper):
105 """Wrapper for the "console" dictionary.
106
107 Returned by the novaclient.servers.get_mks_console method.
108 """
109 _attrs = ['url', 'type']
110
111
104class Server(base.APIResourceWrapper): 112class Server(base.APIResourceWrapper):
105 """Simple wrapper around novaclient.server.Server. 113 """Simple wrapper around novaclient.server.Server.
106 114
@@ -302,6 +310,13 @@ def server_serial_console(request, instance_id, console_type='serial'):
302 310
303 311
304@profiler.trace 312@profiler.trace
313def server_mks_console(request, instance_id, console_type='mks'):
314 microver = get_microversion(request, "remote_console_mks")
315 return MKSConsole(novaclient(request, microver).servers.get_mks_console(
316 instance_id, console_type)['remote_console'])
317
318
319@profiler.trace
305def flavor_create(request, name, memory, vcpu, disk, flavorid='auto', 320def flavor_create(request, name, memory, vcpu, disk, flavorid='auto',
306 ephemeral=0, swap=0, metadata=None, is_public=True, 321 ephemeral=0, swap=0, metadata=None, is_public=True,
307 rxtx_factor=1): 322 rxtx_factor=1):
diff --git a/openstack_dashboard/api/rest/neutron.py b/openstack_dashboard/api/rest/neutron.py
index 004a618..31945c2 100644
--- a/openstack_dashboard/api/rest/neutron.py
+++ b/openstack_dashboard/api/rest/neutron.py
@@ -129,7 +129,7 @@ class Ports(generic.View):
129 """Get a list of ports for a network 129 """Get a list of ports for a network
130 130
131 The listing result is an object with property "items". Each item is 131 The listing result is an object with property "items". Each item is
132 a subnet. 132 a port.
133 """ 133 """
134 # see 134 # see
135 # https://github.com/openstack/neutron/blob/master/neutron/api/v2/attributes.py 135 # https://github.com/openstack/neutron/blob/master/neutron/api/v2/attributes.py
@@ -153,6 +153,15 @@ class Trunk(generic.View):
153 trunk = api.neutron.trunk_show(request, trunk_id) 153 trunk = api.neutron.trunk_show(request, trunk_id)
154 return trunk.to_dict() 154 return trunk.to_dict()
155 155
156 @rest_utils.ajax(data_required=True)
157 def patch(self, request, trunk_id):
158 """Update a specific trunk"""
159 old_trunk = request.DATA[0]
160 new_trunk = request.DATA[1]
161
162 return api.neutron.trunk_update(
163 request, trunk_id, old_trunk, new_trunk)
164
156 165
157@urls.register 166@urls.register
158class Trunks(generic.View): 167class Trunks(generic.View):
@@ -169,6 +178,14 @@ class Trunks(generic.View):
169 result = api.neutron.trunk_list(request, **request.GET.dict()) 178 result = api.neutron.trunk_list(request, **request.GET.dict())
170 return {'items': [n.to_dict() for n in result]} 179 return {'items': [n.to_dict() for n in result]}
171 180
181 @rest_utils.ajax(data_required=True)
182 def post(self, request):
183 new_trunk = api.neutron.trunk_create(request, **request.DATA)
184 return rest_utils.CreatedResponse(
185 '/api/neutron/trunks/%s' % new_trunk.id,
186 new_trunk.to_dict()
187 )
188
172 189
173@urls.register 190@urls.register
174class Services(generic.View): 191class Services(generic.View):
diff --git a/openstack_dashboard/api/rest/nova.py b/openstack_dashboard/api/rest/nova.py
index 36e7579..27fea2f 100644
--- a/openstack_dashboard/api/rest/nova.py
+++ b/openstack_dashboard/api/rest/nova.py
@@ -51,7 +51,7 @@ class Features(generic.View):
51 @rest_utils.ajax() 51 @rest_utils.ajax()
52 def get(self, request, name): 52 def get(self, request, name):
53 """Check if a specified feature is supported.""" 53 """Check if a specified feature is supported."""
54 return api.nova.is_feature_available(request, name) 54 return api.nova.is_feature_available(request, [name])
55 55
56 56
57@urls.register 57@urls.register
@@ -246,7 +246,8 @@ class RemoteConsoleInfo(generic.View):
246 CONSOLES = OrderedDict([('VNC', api.nova.server_vnc_console), 246 CONSOLES = OrderedDict([('VNC', api.nova.server_vnc_console),
247 ('SPICE', api.nova.server_spice_console), 247 ('SPICE', api.nova.server_spice_console),
248 ('RDP', api.nova.server_rdp_console), 248 ('RDP', api.nova.server_rdp_console),
249 ('SERIAL', api.nova.server_serial_console)]) 249 ('SERIAL', api.nova.server_serial_console),
250 ('MKS', api.nova.server_mks_console)])
250 251
251 """Get a tuple of console url and console type.""" 252 """Get a tuple of console url and console type."""
252 if console_type == 'AUTO': 253 if console_type == 'AUTO':
diff --git a/openstack_dashboard/dashboards/admin/instances/tests.py b/openstack_dashboard/dashboards/admin/instances/tests.py
index 211f81d..b353821 100644
--- a/openstack_dashboard/dashboards/admin/instances/tests.py
+++ b/openstack_dashboard/dashboards/admin/instances/tests.py
@@ -117,7 +117,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
117 server.flavor['id'] = str(uuid.UUID(int=i)) 117 server.flavor['id'] = str(uuid.UUID(int=i))
118 118
119 api.glance.image_list_detailed(IsA(http.HttpRequest))\ 119 api.glance.image_list_detailed(IsA(http.HttpRequest))\
120 .AndReturn(images) 120 .AndReturn((images, False, False))
121 api.nova.flavor_list(IsA(http.HttpRequest)).AndReturn(flavors) 121 api.nova.flavor_list(IsA(http.HttpRequest)).AndReturn(flavors)
122 search_opts = {'marker': None, 'paginate': True, 'all_tenants': True} 122 search_opts = {'marker': None, 'paginate': True, 'all_tenants': True}
123 api.nova.server_list(IsA(http.HttpRequest), 123 api.nova.server_list(IsA(http.HttpRequest),
@@ -140,9 +140,9 @@ class InstanceViewTest(test.BaseAdminViewTests):
140 instances = res.context['table'].data 140 instances = res.context['table'].data
141 self.assertTemplateUsed(res, INDEX_TEMPLATE) 141 self.assertTemplateUsed(res, INDEX_TEMPLATE)
142 # Since error messages produced for each instance are identical, 142 # Since error messages produced for each instance are identical,
143 # there will be only two error messages for all instances 143 # there will be only one error message for all instances
144 # (messages de-duplication). 144 # (messages de-duplication).
145 self.assertMessageCount(res, error=2) 145 self.assertMessageCount(res, error=1)
146 self.assertItemsEqual(instances, servers) 146 self.assertItemsEqual(instances, servers)
147 147
148 @test.create_stubs({ 148 @test.create_stubs({
diff --git a/openstack_dashboard/dashboards/admin/instances/urls.py b/openstack_dashboard/dashboards/admin/instances/urls.py
index 455942c..e33ae4c 100644
--- a/openstack_dashboard/dashboards/admin/instances/urls.py
+++ b/openstack_dashboard/dashboards/admin/instances/urls.py
@@ -30,6 +30,7 @@ urlpatterns = [
30 url(INSTANCES % 'detail', views.DetailView.as_view(), name='detail'), 30 url(INSTANCES % 'detail', views.DetailView.as_view(), name='detail'),
31 url(INSTANCES % 'console', views.console, name='console'), 31 url(INSTANCES % 'console', views.console, name='console'),
32 url(INSTANCES % 'vnc', views.vnc, name='vnc'), 32 url(INSTANCES % 'vnc', views.vnc, name='vnc'),
33 url(INSTANCES % 'mks', views.mks, name='mks'),
33 url(INSTANCES % 'spice', views.spice, name='spice'), 34 url(INSTANCES % 'spice', views.spice, name='spice'),
34 url(INSTANCES % 'rdp', views.rdp, name='rdp'), 35 url(INSTANCES % 'rdp', views.rdp, name='rdp'),
35 url(INSTANCES % 'live_migrate', views.LiveMigrateView.as_view(), 36 url(INSTANCES % 'live_migrate', views.LiveMigrateView.as_view(),
diff --git a/openstack_dashboard/dashboards/admin/instances/views.py b/openstack_dashboard/dashboards/admin/instances/views.py
index c23ef2c..2d3e53c 100644
--- a/openstack_dashboard/dashboards/admin/instances/views.py
+++ b/openstack_dashboard/dashboards/admin/instances/views.py
@@ -61,6 +61,11 @@ def rdp(args, **kvargs):
61 return views.rdp(args, **kvargs) 61 return views.rdp(args, **kvargs)
62 62
63 63
64# re-use mks from project.instances.views to make reflection work
65def mks(args, **kvargs):
66 return views.mks(args, **kvargs)
67
68
64# re-use get_resource_id_by_name from project.instances.views 69# re-use get_resource_id_by_name from project.instances.views
65def swap_filter(resources, filters, fake_field, real_field): 70def swap_filter(resources, filters, fake_field, real_field):
66 return views.swap_filter(resources, filters, fake_field, real_field) 71 return views.swap_filter(resources, filters, fake_field, real_field)
diff --git a/openstack_dashboard/dashboards/admin/volumes/tables.py b/openstack_dashboard/dashboards/admin/volumes/tables.py
index ae88850..a06740c 100644
--- a/openstack_dashboard/dashboards/admin/volumes/tables.py
+++ b/openstack_dashboard/dashboards/admin/volumes/tables.py
@@ -92,10 +92,16 @@ class UpdateVolumeStatusAction(tables.LinkAction):
92 "volume_extension:volume_admin_actions:reset_status"),) 92 "volume_extension:volume_admin_actions:reset_status"),)
93 93
94 94
95class AttachmentColumn(volumes_tables.AttachmentColumn):
96 instance_detail_url = "horizon:admin:instances:detail"
97
98
95class VolumesTable(volumes_tables.VolumesTable): 99class VolumesTable(volumes_tables.VolumesTable):
96 name = tables.WrappingColumn("name", 100 name = tables.WrappingColumn("name",
97 verbose_name=_("Name"), 101 verbose_name=_("Name"),
98 link="horizon:admin:volumes:detail") 102 link="horizon:admin:volumes:detail")
103 attachments = AttachmentColumn("attachments",
104 verbose_name=_("Attached To"))
99 host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host")) 105 host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host"))
100 tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None), 106 tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None),
101 verbose_name=_("Project")) 107 verbose_name=_("Project"))
diff --git a/openstack_dashboard/dashboards/project/floating_ips/tests.py b/openstack_dashboard/dashboards/project/floating_ips/tests.py
index d800f01..e7fc4bd 100644
--- a/openstack_dashboard/dashboards/project/floating_ips/tests.py
+++ b/openstack_dashboard/dashboards/project/floating_ips/tests.py
@@ -54,17 +54,14 @@ class FloatingIpViewTests(test.TestCase):
54 # Verify that our "associated" floating IP isn't in the choices list. 54 # Verify that our "associated" floating IP isn't in the choices list.
55 self.assertNotIn(self.floating_ips.first(), choices) 55 self.assertNotIn(self.floating_ips.first(), choices)
56 56
57 @test.create_stubs({api.neutron: ('floating_ip_target_list', 57 @test.create_stubs({api.neutron: ('floating_ip_target_list_by_instance',
58 'floating_ip_target_get_by_instance',
59 'tenant_floating_ip_list',)}) 58 'tenant_floating_ip_list',)})
60 def test_associate_with_instance_id(self): 59 def test_associate_with_instance_id(self):
61 targets = self._get_fip_targets() 60 targets = self._get_fip_targets()
62 target = targets[0] 61 target = targets[0]
63 api.neutron.floating_ip_target_list(IsA(http.HttpRequest)) \ 62 api.neutron.floating_ip_target_list_by_instance(
64 .AndReturn(targets) 63 IsA(http.HttpRequest), target.instance_id) \
65 api.neutron.floating_ip_target_get_by_instance( 64 .AndReturn([target])
66 IsA(http.HttpRequest), target.instance_id, targets) \
67 .AndReturn(target)
68 api.neutron.tenant_floating_ip_list(IsA(http.HttpRequest)) \ 65 api.neutron.tenant_floating_ip_list(IsA(http.HttpRequest)) \
69 .AndReturn(self.floating_ips.list()) 66 .AndReturn(self.floating_ips.list())
70 self.mox.ReplayAll() 67 self.mox.ReplayAll()
diff --git a/openstack_dashboard/dashboards/project/floating_ips/workflows.py b/openstack_dashboard/dashboards/project/floating_ips/workflows.py
index ce4516d..147353c 100644
--- a/openstack_dashboard/dashboards/project/floating_ips/workflows.py
+++ b/openstack_dashboard/dashboards/project/floating_ips/workflows.py
@@ -53,10 +53,15 @@ class AssociateIPAction(workflows.Action):
53 q_instance_id = self.request.GET.get('instance_id') 53 q_instance_id = self.request.GET.get('instance_id')
54 q_port_id = self.request.GET.get('port_id') 54 q_port_id = self.request.GET.get('port_id')
55 if q_instance_id: 55 if q_instance_id:
56 targets = self._get_target_list() 56 targets = self._get_target_list(q_instance_id)
57 target = api.neutron.floating_ip_target_get_by_instance( 57 # Setting the initial value here is required to avoid a situation
58 self.request, q_instance_id, targets) 58 # where instance_id passed in the URL is used as the initial value
59 self.initial['instance_id'] = target.id 59 # unexpectedly. (This always happens if the form is invoked from
60 # the instance table.)
61 if targets:
62 self.initial['instance_id'] = targets[0].id
63 else:
64 self.initial['instance_id'] = ''
60 elif q_port_id: 65 elif q_port_id:
61 targets = self._get_target_list() 66 targets = self._get_target_list()
62 for target in targets: 67 for target in targets:
@@ -84,10 +89,14 @@ class AssociateIPAction(workflows.Action):
84 return options 89 return options
85 90
86 @memoized.memoized_method 91 @memoized.memoized_method
87 def _get_target_list(self): 92 def _get_target_list(self, instance_id=None):
88 targets = [] 93 targets = []
89 try: 94 try:
90 targets = api.neutron.floating_ip_target_list(self.request) 95 if instance_id:
96 targets = api.neutron.floating_ip_target_list_by_instance(
97 self.request, instance_id)
98 else:
99 targets = api.neutron.floating_ip_target_list(self.request)
91 except Exception: 100 except Exception:
92 redirect = reverse('horizon:project:floating_ips:index') 101 redirect = reverse('horizon:project:floating_ips:index')
93 exceptions.handle(self.request, 102 exceptions.handle(self.request,
@@ -97,7 +106,12 @@ class AssociateIPAction(workflows.Action):
97 106
98 # TODO(amotoki): [drop-nova-network] Rename instance_id to port_id 107 # TODO(amotoki): [drop-nova-network] Rename instance_id to port_id
99 def populate_instance_id_choices(self, request, context): 108 def populate_instance_id_choices(self, request, context):
100 targets = self._get_target_list() 109 q_instance_id = self.request.GET.get('instance_id')
110 # The reason of specifying an empty tuple when q_instance_id is None
111 # is to make memoized_method _get_target_list work. Two calls of
112 # _get_target_list from here and __init__ must have a same arguments.
113 params = (q_instance_id, ) if q_instance_id else ()
114 targets = self._get_target_list(*params)
101 instances = sorted([(target.id, target.name) for target in targets], 115 instances = sorted([(target.id, target.name) for target in targets],
102 # Sort FIP targets by server name for easy browsing 116 # Sort FIP targets by server name for easy browsing
103 key=lambda x: x[1]) 117 key=lambda x: x[1])
diff --git a/openstack_dashboard/dashboards/project/instances/console.py b/openstack_dashboard/dashboards/project/instances/console.py
index 9380889..3ecc603b 100644
--- a/openstack_dashboard/dashboards/project/instances/console.py
+++ b/openstack_dashboard/dashboards/project/instances/console.py
@@ -27,7 +27,8 @@ LOG = logging.getLogger(__name__)
27CONSOLES = OrderedDict([('VNC', api.nova.server_vnc_console), 27CONSOLES = OrderedDict([('VNC', api.nova.server_vnc_console),
28 ('SPICE', api.nova.server_spice_console), 28 ('SPICE', api.nova.server_spice_console),
29 ('RDP', api.nova.server_rdp_console), 29 ('RDP', api.nova.server_rdp_console),
30 ('SERIAL', api.nova.server_serial_console)]) 30 ('SERIAL', api.nova.server_serial_console),
31 ('MKS', api.nova.server_mks_console)])
31 32
32 33
33def get_console(request, console_type, instance): 34def get_console(request, console_type, instance):
diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py
index 52fa834..98b3d12 100644
--- a/openstack_dashboard/dashboards/project/instances/tests.py
+++ b/openstack_dashboard/dashboards/project/instances/tests.py
@@ -181,7 +181,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
181 api.nova.flavor_list(IsA(http.HttpRequest)) \ 181 api.nova.flavor_list(IsA(http.HttpRequest)) \
182 .AndReturn(flavors) 182 .AndReturn(flavors)
183 api.glance.image_list_detailed(IsA(http.HttpRequest)) \ 183 api.glance.image_list_detailed(IsA(http.HttpRequest)) \
184 .AndReturn(images) 184 .AndReturn((images, False, False))
185 api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ 185 api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \
186 .AndRaise(self.exceptions.nova) 186 .AndRaise(self.exceptions.nova)
187 api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \ 187 api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py
index 01242ca..39a7b40 100644
--- a/openstack_dashboard/dashboards/project/instances/views.py
+++ b/openstack_dashboard/dashboards/project/instances/views.py
@@ -209,6 +209,17 @@ def vnc(request, instance_id):
209 exceptions.handle(request, msg, redirect=redirect) 209 exceptions.handle(request, msg, redirect=redirect)
210 210
211 211
212def mks(request, instance_id):
213 try:
214 instance = api.nova.server_get(request, instance_id)
215 console_url = project_console.get_console(request, 'MKS', instance)[1]
216 return shortcuts.redirect(console_url)
217 except Exception:
218 redirect = reverse("horizon:project:instances:index")
219 msg = _('Unable to get MKS console for instance "%s".') % instance_id
220 exceptions.handle(request, msg, redirect=redirect)
221
222
212def spice(request, instance_id): 223def spice(request, instance_id):
213 try: 224 try:
214 instance = api.nova.server_get(request, instance_id) 225 instance = api.nova.server_get(request, instance_id)
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js
index 7c384fb..3a13c03 100644
--- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js
@@ -35,7 +35,7 @@
35 */ 35 */
36 function LaunchInstanceConfigurationController() { 36 function LaunchInstanceConfigurationController() {
37 var ctrl = this; 37 var ctrl = this;
38 38 ctrl.title = gettext("Customization Script");
39 ctrl.MAX_SCRIPT_SIZE = MAX_SCRIPT_SIZE; 39 ctrl.MAX_SCRIPT_SIZE = MAX_SCRIPT_SIZE;
40 40
41 ctrl.diskConfigOptions = [ 41 ctrl.diskConfigOptions = [
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html
index fd7cca7..cae980f 100644
--- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html
@@ -1,12 +1,14 @@
1<div ng-controller="LaunchInstanceConfigurationController as config"> 1<div ng-controller="LaunchInstanceConfigurationController as ctrl">
2 <p class="step-description" translate> 2 <p class="step-description" translate>
3 You can customize your instance after it has launched using the options available here. 3 You can customize your instance after it has launched using the options available here.
4 "Customization Script" is analogous to "User Data" in other systems. 4 "Customization Script" is analogous to "User Data" in other systems.
5 </p> 5 </p>
6 6
7 <load-edit config="config" 7 <load-edit title="{$ ctrl.title $}"
8 user-input="model.newInstanceSpec" 8 model="model.newInstanceSpec.user_data"
9 key="user_data"> 9 max-bytes="{$ ctrl.MAX_SCRIPT_SIZE $}"
10 key="user-data"
11 rows=8>
10 </load-edit> 12 </load-edit>
11 13
12 <div hz-if-nova-extensions='["DiskConfig"]'> 14 <div hz-if-nova-extensions='["DiskConfig"]'>
@@ -17,7 +19,7 @@
17 <select class="form-control" 19 <select class="form-control"
18 id="disk-partition" 20 id="disk-partition"
19 ng-model="model.newInstanceSpec.disk_config" 21 ng-model="model.newInstanceSpec.disk_config"
20 ng-options="option.value as option.text for option in config.diskConfigOptions"> 22 ng-options="option.value as option.text for option in ctrl.diskConfigOptions">
21 </select> 23 </select>
22 </div> 24 </div>
23 </div> 25 </div>
diff --git a/openstack_dashboard/dashboards/project/volumes/forms.py b/openstack_dashboard/dashboards/project/volumes/forms.py
index ad336a9..4efe2b1 100644
--- a/openstack_dashboard/dashboards/project/volumes/forms.py
+++ b/openstack_dashboard/dashboards/project/volumes/forms.py
@@ -20,7 +20,6 @@ Views for managing volumes.
20from django.conf import settings 20from django.conf import settings
21from django.core.urlresolvers import reverse 21from django.core.urlresolvers import reverse
22from django.forms import ValidationError 22from django.forms import ValidationError
23from django import http
24from django.template.defaultfilters import filesizeformat 23from django.template.defaultfilters import filesizeformat
25from django.utils.translation import pgettext_lazy 24from django.utils.translation import pgettext_lazy
26from django.utils.translation import ugettext_lazy as _ 25from django.utils.translation import ugettext_lazy as _
@@ -549,6 +548,10 @@ class CreateSnapshotForm(forms.SelfHandlingForm):
549class CreateTransferForm(forms.SelfHandlingForm): 548class CreateTransferForm(forms.SelfHandlingForm):
550 name = forms.CharField(max_length=255, label=_("Transfer Name")) 549 name = forms.CharField(max_length=255, label=_("Transfer Name"))
551 550
551 def __init__(self, *args, **kwargs):
552 self.next_view = kwargs.pop('next_view', None)
553 super(CreateTransferForm, self).__init__(*args, **kwargs)
554
552 def clean_name(self): 555 def clean_name(self):
553 cleaned_name = self.cleaned_data['name'] 556 cleaned_name = self.cleaned_data['name']
554 if cleaned_name.isspace(): 557 if cleaned_name.isspace():
@@ -564,10 +567,12 @@ class CreateTransferForm(forms.SelfHandlingForm):
564 567
565 msg = _('Created volume transfer: "%s".') % data['name'] 568 msg = _('Created volume transfer: "%s".') % data['name']
566 messages.success(request, msg) 569 messages.success(request, msg)
567 response = http.HttpResponseRedirect( 570 kwargs = {
568 reverse("horizon:project:volumes:show_transfer", 571 'transfer_id': transfer.id,
569 args=(transfer.id, transfer.auth_key))) 572 'auth_key': transfer.auth_key
570 return response 573 }
574 request.method = 'GET'
575 return self.next_view.as_view()(request, **kwargs)
571 except Exception: 576 except Exception:
572 redirect = reverse("horizon:project:volumes:index") 577 redirect = reverse("horizon:project:volumes:index")
573 exceptions.handle(request, _('Unable to create volume transfer.'), 578 exceptions.handle(request, _('Unable to create volume transfer.'),
diff --git a/openstack_dashboard/dashboards/project/volumes/tables.py b/openstack_dashboard/dashboards/project/volumes/tables.py
index e616b3c..d57cf37 100644
--- a/openstack_dashboard/dashboards/project/volumes/tables.py
+++ b/openstack_dashboard/dashboards/project/volumes/tables.py
@@ -346,7 +346,7 @@ def get_size(volume):
346 return _("%sGiB") % volume.size 346 return _("%sGiB") % volume.size
347 347
348 348
349def get_attachment_name(request, attachment): 349def get_attachment_name(request, attachment, instance_detail_url=None):
350 server_id = attachment.get("server_id", None) 350 server_id = attachment.get("server_id", None)
351 if "instance" in attachment and attachment['instance']: 351 if "instance" in attachment and attachment['instance']:
352 name = attachment["instance"].name 352 name = attachment["instance"].name
@@ -358,8 +358,10 @@ def get_attachment_name(request, attachment):
358 name = server_id 358 name = server_id
359 exceptions.handle(request, _("Unable to retrieve " 359 exceptions.handle(request, _("Unable to retrieve "
360 "attachment information.")) 360 "attachment information."))
361 if not instance_detail_url:
362 instance_detail_url = "horizon:project:instances:detail"
361 try: 363 try:
362 url = reverse("horizon:project:instances:detail", args=(server_id,)) 364 url = reverse(instance_detail_url, args=(server_id,))
363 instance = '<a href="%s">%s</a>' % (url, html.escape(name)) 365 instance = '<a href="%s">%s</a>' % (url, html.escape(name))
364 except NoReverseMatch: 366 except NoReverseMatch:
365 instance = html.escape(name) 367 instance = html.escape(name)
@@ -372,6 +374,9 @@ class AttachmentColumn(tables.WrappingColumn):
372 So it that does complex processing on the attachments 374 So it that does complex processing on the attachments
373 for a volume instance. 375 for a volume instance.
374 """ 376 """
377
378 instance_detail_url = "horizon:project:instances:detail"
379
375 def get_raw_data(self, volume): 380 def get_raw_data(self, volume):
376 request = self.table.request 381 request = self.table.request
377 link = _('%(dev)s on %(instance)s') 382 link = _('%(dev)s on %(instance)s')
@@ -380,7 +385,8 @@ class AttachmentColumn(tables.WrappingColumn):
380 for attachment in [att for att in volume.attachments if att]: 385 for attachment in [att for att in volume.attachments if att]:
381 # When a volume is attached it may return the server_id 386 # When a volume is attached it may return the server_id
382 # without the server name... 387 # without the server name...
383 instance = get_attachment_name(request, attachment) 388 instance = get_attachment_name(request, attachment,
389 self.instance_detail_url)
384 vals = {"instance": instance, 390 vals = {"instance": instance,
385 "dev": html.escape(attachment.get("device", ""))} 391 "dev": html.escape(attachment.get("device", ""))}
386 attachments.append(link % vals) 392 attachments.append(link % vals)
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_show_transfer.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_show_transfer.html
index 947f4be..2a9a687 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_show_transfer.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_show_transfer.html
@@ -1,6 +1,11 @@
1{% extends "horizon/common/_modal_form.html" %} 1{% extends "horizon/common/_modal_form.html" %}
2{% load i18n %} 2{% load i18n %}
3 3
4{% block header %}
5 <div class="modal-header">
6 <h3 class="modal-title">{% block modal-header %}{{ modal_header }}{% endblock %}</h3>
7 </div>
8{% endblock %}
4{% block modal-body-right %} 9{% block modal-body-right %}
5 <h3>{% trans "Description:" %}</h3> 10 <h3>{% trans "Description:" %}</h3>
6 <p>{% trans "The Transfer ID and the Authorization Key are needed by the recipient in order to accept the transfer. Please capture both the Transfer ID and the Authorization Key and provide them to your transfer recipient." %}</p> 11 <p>{% trans "The Transfer ID and the Authorization Key are needed by the recipient in order to accept the transfer. Please capture both the Transfer ID and the Authorization Key and provide them to your transfer recipient." %}</p>
@@ -11,8 +16,5 @@
11 <span class="fa fa-download"></span> 16 <span class="fa fa-download"></span>
12 {{ download_label }} 17 {{ download_label }}
13 </a> 18 </a>
14 <a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}" 19 <a onClick="location.href='{{cancel_url}}'" href="{{ cancel_url }}" class="btn btn-default">{{ cancel_label }}</a>
15 class="btn btn-default cancel">
16 {{ cancel_label }}
17 </a>
18{% endblock %} 20{% endblock %}
diff --git a/openstack_dashboard/dashboards/project/volumes/tests.py b/openstack_dashboard/dashboards/project/volumes/tests.py
index e8767ae..bff5b98 100644
--- a/openstack_dashboard/dashboards/project/volumes/tests.py
+++ b/openstack_dashboard/dashboards/project/volumes/tests.py
@@ -1775,14 +1775,17 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
1775 search_opts=None) 1775 search_opts=None)
1776 self.assertEqual(10, mock_limits.call_count) 1776 self.assertEqual(10, mock_limits.call_count)
1777 1777
1778 @mock.patch.object(cinder, 'transfer_get')
1778 @mock.patch.object(cinder, 'transfer_create') 1779 @mock.patch.object(cinder, 'transfer_create')
1779 def test_create_transfer(self, mock_transfer): 1780 def test_create_transfer(self, mock_transfer_create, mock_transfer_get):
1780 volumes = self.volumes.list() 1781 volumes = self.volumes.list()
1781 volToTransfer = [v for v in volumes if v.status == 'available'][0] 1782 volToTransfer = [v for v in volumes if v.status == 'available'][0]
1782 formData = {'volume_id': volToTransfer.id, 1783 formData = {'volume_id': volToTransfer.id,
1783 'name': u'any transfer name'} 1784 'name': u'any transfer name'}
1784 1785
1785 mock_transfer.return_value = self.cinder_volume_transfers.first() 1786 transfer = self.cinder_volume_transfers.first()
1787 mock_transfer_create.return_value = transfer
1788 mock_transfer_get.return_value = transfer
1786 1789
1787 # Create a transfer for the first available volume 1790 # Create a transfer for the first available volume
1788 url = reverse('horizon:project:volumes:create_transfer', 1791 url = reverse('horizon:project:volumes:create_transfer',
@@ -1790,9 +1793,11 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
1790 res = self.client.post(url, formData) 1793 res = self.client.post(url, formData)
1791 1794
1792 self.assertNoFormErrors(res) 1795 self.assertNoFormErrors(res)
1793 mock_transfer.assert_called_once_with(test.IsHttpRequest(), 1796 mock_transfer_create.assert_called_once_with(test.IsHttpRequest(),
1794 formData['volume_id'], 1797 formData['volume_id'],
1795 formData['name']) 1798 formData['name'])
1799 mock_transfer_get.assert_called_once_with(test.IsHttpRequest(),
1800 transfer.id)
1796 1801
1797 @mock.patch.object(api.nova, 'server_list') 1802 @mock.patch.object(api.nova, 'server_list')
1798 @mock.patch.object(cinder, 'volume_backup_supported') 1803 @mock.patch.object(cinder, 'volume_backup_supported')
diff --git a/openstack_dashboard/dashboards/project/volumes/views.py b/openstack_dashboard/dashboards/project/volumes/views.py
index f1f2c14..209447f 100644
--- a/openstack_dashboard/dashboards/project/volumes/views.py
+++ b/openstack_dashboard/dashboards/project/volumes/views.py
@@ -378,6 +378,11 @@ class CreateTransferView(forms.ModalFormView):
378 def get_initial(self): 378 def get_initial(self):
379 return {'volume_id': self.kwargs["volume_id"]} 379 return {'volume_id': self.kwargs["volume_id"]}
380 380
381 def get_form_kwargs(self):
382 kwargs = super(CreateTransferView, self).get_form_kwargs()
383 kwargs['next_view'] = ShowTransferView
384 return kwargs
385
381 386
382class AcceptTransferView(forms.ModalFormView): 387class AcceptTransferView(forms.ModalFormView):
383 form_class = volume_forms.AcceptTransferForm 388 form_class = volume_forms.AcceptTransferForm
@@ -395,6 +400,7 @@ class ShowTransferView(forms.ModalFormView):
395 template_name = 'project/volumes/show_transfer.html' 400 template_name = 'project/volumes/show_transfer.html'
396 success_url = reverse_lazy('horizon:project:volumes:index') 401 success_url = reverse_lazy('horizon:project:volumes:index')
397 modal_id = "show_volume_transfer_modal" 402 modal_id = "show_volume_transfer_modal"
403 modal_header = _("Volume Transfer")
398 submit_url = "horizon:project:volumes:show_transfer" 404 submit_url = "horizon:project:volumes:show_transfer"
399 cancel_label = _("Close") 405 cancel_label = _("Close")
400 download_label = _("Download transfer credentials") 406 download_label = _("Download transfer credentials")
@@ -416,8 +422,6 @@ class ShowTransferView(forms.ModalFormView):
416 context = super(ShowTransferView, self).get_context_data(**kwargs) 422 context = super(ShowTransferView, self).get_context_data(**kwargs)
417 context['transfer_id'] = self.kwargs['transfer_id'] 423 context['transfer_id'] = self.kwargs['transfer_id']
418 context['auth_key'] = self.kwargs['auth_key'] 424 context['auth_key'] = self.kwargs['auth_key']
419 context['submit_url'] = reverse(self.submit_url, args=[
420 context['transfer_id'], context['auth_key']])
421 context['download_label'] = self.download_label 425 context['download_label'] = self.download_label
422 context['download_url'] = reverse( 426 context['download_url'] = reverse(
423 'horizon:project:volumes:download_transfer_creds', 427 'horizon:project:volumes:download_transfer_creds',
diff --git a/openstack_dashboard/enabled/_1500_project_trunks_panel.py b/openstack_dashboard/enabled/_1500_project_trunks_panel.py
index 3445ee6..1775743 100644
--- a/openstack_dashboard/enabled/_1500_project_trunks_panel.py
+++ b/openstack_dashboard/enabled/_1500_project_trunks_panel.py
@@ -8,6 +8,3 @@ PANEL_GROUP = 'network'
8# Python panel class of the PANEL to be added. 8# Python panel class of the PANEL to be added.
9ADD_PANEL = \ 9ADD_PANEL = \
10 'openstack_dashboard.dashboards.project.trunks.panel.Trunks' 10 'openstack_dashboard.dashboards.project.trunks.panel.Trunks'
11
12# Will default to disabled until the feature is completed.
13DISABLED = True
diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example
index 36e698f..995c828 100644
--- a/openstack_dashboard/local/local_settings.py.example
+++ b/openstack_dashboard/local/local_settings.py.example
@@ -104,8 +104,8 @@ WEBROOT = '/'
104#OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT = False 104#OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT = False
105 105
106# Set Console type: 106# Set Console type:
107# valid options are "AUTO"(default), "VNC", "SPICE", "RDP", "SERIAL" or None 107# valid options are "AUTO"(default), "VNC", "SPICE", "RDP", "SERIAL", "MKS"
108# Set to None explicitly if you want to deactivate the console. 108# or None. Set to None explicitly if you want to deactivate the console.
109#CONSOLE_TYPE = "AUTO" 109#CONSOLE_TYPE = "AUTO"
110 110
111# If provided, a "Report Bug" link will be displayed in the site header 111# If provided, a "Report Bug" link will be displayed in the site header
diff --git a/openstack_dashboard/locale/cs/LC_MESSAGES/djangojs.po b/openstack_dashboard/locale/cs/LC_MESSAGES/djangojs.po
index c27b5fb..9033db2 100644
--- a/openstack_dashboard/locale/cs/LC_MESSAGES/djangojs.po
+++ b/openstack_dashboard/locale/cs/LC_MESSAGES/djangojs.po
@@ -2,17 +2,16 @@
2# Zbyněk Schwarz <zbynek.schwarz@gmail.com>, 2015. #zanata 2# Zbyněk Schwarz <zbynek.schwarz@gmail.com>, 2015. #zanata
3# Lenka Husáková <lenka.husakova@ultimum.io>, 2016. #zanata 3# Lenka Husáková <lenka.husakova@ultimum.io>, 2016. #zanata
4# Stanislav Ulrych <stanislav.ulrych@ultimum.io>, 2016. #zanata 4# Stanislav Ulrych <stanislav.ulrych@ultimum.io>, 2016. #zanata
5# Stanislav Ulrych <stanislav.ulrych@ultimum.io>, 2017. #zanata
6msgid "" 5msgid ""
7msgstr "" 6msgstr ""
8"Project-Id-Version: horizon 13.0.0.0b2.dev91\n" 7"Project-Id-Version: horizon 13.0.0.0b2.dev141\n"
9"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 8"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
10"POT-Creation-Date: 2017-11-17 06:13+0000\n" 9"POT-Creation-Date: 2017-11-28 23:44+0000\n"
11"MIME-Version: 1.0\n" 10"MIME-Version: 1.0\n"
12"Content-Type: text/plain; charset=UTF-8\n" 11"Content-Type: text/plain; charset=UTF-8\n"
13"Content-Transfer-Encoding: 8bit\n" 12"Content-Transfer-Encoding: 8bit\n"
14"PO-Revision-Date: 2017-11-17 06:13+0000\n" 13"PO-Revision-Date: 2016-11-24 08:54+0000\n"
15"Last-Translator: Lenka Husáková <lenka.husakova@ultimum.io>\n" 14"Last-Translator: Stanislav Ulrych <stanislav.ulrych@ultimum.io>\n"
16"Language-Team: Czech\n" 15"Language-Team: Czech\n"
17"Language: cs\n" 16"Language: cs\n"
18"X-Generator: Zanata 3.9.6\n" 17"X-Generator: Zanata 3.9.6\n"
@@ -2635,21 +2634,9 @@ msgstr[0] "Vybrali jste \"%s\". Smazaný obraz nelze obnovit."
2635msgstr[1] "Vybrali jste \"%s\". Smazané obrazy nelze obnovit." 2634msgstr[1] "Vybrali jste \"%s\". Smazané obrazy nelze obnovit."
2636msgstr[2] "Vybrali jste \"%s\". Smazané obrazy nelze obnovit." 2635msgstr[2] "Vybrali jste \"%s\". Smazané obrazy nelze obnovit."
2637 2636
2638msgid "error"
2639msgid_plural "errors"
2640msgstr[0] "chyba"
2641msgstr[1] "chyby"
2642msgstr[2] "chyb"
2643
2644msgid "image" 2637msgid "image"
2645msgstr "obraz" 2638msgstr "obraz"
2646 2639
2647msgid "message"
2648msgid_plural "messages"
2649msgstr[0] "zpráva"
2650msgstr[1] "zprávy"
2651msgstr[2] "zpráv"
2652
2653#, python-format 2640#, python-format
2654msgid "resource load failed: %s" 2641msgid "resource load failed: %s"
2655msgstr "Nelze načíst: %s" 2642msgstr "Nelze načíst: %s"
@@ -2657,25 +2644,6 @@ msgstr "Nelze načíst: %s"
2657msgid "snapshot" 2644msgid "snapshot"
2658msgstr "snapshot" 2645msgstr "snapshot"
2659 2646
2660msgid "submit"
2661msgid_plural "submits"
2662msgstr[0] "odeslání"
2663msgstr[1] "odeslání"
2664msgstr[2] "odeslání"
2665
2666#, fuzzy
2667msgid "success"
2668msgid_plural "successes"
2669msgstr[0] "úšpěch"
2670msgstr[1] "úspěchy"
2671msgstr[2] "úspěchy"
2672
2673msgid "title"
2674msgid_plural "titles"
2675msgstr[0] "název"
2676msgstr[1] "názvy"
2677msgstr[2] "názvů"
2678
2679msgid "" 2647msgid ""
2680"{$ ctrl.model.counted.files $} files in\n" 2648"{$ ctrl.model.counted.files $} files in\n"
2681" {$ ctrl.model.counted.folders $} folders." 2649" {$ ctrl.model.counted.folders $} folders."
diff --git a/openstack_dashboard/locale/de/LC_MESSAGES/django.po b/openstack_dashboard/locale/de/LC_MESSAGES/django.po
index f607e1d..c6b3994 100644
--- a/openstack_dashboard/locale/de/LC_MESSAGES/django.po
+++ b/openstack_dashboard/locale/de/LC_MESSAGES/django.po
@@ -8,13 +8,13 @@
8# Robert Simai <robert.simai@suse.com>, 2017. #zanata 8# Robert Simai <robert.simai@suse.com>, 2017. #zanata
9msgid "" 9msgid ""
10msgstr "" 10msgstr ""
11"Project-Id-Version: horizon 13.0.0.0b2.dev119\n" 11"Project-Id-Version: horizon 13.0.0.0b3.dev2\n"
12"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" 12"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
13"POT-Creation-Date: 2017-11-22 09:01+0000\n" 13"POT-Creation-Date: 2017-12-07 18:16+0000\n"
14"MIME-Version: 1.0\n" 14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n" 15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n" 16"Content-Transfer-Encoding: 8bit\n"
17"PO-Revision-Date: 2017-11-02 02:13+0000\n" 17"PO-Revision-Date: 2017-12-08 01:56+0000\n"
18"Last-Translator: Robert Simai <robert.simai@suse.com>\n" 18"Last-Translator: Robert Simai <robert.simai@suse.com>\n"
19"Language-Team: German\n" 19"Language-Team: German\n"
20"Language: de\n" 20"Language: de\n"
@@ -572,6 +572,10 @@ msgstr "Weise eine Netzwerkadresse aus einem Pool zu."
572msgid "Allocate a floating IP from a given floating IP pool." 572msgid "Allocate a floating IP from a given floating IP pool."
573msgstr "Floating IP aus einem angegebenen Pool belegen." 573msgstr "Floating IP aus einem angegebenen Pool belegen."
574 574
575msgctxt "Label in the limit summary"
576msgid "Allocated"
577msgstr "Zugewiesen"
578
575#, python-format 579#, python-format
576msgid "Allocated Floating IP %(ip)s." 580msgid "Allocated Floating IP %(ip)s."
577msgstr "Zugewiesene Floating IP %(ip)s." 581msgstr "Zugewiesene Floating IP %(ip)s."
@@ -2109,12 +2113,18 @@ msgstr "Geräte-ID"
2109msgid "Device ID attached to the port" 2113msgid "Device ID attached to the port"