heat-dashboard-1.0.2/0000775000175100017510000000000013240545010014376 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/0000775000175100017510000000000013240545010015143 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/requirements.txt0000666000175100017510000000052613240544407020445 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. openstackdocstheme>=1.18.1 # Apache-2.0 sphinx!=1.6.6,>=1.6.2 # BSD reno>=2.5.0 # Apache-2.0 sphinxcontrib-httpdomain>=1.3.0 # BSD heat-dashboard-1.0.2/doc/source/0000775000175100017510000000000013240545010016443 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/source/install/0000775000175100017510000000000013240545010020111 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/source/install/index.rst0000666000175100017510000000024713240544407021770 0ustar zuulzuul00000000000000================================= Heat Dashboard installation guide ================================= .. toctree:: :maxdepth: 1 installation uninstallation heat-dashboard-1.0.2/doc/source/install/installation.rst0000666000175100017510000000011713240544407023356 0ustar zuulzuul00000000000000============ Installation ============ .. include:: installation_contents.rst heat-dashboard-1.0.2/doc/source/install/installation_contents.rst0000666000175100017510000000364513240544407025304 0ustar zuulzuul00000000000000Use Heat Dashboard in DevStack ------------------------------ Set up your ``local.conf`` to enable heat-dashboard:: [[local|localrc]] enable_plugin heat-dashboard https://git.openstack.org/openstack/heat-dashboard .. note:: You also need to install Heat itself into DevStack to use Heat Dashboard. Manual Installation ------------------- Clone both Horizon and Heat Dashboard repositories:: git clone https://github.com/openstack/horizon git clone https://github.com/openstack/heat-dashboard Create a virtual environment and install Horizon relevant packages:: pip install -r horizon/requirements.txt Create your ``local_settings.py`` file:: cp horizon/openstack_dashboard/local/local_settings.py.example \ horizon/openstack_dashboard/local/local_settings.py Open newly created ``local_settings.py`` with your text editor, and set some parameter to connect to your OpenStack environment: - Set ``OPENSTACK_HOST`` as hostname or IP address of your OpenStack server. - Verify that the ``OPENSTACK_KEYSTONE_URL`` and ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your environment. (They should be correct unless you modified your OpenStack server to change them.) Install Heat Dashboard with all relevant packages to your Horizon environment:: pip install -e ./heat-dashboard/ Enable heat-dashboard plugin in your Horizon environment:: cp heat-dashboard/heat_dashboard/enabled/* \ horizon/openstack_dashboard/local/enabled cp heat-dashboard/heat_dashboard/conf/* \ horizon/openstack_dashboard/conf/ cp heat-dashboard/heat_dashboard/local_settings.d/* \ horizon/openstack_dashboard/local/local_settings.d/ Finally you can launch Horizon with Heat Dashboard plugin:: cd horizon python manage.py runserver 0.0.0.0:8080 Now you can connect to your Horizon including Heat Dashboard plugin from your browser with URL http://localhost:8080/. heat-dashboard-1.0.2/doc/source/install/uninstallation.rst0000666000175100017510000000057413240544407023730 0ustar zuulzuul00000000000000============== Uninstallation ============== To uninstall this plugin, use ``pip uninstall heat-dashboard`` in your Horizon's virtual environment. You also need to remove following files:: _1610_project_orchestration_panel.py _1620_project_stacks_panel.py _1630_project_resource_types_panel.py _1640_project_template_versions_panel.py _1650_project_template_generator_panel.py heat-dashboard-1.0.2/doc/source/index.rst0000666000175100017510000000110413240544407020313 0ustar zuulzuul00000000000000.. openstack documentation master file, created by sphinx-quickstart on Tue Jul 9 22:26:36 2013. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. ============================================== Welcome to the documentation of Heat Dashboard ============================================== Contents: .. toctree:: :maxdepth: 2 readme install/index contributor/index configuration/index user/index Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` heat-dashboard-1.0.2/doc/source/readme.rst0000666000175100017510000000003613240544407020444 0ustar zuulzuul00000000000000.. include:: ../../README.rst heat-dashboard-1.0.2/doc/source/contributor/0000775000175100017510000000000013240545010021015 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/source/contributor/contributing.rst0000666000175100017510000000154513240544407024276 0ustar zuulzuul00000000000000================= How to Contribute ================= Contributor License Agreement ----------------------------- .. index:: single: license; agreement In order to contribute to the Heat Dashboard project, you need to have signed OpenStack's contributor's agreement. .. seealso:: * http://docs.openstack.org/infra/manual/developers.html * http://wiki.openstack.org/CLA LaunchPad Project ----------------- Most of the tools used for OpenStack depend on a launchpad.net ID for authentication. .. seealso:: * https://launchpad.net * https://launchpad.net/heat-dashboard Project Hosting Details ------------------------- Bug tracker http://launchpad.net/heat-dashboard Code Hosting https://git.openstack.org/cgit/openstack/heat-dashboard Code Review https://review.openstack.org/#/q/status:open+project:openstack/heat-dashboard,n,z heat-dashboard-1.0.2/doc/source/contributor/index.rst0000666000175100017510000000020313240544407022664 0ustar zuulzuul00000000000000=========================== Contributor Documentation =========================== .. toctree:: :maxdepth: 2 contributing heat-dashboard-1.0.2/doc/source/configuration/0000775000175100017510000000000013240545010021312 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/source/configuration/configuration.rst0000666000175100017510000000147713240544407024737 0ustar zuulzuul00000000000000============= Configuration ============= Heat Dashboard has configuration option as below. For more configurations, see `Configuration Guide `_ in the Horizon documentation. OPENSTACK_HEAT_STACK ~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 9.0.0(Mitaka) Default: .. code-block:: python { 'enable_user_pass': True } A dictionary of settings to use with heat stacks. Currently, the only setting available is "enable_user_pass", which can be used to disable the password field while launching the stack. Currently HEAT API needs user password to perform all the heat operations because in HEAT API trusts is not enabled by default. So, this setting can be set as "False" in-case HEAT uses trusts by default otherwise it needs to be set as "True". heat-dashboard-1.0.2/doc/source/configuration/index.rst0000666000175100017510000000023113240544407023162 0ustar zuulzuul00000000000000================================== Heat Dashboard configuration guide ================================== .. toctree:: :maxdepth: 1 configuration heat-dashboard-1.0.2/doc/source/conf.py0000777000175100017510000000543113240544407017763 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys sys.path.insert(0, os.path.abspath('../..')) # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'openstackdocstheme', # 'sphinx.ext.intersphinx', ] # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. # execute "export SPHINX_DEBUG=1" in your terminal to disable # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Heat Dashboard' copyright = u'2017, OpenStack Developers' # openstackdocstheme options repository_name = 'openstack/heat-dashboard' bug_project = 'heat-dashboard' bug_tag = 'doc' html_last_updated_fmt = '%Y-%m-%d %H:%M' # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ["."] # html_theme = '_theme' # html_static_path = ['static'] html_theme = 'openstackdocs' # Output file base name for HTML help builder. htmlhelp_basename = '%sdoc' % project # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ('index', '%s.tex' % project, u'%s Documentation' % project, u'OpenStack Developers', 'manual'), ] man_pages = [ ('index', u'Heat Dashboard Documentation', 'Documentation for Heat Dashboard plugin to Openstack\ Dashboard (Horizon)', [u'OpenStack'], 1) ] # Example configuration for intersphinx: refer to the Python standard library. # intersphinx_mapping = {'http://docs.python.org/': None} heat-dashboard-1.0.2/doc/source/user/0000775000175100017510000000000013240545010017421 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/doc/source/user/index.rst0000666000175100017510000000025513240544407021277 0ustar zuulzuul00000000000000================================= Heat Dashboard User Documentation ================================= .. toctree:: :maxdepth: 2 stacks.rst template_generator.rst heat-dashboard-1.0.2/doc/source/user/stacks.rst0000666000175100017510000001616013240544407021462 0ustar zuulzuul00000000000000======================== Launch and manage stacks ======================== OpenStack Orchestration is a service that you can use to orchestrate multiple composite cloud applications. This service supports the use of both the Amazon Web Services (AWS) CloudFormation template format through both a Query API that is compatible with CloudFormation and the native OpenStack Heat Orchestration Template (HOT) format through a REST API. These flexible template languages enable application developers to describe and automate the deployment of infrastructure, services, and applications. The templates enable creation of most OpenStack resource types, such as instances, floating IP addresses, volumes, security groups, and users. Once created, the resources are referred to as stacks. The template languages are described in the `Template Guide `_. Launch a stack ~~~~~~~~~~~~~~ #. Log in to the dashboard. #. Select the appropriate project from the drop down menu at the top left. #. On the :guilabel:`Project` tab, open the :guilabel:`Orchestration` tab and click :guilabel:`Stacks` category. #. Click :guilabel:`Launch Stack`. #. In the :guilabel:`Select Template` dialog box, specify the following values: +---------------------------------------+-------------------------------+ | :guilabel:`Template Source` | Choose the source of the | | | template from the list. | +---------------------------------------+-------------------------------+ | :guilabel:`Template URL/File/Data` | Depending on the source that | | | you select, enter the URL, | | | browse to the file location, | | | or directly include the | | | template. | +---------------------------------------+-------------------------------+ | :guilabel:`Environment Source` | Choose the source of the | | | environment from the list. | | | The environment files contain | | | additional settings for the | | | stack. | +---------------------------------------+-------------------------------+ | :guilabel:`Environment File/Data` | Depending on the source that | | | you select, browse to the | | | file location, directly | | | include the environment | +---------------------------------------+-------------------------------+ #. Click :guilabel:`Next`. #. In the :guilabel:`Launch Stack` dialog box, specify the following values: +---------------------------------+---------------------------------+ | :guilabel:`Stack Name` | Enter a name to identify | | | the stack. | +---------------------------------+---------------------------------+ | :guilabel:`Creation Timeout` | Specify the number of minutes | | :guilabel:`(minutes)` | that can elapse before the | | | launch of the stack times out. | +---------------------------------+---------------------------------+ | :guilabel:`Rollback On Failure` | Select this check box if you | | | want the service to roll back | | | changes if the stack fails to | | | launch. | +---------------------------------+---------------------------------+ | :guilabel:`Password for user` | Specify the password that | | :guilabel:`"demo"` | the default user uses when the | | | stack is created. | +---------------------------------+---------------------------------+ | :guilabel:`DBUsername` | Specify the name of the | | | database user. | +---------------------------------+---------------------------------+ | :guilabel:`LinuxDistribution` | Specify the Linux distribution | | | that is used in the stack. | +---------------------------------+---------------------------------+ | :guilabel:`DBRootPassword` | Specify the root password for | | | the database. | +---------------------------------+---------------------------------+ | :guilabel:`KeyName` | Specify the name of the key pair| | | to use to log in to the stack. | +---------------------------------+---------------------------------+ | :guilabel:`DBName` | Specify the name of the | | | database. | +---------------------------------+---------------------------------+ | :guilabel:`DBPassword` | Specify the password of the | | | database. | +---------------------------------+---------------------------------+ | :guilabel:`InstanceType` | Specify the flavor for the | | | instance. | +---------------------------------+---------------------------------+ #. Click :guilabel:`Launch` to create a stack. The :guilabel:`Stacks` tab shows the stack. After the stack is created, click on the stack name to see the following details: Topology The topology of the stack. Overview The parameters and details of the stack. Resources The resources used by the stack. Events The events related to the stack. Template The template for the stack. Manage a stack ~~~~~~~~~~~~~~ #. Log in to the dashboard. #. Select the appropriate project from the drop down menu at the top left. #. On the :guilabel:`Project` tab, open the :guilabel:`Orchestration` tab and click :guilabel:`Stacks` category. #. Select the stack that you want to update. #. Click :guilabel:`Change Stack Template`. #. In the :guilabel:`Select Template` dialog box, select the new template source or environment source. #. Click :guilabel:`Next`. The :guilabel:`Update Stack Parameters` window appears. #. Enter new values for any parameters that you want to update. #. Click :guilabel:`Update`. Delete a stack ~~~~~~~~~~~~~~ When you delete a stack, you cannot undo this action. #. Log in to the dashboard. #. Select the appropriate project from the drop down menu at the top left. #. On the :guilabel:`Project` tab, open the :guilabel:`Orchestration` tab and click :guilabel:`Stacks` category. #. Select the stack that you want to delete. #. Click :guilabel:`Delete Stack`. #. In the confirmation dialog box, click :guilabel:`Delete Stack` to confirm the deletion. heat-dashboard-1.0.2/doc/source/user/template_generator.rst0000666000175100017510000000353313240544407024053 0ustar zuulzuul00000000000000====================================== Generate a Heat Orchestration Template ====================================== Heat Dashboard provides a user-friendly interface to generate Heat Orchestration templates in a Drag and Drop way. Generate a template ~~~~~~~~~~~~~~~~~~~ #. Log in to the dashboard. #. On the :guilabel:`Project` tab, open the :guilabel:`Orchestration` tab and click :guilabel:`Template Generator` category. #. Wait until the page is completely loaded. It may take several seconds. #. Click the dropdown menu of Template Version, and choose an appropriate version. #. Drag icons of resource types at the top of the page to the central canvas. #. Click icons on the canvas to specify properties of resources. #. Click EDIT button at the top of the canvas, to enable manipulate mode. #. When in manipulate mode, click on CONNECT button to add an edge between icons. #. Click edges to show details of connections. #. Click the Generate Template button at the top-right of the page and generated template will be shown in a text box. You can also add modification to the template here. #. Click CREATE STACK to jump to continue to :guilabel:`Launch Stack`. #. Click DOWNLOAD STACK to download the generated template. #. You can also click the Manage Drafts button at the top-right of the page, to temporarily save the editing canvas or to load a saved one. Currently Supported resource types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 types of resources are supported in the first release of Heat Dashboard. #. OS::Cinder::Volume #. OS::Cinder::VolumeAttachment #. OS::Heat::ResourceGroup #. OS::Neutron::FloatingIP #. OS::Neutron::FloatingIPAssociation #. OS::Neutron::Net #. OS::Neutron::Port #. OS::Neutron::Router #. OS::Neutron::RouterInterface #. OS::Neutron::SecurityGroup #. OS::Neutron::Subnet #. OS::Nova::KeyPair #. OS::Nova::Server heat-dashboard-1.0.2/.eslintignore0000666000175100017510000000012713240544407017114 0ustar zuulzuul00000000000000heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/* heat-dashboard-1.0.2/setup.cfg0000666000175100017510000000154413240545010016225 0ustar zuulzuul00000000000000[metadata] name = heat-dashboard summary = Heat Management Dashboard description-file = README.rst author = OpenStack author-email = openstack-dev@lists.openstack.org home-page = https://docs.openstack.org/heat-dashboard/latest/ classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 [files] packages = heat_dashboard [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 [upload_sphinx] upload-dir = doc/build/html [egg_info] tag_build = tag_date = 0 heat-dashboard-1.0.2/devstack/0000775000175100017510000000000013240545010016202 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/devstack/plugin.sh0000666000175100017510000000445413240544407020056 0ustar zuulzuul00000000000000# plugin.sh - DevStack plugin.sh dispatch script heat-dashboard HEAT_DASHBOARD_DIR=$(cd $(dirname $BASH_SOURCE)/.. && pwd) function install_heat_dashboard { # NOTE(shu-mutou): workaround for devstack bug: 1540328 # where devstack install 'test-requirements' but should not do it # for heat-dashboard project as it installs Horizon from url. # Remove following two 'mv' commands when mentioned bug is fixed. mv $HEAT_DASHBOARD_DIR/test-requirements.txt $HEAT_DASHBOARD_DIR/_test-requirements.txt setup_develop ${HEAT_DASHBOARD_DIR} mv $HEAT_DASHBOARD_DIR/_test-requirements.txt $HEAT_DASHBOARD_DIR/test-requirements.txt } function configure_heat_dashboard { cp -a ${HEAT_DASHBOARD_DIR}/heat_dashboard/enabled/* ${DEST}/horizon/openstack_dashboard/local/enabled/ cp -a ${HEAT_DASHBOARD_DIR}/heat_dashboard/local_settings.d/_1699_orchestration_settings.py ${DEST}/horizon/openstack_dashboard/local/local_settings.d/ cp -a ${HEAT_DASHBOARD_DIR}/heat_dashboard/conf/heat_policy.json ${DEST}/horizon/openstack_dashboard/conf/ # NOTE: If locale directory does not exist, compilemessages will fail, # so check for an existence of locale directory is required. if [ -d ${HEAT_DASHBOARD_DIR}/heat_dashboard/locale ]; then (cd ${HEAT_DASHBOARD_DIR}/heat_dashboard; DJANGO_SETTINGS_MODULE=openstack_dashboard.settings ../manage.py compilemessages) fi } # check for service enabled if is_service_enabled heat-dashboard; then if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then # Set up system services # no-op : elif [[ "$1" == "stack" && "$2" == "install" ]]; then # Perform installation of service source echo_summary "Installing Heat Dashboard" install_heat_dashboard elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then # Configure after the other layer 1 and 2 services have been configured echo_summary "Configuring Heat Dashboard" configure_heat_dashboard elif [[ "$1" == "stack" && "$2" == "extra" ]]; then # no-op : fi if [[ "$1" == "unstack" ]]; then # no-op : fi if [[ "$1" == "clean" ]]; then # Remove state and transient data # Remember clean.sh first calls unstack.sh # no-op : fi fi heat-dashboard-1.0.2/devstack/settings0000666000175100017510000000011013240544407017770 0ustar zuulzuul00000000000000# settings file for heat-dashboard plugin enable_service heat-dashboard heat-dashboard-1.0.2/package.json0000666000175100017510000000167113240544407016704 0ustar zuulzuul00000000000000{ "name": "heat-dashboard", "version": "0.0.0", "description": "OpenStack Heat Dashboard - Angular", "main": "karma.conf.js", "directories": { "doc": "doc" }, "devDependencies": { "angular-ui-router": "0.4.3", "angular-mocks": "1.5.8", "angular": "1.5.8", "jasmine": "2.8.0", "jasmine-core": "2.8.0", "karma-coverage": "1.1.1", "karma-jasmine": "1.1.0", "karma-firefox-launcher": "1.0.1", "karma-chrome-launcher": "2.2.0", "karma-ng-html2js-preprocessor": "1.0.0", "karma": "1.7.1", "eslint": "4.9.0", "eslint-plugin-angular": "3.1.1", "eslint-plugin-jasmine": "2.9.1" }, "scripts": { "test": "if [ -z $CHROME_BIN ];then export CHROME_BIN=/usr/bin/chromium-browser;fi && karma start karma.conf.js --single-run", "lint": "eslint --no-color heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/" }, "author": "", "license": "Apache-2.0" } heat-dashboard-1.0.2/.eslintrc.js0000666000175100017510000002036213240544407016653 0ustar zuulzuul00000000000000module.exports = { "env": { "browser": true, "jasmine": true, }, "plugins": ["jasmine"], "globals": { "angular": true, "module": true, "inject": true, "saveAs": true, "json2yaml": true }, "extends": ["eslint:recommended", "plugin:jasmine/recommended"], "rules": { "accessor-pairs": "error", "array-bracket-newline": "off", "array-bracket-spacing": "off", "array-callback-return": "error", "array-element-newline": "off", "arrow-body-style": "error", "arrow-parens": "error", "arrow-spacing": "error", "block-scoped-var": "off", "block-spacing": "off", "brace-style": "off", "callback-return": "off", "camelcase": "off", "capitalized-comments": "off", "class-methods-use-this": "error", "comma-dangle": "off", "comma-spacing": "off", "comma-style": "off", "complexity": "off", "computed-property-spacing": [ "error", "never" ], "consistent-return": "off", "consistent-this": "off", "curly": "off", "default-case": "off", "dot-location": [ "error", "property" ], "dot-notation": "off", "eol-last": "off", "eqeqeq": "off", "for-direction": "error", "func-call-spacing": "off", "func-name-matching": "off", "func-names": "off", "func-style": "off", "function-paren-newline": "off", "generator-star-spacing": "error", "getter-return": "error", "global-require": "error", "guard-for-in": "off", "handle-callback-err": "error", "id-blacklist": "error", "id-length": "off", "id-match": "error", "indent": "off", "indent-legacy": "off", "init-declarations": "off", "jasmine/prefer-toHaveBeenCalledWith": "off", "jsx-quotes": "error", "key-spacing": "off", "keyword-spacing": "off", "line-comment-position": "off", "linebreak-style": [ "error", "unix" ], "lines-around-comment": "off", "lines-around-directive": "off", "lines-between-class-members": "error", "max-depth": "off", "max-len": "off", "max-lines": "off", "max-nested-callbacks": "error", "max-params": "off", "max-statements": "off", "max-statements-per-line": "off", "multiline-comment-style": "off", "multiline-ternary": "off", "new-parens": "off", "newline-after-var": "off", "newline-before-return": "off", "newline-per-chained-call": "off", "no-alert": "off", "no-array-constructor": "error", "no-await-in-loop": "error", "no-bitwise": "off", "no-buffer-constructor": "error", "no-caller": "error", "no-catch-shadow": "off", "no-confusing-arrow": "error", "no-continue": "off", "no-div-regex": "error", "no-duplicate-imports": "error", "no-else-return": "off", "no-empty-function": "off", "no-eq-null": "off", "no-eval": "error", "no-extend-native": "error", "no-extra-bind": "off", "no-extra-label": "off", "no-extra-parens": "off", "no-floating-decimal": "off", "no-implicit-coercion": [ "error", { "boolean": false, "number": false, "string": false } ], "no-implicit-globals": "off", "no-implied-eval": "error", "no-inline-comments": "off", "no-inner-declarations": [ "error", "functions" ], "no-invalid-this": "off", "no-iterator": "error", "no-label-var": "error", "no-lone-blocks": "off", "no-lonely-if": "off", "no-loop-func": "off", "no-magic-numbers": "off", "no-mixed-operators": "off", "no-mixed-requires": "error", "no-multi-assign": "off", "no-multi-spaces": "off", "no-multi-str": "error", "no-multiple-empty-lines": "off", "no-native-reassign": "error", "no-negated-condition": "off", "no-negated-in-lhs": "error", "no-nested-ternary": "off", "no-new": "error", "no-new-func": "off", "no-new-object": "error", "no-new-require": "error", "no-new-wrappers": "error", "no-octal-escape": "error", "no-param-reassign": "off", "no-path-concat": "error", "no-plusplus": "off", "no-process-env": "error", "no-process-exit": "error", "no-proto": "off", "no-prototype-builtins": "off", "no-redeclare": "off", "no-restricted-globals": "error", "no-restricted-imports": "error", "no-restricted-modules": "error", "no-restricted-properties": "error", "no-restricted-syntax": "error", "no-return-assign": "off", "no-return-await": "error", "no-script-url": "error", "no-self-compare": "error", "no-sequences": "off", "no-shadow": "off", "no-shadow-restricted-names": "off", "no-spaced-func": "off", "no-sync": "error", "no-tabs": "off", "no-template-curly-in-string": "error", "no-ternary": "off", "no-throw-literal": "off", "no-trailing-spaces": [ "error", { "ignoreComments": true, "skipBlankLines": true } ], "no-undef-init": "off", "no-undefined": "off", "no-underscore-dangle": "off", "no-unmodified-loop-condition": "off", "no-unneeded-ternary": "off", "no-unused-expressions": "off", "no-unused-vars": "off", "no-use-before-define": "off", "no-useless-call": "off", "no-useless-computed-key": "error", "no-useless-concat": "off", "no-useless-constructor": "error", "no-useless-rename": "error", "no-useless-return": "off", "no-var": "off", "no-void": "off", "no-warning-comments": "off", "no-whitespace-before-property": "error", "no-with": "error", "nonblock-statement-body-position": [ "error", "any" ], "object-curly-newline": "off", "object-curly-spacing": "off", "object-property-newline": "off", "object-shorthand": "off", "one-var": "off", "one-var-declaration-per-line": "off", "operator-assignment": "off", "operator-linebreak": "off", "padded-blocks": "off", "padding-line-between-statements": "error", "prefer-arrow-callback": "off", "prefer-const": "error", "prefer-destructuring": "off", "prefer-numeric-literals": "error", "prefer-promise-reject-errors": "error", "prefer-reflect": "off", "prefer-rest-params": "off", "prefer-spread": "off", "prefer-template": "off", "quote-props": "off", "quotes": "off", "radix": "off", "require-await": "error", "require-jsdoc": "off", "rest-spread-spacing": "error", "semi": "off", "semi-spacing": "off", "semi-style": "off", "sort-imports": "error", "sort-keys": "off", "sort-vars": "off", "space-before-blocks": "off", "space-before-function-paren": "off", "space-in-parens": "off", "space-infix-ops": "off", "space-unary-ops": "off", "spaced-comment": "off", "strict": "off", "switch-colon-spacing": "off", "symbol-description": "error", "template-curly-spacing": "error", "template-tag-spacing": "error", "unicode-bom": [ "error", "never" ], "valid-jsdoc": "off", "valid-typeof": [ "error", { "requireStringLiterals": false } ], "vars-on-top": "off", "wrap-iife": "off", "wrap-regex": "off", "yield-star-spacing": "error", "yoda": "off" } }; heat-dashboard-1.0.2/MANIFEST.in0000666000175100017510000000016613240544407016152 0ustar zuulzuul00000000000000recursive-include heat_dashboard *.html *.scss *.css *.js *.map *.svg *.png *.json include AUTHORS include ChangeLog heat-dashboard-1.0.2/requirements.txt0000666000175100017510000000105513240544407017676 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. # Order matters to the pip dependency resolver, so sorting this file # changes how packages are installed. New dependencies should be # added in alphabetical order, however, some dependencies may need to # be installed in a specific order. # # PBR should always appear first pbr!=2.1.0,>=2.0.0 # Apache-2.0 python-heatclient>=1.10.0 # Apache-2.0 heat-dashboard-1.0.2/PKG-INFO0000664000175100017510000000755713240545010015511 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: heat-dashboard Version: 1.0.2 Summary: Heat Management Dashboard Home-page: https://docs.openstack.org/heat-dashboard/latest/ Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: UNKNOWN Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/heat-dashboard.svg :target: http://governance.openstack.org/reference/tags/index.html .. Change things from this point on ============== Heat Dashboard ============== Horizon plugin for Heat * License: Apache license * Source: http://git.openstack.org/cgit/openstack/heat-dashboard * Bugs: http://bugs.launchpad.net/heat-dashboard Use Heat Dashboard in DevStack ------------------------------ Set up your ``local.conf`` to enable heat-dashboard:: [[local|localrc]] enable_plugin heat-dashboard https://git.openstack.org/openstack/heat-dashboard .. note:: You also need to install Heat itself into DevStack to use Heat Dashboard. Manual Installation ------------------- Clone both Horizon and Heat Dashboard repositories:: git clone https://github.com/openstack/horizon git clone https://github.com/openstack/heat-dashboard Create a virtual environment and install Horizon relevant packages:: pip install -r horizon/requirements.txt Create your ``local_settings.py`` file:: cp horizon/openstack_dashboard/local/local_settings.py.example \ horizon/openstack_dashboard/local/local_settings.py Open newly created ``local_settings.py`` with your text editor, and set some parameter to connect to your OpenStack environment: - Set ``OPENSTACK_HOST`` as hostname or IP address of your OpenStack server. - Verify that the ``OPENSTACK_KEYSTONE_URL`` and ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your environment. (They should be correct unless you modified your OpenStack server to change them.) Install Heat Dashboard with all relevant packages to your Horizon environment:: pip install -e ./heat-dashboard/ Enable heat-dashboard plugin in your Horizon environment:: cp heat-dashboard/heat_dashboard/enabled/* \ horizon/openstack_dashboard/local/enabled cp heat-dashboard/heat_dashboard/conf/* \ horizon/openstack_dashboard/conf/ cp heat-dashboard/heat_dashboard/local_settings.d/* \ horizon/openstack_dashboard/local/local_settings.d/ Finally you can launch Horizon with Heat Dashboard plugin:: cd horizon python manage.py runserver 0.0.0.0:8080 Now you can connect to your Horizon including Heat Dashboard plugin from your browser with URL http://localhost:8080/. Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 heat-dashboard-1.0.2/manage.py0000777000175100017510000000147613240544407016226 0ustar zuulzuul00000000000000#!/usr/bin/env python # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os import sys from django.core.management import execute_from_command_line if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "heat_dashboard.test.settings") execute_from_command_line(sys.argv) heat-dashboard-1.0.2/heat_dashboard.egg-info/0000775000175100017510000000000013240545010021020 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard.egg-info/dependency_links.txt0000664000175100017510000000000113240545005025072 0ustar zuulzuul00000000000000 heat-dashboard-1.0.2/heat_dashboard.egg-info/PKG-INFO0000664000175100017510000000755713240545005022137 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: heat-dashboard Version: 1.0.2 Summary: Heat Management Dashboard Home-page: https://docs.openstack.org/heat-dashboard/latest/ Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: UNKNOWN Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/heat-dashboard.svg :target: http://governance.openstack.org/reference/tags/index.html .. Change things from this point on ============== Heat Dashboard ============== Horizon plugin for Heat * License: Apache license * Source: http://git.openstack.org/cgit/openstack/heat-dashboard * Bugs: http://bugs.launchpad.net/heat-dashboard Use Heat Dashboard in DevStack ------------------------------ Set up your ``local.conf`` to enable heat-dashboard:: [[local|localrc]] enable_plugin heat-dashboard https://git.openstack.org/openstack/heat-dashboard .. note:: You also need to install Heat itself into DevStack to use Heat Dashboard. Manual Installation ------------------- Clone both Horizon and Heat Dashboard repositories:: git clone https://github.com/openstack/horizon git clone https://github.com/openstack/heat-dashboard Create a virtual environment and install Horizon relevant packages:: pip install -r horizon/requirements.txt Create your ``local_settings.py`` file:: cp horizon/openstack_dashboard/local/local_settings.py.example \ horizon/openstack_dashboard/local/local_settings.py Open newly created ``local_settings.py`` with your text editor, and set some parameter to connect to your OpenStack environment: - Set ``OPENSTACK_HOST`` as hostname or IP address of your OpenStack server. - Verify that the ``OPENSTACK_KEYSTONE_URL`` and ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your environment. (They should be correct unless you modified your OpenStack server to change them.) Install Heat Dashboard with all relevant packages to your Horizon environment:: pip install -e ./heat-dashboard/ Enable heat-dashboard plugin in your Horizon environment:: cp heat-dashboard/heat_dashboard/enabled/* \ horizon/openstack_dashboard/local/enabled cp heat-dashboard/heat_dashboard/conf/* \ horizon/openstack_dashboard/conf/ cp heat-dashboard/heat_dashboard/local_settings.d/* \ horizon/openstack_dashboard/local/local_settings.d/ Finally you can launch Horizon with Heat Dashboard plugin:: cd horizon python manage.py runserver 0.0.0.0:8080 Now you can connect to your Horizon including Heat Dashboard plugin from your browser with URL http://localhost:8080/. Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 heat-dashboard-1.0.2/heat_dashboard.egg-info/requires.txt0000664000175100017510000000005513240545005023424 0ustar zuulzuul00000000000000pbr!=2.1.0,>=2.0.0 python-heatclient>=1.10.0 heat-dashboard-1.0.2/heat_dashboard.egg-info/SOURCES.txt0000664000175100017510000012356313240545010022716 0ustar zuulzuul00000000000000.eslintignore .eslintrc.js .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE MANIFEST.in README.rst babel-django.cfg babel-djangojs.cfg karma.conf.js manage.py package.json requirements.txt setup.cfg setup.py test-requirements.txt tox.ini devstack/plugin.sh devstack/settings doc/requirements.txt doc/source/conf.py doc/source/index.rst doc/source/readme.rst doc/source/configuration/configuration.rst doc/source/configuration/index.rst doc/source/contributor/contributing.rst doc/source/contributor/index.rst doc/source/install/index.rst doc/source/install/installation.rst doc/source/install/installation_contents.rst doc/source/install/uninstallation.rst doc/source/user/index.rst doc/source/user/stacks.rst doc/source/user/template_generator.rst heat_dashboard/__init__.py heat_dashboard/exceptions.py heat_dashboard.egg-info/PKG-INFO heat_dashboard.egg-info/SOURCES.txt heat_dashboard.egg-info/dependency_links.txt heat_dashboard.egg-info/not-zip-safe heat_dashboard.egg-info/pbr.json heat_dashboard.egg-info/requires.txt heat_dashboard.egg-info/top_level.txt heat_dashboard/api/__init__.py heat_dashboard/api/heat.py heat_dashboard/api/rest/__init__.py heat_dashboard/api/rest/heat.py heat_dashboard/conf/heat_policy.json heat_dashboard/content/__init__.py heat_dashboard/content/resource_types/__init__.py heat_dashboard/content/resource_types/panel.py heat_dashboard/content/resource_types/tables.py heat_dashboard/content/resource_types/tabs.py heat_dashboard/content/resource_types/urls.py heat_dashboard/content/resource_types/views.py heat_dashboard/content/resource_types/templates/resource_types/_details.html heat_dashboard/content/resource_types/templates/stacks.resource_types/_details.html heat_dashboard/content/stacks/__init__.py heat_dashboard/content/stacks/api.py heat_dashboard/content/stacks/forms.py heat_dashboard/content/stacks/mappings.py heat_dashboard/content/stacks/panel.py heat_dashboard/content/stacks/sro.py heat_dashboard/content/stacks/tables.py heat_dashboard/content/stacks/tabs.py heat_dashboard/content/stacks/urls.py heat_dashboard/content/stacks/views.py heat_dashboard/content/stacks/templates/stacks/_change_template.html heat_dashboard/content/stacks/templates/stacks/_create.html heat_dashboard/content/stacks/templates/stacks/_detail_events.html heat_dashboard/content/stacks/templates/stacks/_detail_overview.html heat_dashboard/content/stacks/templates/stacks/_detail_resources.html heat_dashboard/content/stacks/templates/stacks/_detail_topology.html heat_dashboard/content/stacks/templates/stacks/_preview.html heat_dashboard/content/stacks/templates/stacks/_preview_details.html heat_dashboard/content/stacks/templates/stacks/_preview_template.html heat_dashboard/content/stacks/templates/stacks/_resource_info.html heat_dashboard/content/stacks/templates/stacks/_resource_overview.html heat_dashboard/content/stacks/templates/stacks/_select_template.html heat_dashboard/content/stacks/templates/stacks/_stack_info.html heat_dashboard/content/stacks/templates/stacks/_stack_template.html heat_dashboard/content/stacks/templates/stacks/_update.html heat_dashboard/content/stacks/templates/stacks/change_template.html heat_dashboard/content/stacks/templates/stacks/create.html heat_dashboard/content/stacks/templates/stacks/index.html heat_dashboard/content/stacks/templates/stacks/preview.html heat_dashboard/content/stacks/templates/stacks/preview_details.html heat_dashboard/content/stacks/templates/stacks/preview_template.html heat_dashboard/content/stacks/templates/stacks/select_template.html heat_dashboard/content/stacks/templates/stacks/update.html heat_dashboard/content/template_generator/__init__.py heat_dashboard/content/template_generator/api.py heat_dashboard/content/template_generator/panel.py heat_dashboard/content/template_generator/urls.py heat_dashboard/content/template_generator/views.py heat_dashboard/content/template_generator/templates/template_generator/index.html heat_dashboard/content/template_versions/__init__.py heat_dashboard/content/template_versions/panel.py heat_dashboard/content/template_versions/tables.py heat_dashboard/content/template_versions/tabs.py heat_dashboard/content/template_versions/urls.py heat_dashboard/content/template_versions/views.py heat_dashboard/content/template_versions/templates/stacks.template_versions/_details.html heat_dashboard/content/template_versions/templates/stacks.template_versions/index.html heat_dashboard/content/template_versions/templates/template_versions/_details.html heat_dashboard/content/template_versions/templates/template_versions/index.html heat_dashboard/enabled/_1610_project_orchestration_panel.py heat_dashboard/enabled/_1620_project_stacks_panel.py heat_dashboard/enabled/_1630_project_resource_types_panel.py heat_dashboard/enabled/_1640_project_template_versions_panel.py heat_dashboard/enabled/_1650_project_template_generator_panel.py heat_dashboard/enabled/__init__.py heat_dashboard/local_settings.d/_1699_orchestration_settings.py heat_dashboard/local_settings.d/__init__.py heat_dashboard/locale/cs/LC_MESSAGES/django.po heat_dashboard/locale/de/LC_MESSAGES/django.po heat_dashboard/locale/de/LC_MESSAGES/djangojs.po heat_dashboard/locale/en_AU/LC_MESSAGES/django.po heat_dashboard/locale/en_GB/LC_MESSAGES/django.po heat_dashboard/locale/en_GB/LC_MESSAGES/djangojs.po heat_dashboard/locale/es/LC_MESSAGES/django.po heat_dashboard/locale/fr/LC_MESSAGES/django.po heat_dashboard/locale/id/LC_MESSAGES/django.po heat_dashboard/locale/id/LC_MESSAGES/djangojs.po heat_dashboard/locale/it/LC_MESSAGES/django.po heat_dashboard/locale/ja/LC_MESSAGES/django.po heat_dashboard/locale/ja/LC_MESSAGES/djangojs.po heat_dashboard/locale/ko_KR/LC_MESSAGES/django.po heat_dashboard/locale/ko_KR/LC_MESSAGES/djangojs.po heat_dashboard/locale/pl_PL/LC_MESSAGES/django.po heat_dashboard/locale/pt/LC_MESSAGES/djangojs.po heat_dashboard/locale/pt_BR/LC_MESSAGES/django.po heat_dashboard/locale/pt_BR/LC_MESSAGES/djangojs.po heat_dashboard/locale/ru/LC_MESSAGES/django.po heat_dashboard/locale/tr_TR/LC_MESSAGES/django.po heat_dashboard/locale/zh_CN/LC_MESSAGES/django.po heat_dashboard/locale/zh_CN/LC_MESSAGES/djangojs.po heat_dashboard/locale/zh_TW/LC_MESSAGES/django.po heat_dashboard/static/dashboard/project/heat_dashboard/img/alarm-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/alarm-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/alarm-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/alarm-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/apple-touch-icon.png heat_dashboard/static/dashboard/project/heat_dashboard/img/config-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/config-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/config-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/config-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/db-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/db-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/db-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/db-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/drag.png heat_dashboard/static/dashboard/project/heat_dashboard/img/favicon.ico heat_dashboard/static/dashboard/project/heat_dashboard/img/firewall-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/firewall-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/firewall-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/firewall-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/flavor-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/flavor-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/flavor-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/flavor-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/floatingip-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/floatingip-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/floatingip-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/floatingip-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/image-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/image-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/image-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/image-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/keypair-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/keypair-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/keypair-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/keypair-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/lb-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/lb-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/lb-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/lb-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/logo-splash.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/logo.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/network-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/network-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/network-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/network-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/policy-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/policy-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/policy-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/policy-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/port-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/port-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/port-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/port-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/router-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/router-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/router-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/router-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/safari-pinned-tab.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/securitygroup-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/securitygroup-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/securitygroup-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/securitygroup-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/server-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/server-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/server-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/server-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/spinner.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/stack-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/stack-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/stack-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/stack-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/unknown-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/unknown-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/unknown-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/unknown-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/volume-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/volume-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/volume-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/volume-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/vpn-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/vpn-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/vpn-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/vpn.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/wait-gray.gif heat_dashboard/static/dashboard/project/heat_dashboard/img/wait-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/wait-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/img/wait-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/angular-material.min.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/angular-notify.min.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/bootstrap.css.map heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/bootstrap.min.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/bootstrap.min.css.map heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/hotgen.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/vis.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/HELP-US-OUT.txt heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/css/font-awesome.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/css/font-awesome.min.css heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/fonts/FontAwesome.otf heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/fonts/fontawesome-webfont.eot heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/fonts/fontawesome-webfont.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/animated.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/bordered-pulled.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/core.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/fixed-width.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/font-awesome.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/icons.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/larger.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/list.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/mixins.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/path.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/rotated-flipped.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/screen-reader.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/stacked.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/less/variables.less heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_animated.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_bordered-pulled.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_core.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_fixed-width.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_icons.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_larger.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_list.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_mixins.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_path.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_rotated-flipped.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_screen-reader.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_stacked.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/_variables.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/font-awesome-4.7.0/scss/font-awesome.scss heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/file-text-o.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/floppy-o.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/ic_close_24px.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/ic_help_outline_24px.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/spinner.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/trash.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/unknown-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/unknown-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/unknown-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/unknown.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/acceptDeleteIcon.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/addNodeIcon.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/backIcon.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/connectIcon.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/cross.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/cross2.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/deleteIcon.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/downArrow.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/editIcon.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/leftArrow.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/minus.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/plus.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/rightArrow.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/upArrow.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/network/zoomExtends.png heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/compile.directive.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/compile.directive.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/dependson.directive.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/dependson.directive.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/globals.service.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/globals.service.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/template-generator.module.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/template-generator.module.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingassociation.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-blue.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-gray.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-green.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-red.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.spec.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.svg heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/FileSaver.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-animate.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-animate.min.js.map heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-aria.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-aria.min.js.map heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-material.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-messages.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-messages.min.js.map heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-notify.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-sanitize.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-sanitize.min.js.map heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-uuid.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-vis.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/js-yaml.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/json2yaml.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/ui-bootstrap-tpls-2.5.0.min.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/vis.js heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/depends_on.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_draft.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_edge.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_resource.html heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_template.html heat_dashboard/test/__init__.py heat_dashboard/test/helpers.py heat_dashboard/test/settings.py heat_dashboard/test/test_data/__init__.py heat_dashboard/test/test_data/cinder_data.py heat_dashboard/test/test_data/exceptions.py heat_dashboard/test/test_data/glance_data.py heat_dashboard/test/test_data/heat_data.py heat_dashboard/test/test_data/keystone_data.py heat_dashboard/test/test_data/neutron_data.py heat_dashboard/test/test_data/nova_data.py heat_dashboard/test/test_data/utils.py heat_dashboard/test/tests/__init__.py heat_dashboard/test/tests/api/__init__.py heat_dashboard/test/tests/api/heat_rest_tests.py heat_dashboard/test/tests/api/heat_tests.py heat_dashboard/test/tests/content/__init__.py heat_dashboard/test/tests/content/test_resource_types.py heat_dashboard/test/tests/content/test_stacks.py heat_dashboard/test/tests/content/test_template_generator.py heat_dashboard/test/tests/content/test_template_versions.py releasenotes/notes/.placeholder releasenotes/notes/split-out-from-horizon-1d1eabed58eb885e.yaml releasenotes/notes/template-generator-panel-decc3ec172bfa1dd.yaml releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po releasenotes/source/locale/id/LC_MESSAGES/releasenotes.po releasenotes/source/locale/ja/LC_MESSAGES/releasenotes.po releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po releasenotes/source/locale/pt_BR/LC_MESSAGES/releasenotes.po tools/tox_install.shheat-dashboard-1.0.2/heat_dashboard.egg-info/not-zip-safe0000664000175100017510000000000113240544730023256 0ustar zuulzuul00000000000000 heat-dashboard-1.0.2/heat_dashboard.egg-info/pbr.json0000664000175100017510000000005613240545005022503 0ustar zuulzuul00000000000000{"git_version": "56e3c1f", "is_release": true}heat-dashboard-1.0.2/heat_dashboard.egg-info/top_level.txt0000664000175100017510000000001713240545005023554 0ustar zuulzuul00000000000000heat_dashboard heat-dashboard-1.0.2/CONTRIBUTING.rst0000666000175100017510000000121613240544407017052 0ustar zuulzuul00000000000000If you would like to contribute to the development of OpenStack, you must follow the steps in this page: http://docs.openstack.org/infra/manual/developers.html If you already have a good understanding of how the system works and your OpenStack accounts are set up, you can skip to the development workflow section of this documentation to learn how changes to OpenStack should be submitted for review via the Gerrit tool: http://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/../horizon heat-dashboard-1.0.2/HACKING.rst0000666000175100017510000000023713240544407016211 0ustar zuulzuul00000000000000openstack Style Commandments =============================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ heat-dashboard-1.0.2/tools/0000775000175100017510000000000013240545010015536 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/tools/tox_install.sh0000777000175100017510000000366113240544407020456 0ustar zuulzuul00000000000000#!/usr/bin/env bash # Many of horizon's repos suffer from the problem of depending on horizon, # but it not existing on pypi. # This wrapper for tox's package installer will use the existing package # if it exists, else use zuul-cloner if that program exists, else grab it # from horizon master via a hard-coded URL. That last case should only # happen with devs running unit tests locally. # From the tox.ini config page: # install_command=ARGV # default: # pip install {opts} {packages} ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner BRANCH_NAME=master GIT_BASE=${GIT_BASE:-https://git.openstack.org/} install_project() { local project=$1 local branch=${2:-$BRANCH_NAME} local module_name=${project//-/_} set +e project_installed=$(echo "import $module_name" | python 2>/dev/null ; echo $?) set -e if [ $project_installed -eq 0 ]; then echo "ALREADY INSTALLED" > /tmp/tox_install.txt echo "$project already installed; using existing package" elif [ -x "$ZUUL_CLONER" ]; then echo "ZUUL CLONER" > /tmp/tox_install.txt # Make this relative to current working directory so that # git clean can remove it. We cannot remove the directory directly # since it is referenced after $install_cmd -e mkdir -p .tmp PROJECT_DIR=$(/bin/mktemp -d -p $(pwd)/.tmp) pushd $PROJECT_DIR $ZUUL_CLONER --cache-dir \ /opt/git \ --branch $branch \ http://git.openstack.org \ openstack/$project cd openstack/$project $install_cmd -e . popd else echo "PIP HARDCODE" > /tmp/tox_install.txt local GIT_REPO="$GIT_BASE/openstack/$project" SRC_DIR="$VIRTUAL_ENV/src/$project" git clone --depth 1 --branch $branch $GIT_REPO $SRC_DIR $install_cmd -U -e $SRC_DIR fi } set -e install_cmd="pip install -c$1" shift install_project horizon $install_cmd -U $* exit $? heat-dashboard-1.0.2/releasenotes/0000775000175100017510000000000013240545010017067 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/0000775000175100017510000000000013240545010020367 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/unreleased.rst0000666000175100017510000000016013240544407023260 0ustar zuulzuul00000000000000============================== Current Series Release Notes ============================== .. release-notes:: heat-dashboard-1.0.2/releasenotes/source/_templates/0000775000175100017510000000000013240545010022524 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/_templates/.placeholder0000666000175100017510000000000013240544407025010 0ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/index.rst0000666000175100017510000000020413240544407022237 0ustar zuulzuul00000000000000============================ Heat Dashboard Release Notes ============================ .. toctree:: :maxdepth: 1 unreleased heat-dashboard-1.0.2/releasenotes/source/locale/0000775000175100017510000000000013240545010021626 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/id/0000775000175100017510000000000013240545010022222 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/id/LC_MESSAGES/0000775000175100017510000000000013240545010024007 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/id/LC_MESSAGES/releasenotes.po0000666000175100017510000000416513240544407027061 0ustar zuulzuul00000000000000# suhartono , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: Heat Dashboard Release Notes\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-12-13 07:43+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-12-15 07:30+0000\n" "Last-Translator: suhartono \n" "Language-Team: Indonesian\n" "Language: id\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A panel for ``Template Generator`` is newly added. There is not specific " "installation process. After installing heat-dashboard, this panel will be " "displayed along with ``Stacks``, ``Resource Types`` and ``Template " "Versions``." msgstr "" "Panel untuk ``Template Generator`` baru saja ditambahkan. Tidak ada proses " "instalasi yang spesifik. Setelah memasang heat-dashboard, panel ini akan " "ditampilkan bersama dengan ``Stacks``, ``Resource Types`` dan ``Template " "Versions``." msgid "Current Series Release Notes" msgstr "Catatan rilis seri saat ini" msgid "Heat Dashboard Release Notes" msgstr "Catatan Rilis Heat Dashboard" msgid "" "Heat support in OpenStack Dashboard is now split into a separated python " "package." msgstr "" "Dukungan Heat di OpenStack Dashboard kini terbagi menjadi paket python " "terpisah." msgid "" "Heat support in OpenStack Dashboard is now split into a separete package " "``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading " "OpenStack Dashboard to Queens release and add ``enabled`` file for Heat " "Dashboard. For detail information, see https://docs.openstack.org/heat-" "dashboard/latest/." msgstr "" "Dukungan Heat di OpenStack Dashboard sekarang terbagi menjadi paket terpisah " "``heat-dashboard``. Anda perlu menginstal ``heat-dashboard`` setelah " "mengupgrade Dashboard OpenStack ke rilis Queens dan menambahkan file " "``enabled`` untuk Heat Dashboard. Untuk informasi lebih detail, lihat " "https://docs.openstack.org/heat-dashboard/latest/." msgid "New Features" msgstr "Fitur baru" msgid "Prelude" msgstr "Prelude" heat-dashboard-1.0.2/releasenotes/source/locale/en_GB/0000775000175100017510000000000013240545010022600 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000013240545010024365 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000666000175100017510000000415213240544407027433 0ustar zuulzuul00000000000000# Andi Chandler , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: Heat Dashboard Release Notes\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-12-13 07:43+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-12-13 09:30+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en-GB\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A panel for ``Template Generator`` is newly added. There is not specific " "installation process. After installing heat-dashboard, this panel will be " "displayed along with ``Stacks``, ``Resource Types`` and ``Template " "Versions``." msgstr "" "A panel for ``Template Generator`` is newly added. There is not specific " "installation process. After installing heat-dashboard, this panel will be " "displayed along with ``Stacks``, ``Resource Types`` and ``Template " "Versions``." msgid "Current Series Release Notes" msgstr "Current Series Release Notes" msgid "Heat Dashboard Release Notes" msgstr "Heat Dashboard Release Notes" msgid "" "Heat support in OpenStack Dashboard is now split into a separated python " "package." msgstr "" "Heat support in OpenStack Dashboard is now split into a separated python " "package." msgid "" "Heat support in OpenStack Dashboard is now split into a separete package " "``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading " "OpenStack Dashboard to Queens release and add ``enabled`` file for Heat " "Dashboard. For detail information, see https://docs.openstack.org/heat-" "dashboard/latest/." msgstr "" "Heat support in OpenStack Dashboard is now split into a separate package " "``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading " "OpenStack Dashboard to Queens release and add ``enabled`` file for Heat " "Dashboard. For detail information, see https://docs.openstack.org/heat-" "dashboard/latest/." msgid "New Features" msgstr "New Features" msgid "Prelude" msgstr "Prelude" heat-dashboard-1.0.2/releasenotes/source/locale/ja/0000775000175100017510000000000013240545010022220 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/ja/LC_MESSAGES/0000775000175100017510000000000013240545010024005 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/ja/LC_MESSAGES/releasenotes.po0000666000175100017510000000457713240544407027066 0ustar zuulzuul00000000000000# Yuko Katabami , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: Heat Dashboard Release Notes\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-02-09 08:43+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-02-09 10:14+0000\n" "Last-Translator: Yuko Katabami \n" "Language-Team: Japanese\n" "Language: ja\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A panel for ``Template Generator`` is newly added. There is not specific " "installation process. After installing heat-dashboard, this panel will be " "displayed along with ``Stacks``, ``Resource Types`` and ``Template " "Versions``." msgstr "" "「テンプレートジェãƒãƒ¬ãƒ¼ã‚¿ãƒ¼ã€ç”¨ã®ãƒ‘ãƒãƒ«ãŒæ–°ãŸã«è¿½åŠ ã•れã¾ã—ãŸã€‚特定ã®ã‚¤ãƒ³ã‚¹" "トールプロセスã¯ã‚りã¾ã›ã‚“。heat-dashboard ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«å¾Œã«ã¯ã€ã€Œã‚¹ã‚¿ãƒƒã‚¯ã€" "「リソース種別ã€ã€Œãƒ†ãƒ³ãƒ—レートãƒãƒ¼ã‚¸ãƒ§ãƒ³ã€ã¨ã¨ã‚‚ã«è¡¨ç¤ºã•れã¾ã™ã€‚" msgid "Current Series Release Notes" msgstr "開発中ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒªãƒªãƒ¼ã‚¹ãƒŽãƒ¼ãƒˆ" msgid "Heat Dashboard Release Notes" msgstr "Heat Dashboard リリースノート" msgid "" "Heat support in OpenStack Dashboard is now split into a separated python " "package." msgstr "" "OpenStack Dashboard ã«ãŠã‘ã‚‹ Heat ã®ã‚µãƒãƒ¼ãƒˆã¯ã€åˆ¥ã® python パッケージã«åˆ†é›¢" "ã•れã¾ã—ãŸã€‚" msgid "" "Heat support in OpenStack Dashboard is now split into a separete package " "``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading " "OpenStack Dashboard to Queens release and add ``enabled`` file for Heat " "Dashboard. For detail information, see https://docs.openstack.org/heat-" "dashboard/latest/." msgstr "" "OpenStack Dashboard ã«ãŠã‘ã‚‹ Heat ã®ã‚µãƒãƒ¼ãƒˆã¯ã€ã€Œheat-dashboardã€ã¨ã„ã†åˆ¥ã®" "パッケージã«åˆ†é›¢ã•れã¾ã—ãŸã€‚OpenStack Dashboard ã‚’ Queens リリースã«ã‚¢ãƒƒãƒ—ã‚°" "レードã—ãŸå¾Œã«ã€Œheat-dashboardã€ã‚’インストールã—ã¦ã€Heat Dashboard ã‚’" "「enabledã€ãƒ•ァイルを追加ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚詳細ã«ã¤ã„ã¦ã¯ã€https://docs." "openstack.org/heat-dashboard/latest/ ã‚’å‚ç…§ã—ã¦ãã ã•ã„。" msgid "New Features" msgstr "新機能" msgid "Prelude" msgstr "å‰ç½®ã" heat-dashboard-1.0.2/releasenotes/source/locale/pt_BR/0000775000175100017510000000000013240545010022634 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/pt_BR/LC_MESSAGES/0000775000175100017510000000000013240545010024421 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/pt_BR/LC_MESSAGES/releasenotes.po0000666000175100017510000000434013240544407027466 0ustar zuulzuul00000000000000# Rodrigo Loures , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: Heat Dashboard Release Notes\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-01-23 06:37+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-01-23 10:02+0000\n" "Last-Translator: Rodrigo Loures \n" "Language-Team: Portuguese (Brazil)\n" "Language: pt-BR\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A panel for ``Template Generator`` is newly added. There is not specific " "installation process. After installing heat-dashboard, this panel will be " "displayed along with ``Stacks``, ``Resource Types`` and ``Template " "Versions``." msgstr "" "Um painel para ``Template Generator`` está recentemente adicionado. Não há " "um processo de instalação específico. Depois de instalar heat-dashboard, " "esse painel será exibido juntamente com ``Stacks``, ``Resource Types`` e " "``Template Versions``." msgid "Current Series Release Notes" msgstr "Atual - Séries de Notas de Versão" msgid "Heat Dashboard Release Notes" msgstr "Heat Dashboard - Notas de Versão" msgid "" "Heat support in OpenStack Dashboard is now split into a separated python " "package." msgstr "" "O suporte do Heat no dashboard do Openstack agora está dividido em um " "pacote de Pyton separado." msgid "" "Heat support in OpenStack Dashboard is now split into a separete package " "``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading " "OpenStack Dashboard to Queens release and add ``enabled`` file for Heat " "Dashboard. For detail information, see https://docs.openstack.org/heat-" "dashboard/latest/." msgstr "" "O suporte do Heat no dashboard do Openstack agora está dividido em um pacote " "de Pyton separado ``heat-dashboard``. Você precisa instalar ``heat-" "dashboard`` depois atualizar o dashboard do OpenStack para a versão Queens e " "adicione ``enabled`` arquivo para o dashboard do Heat. Para mais informações " "acesse https://docs.openstack.org/heat-dashboard/latest/." msgid "New Features" msgstr "Novos Recursos" msgid "Prelude" msgstr "Prelúdio" heat-dashboard-1.0.2/releasenotes/source/locale/ko_KR/0000775000175100017510000000000013240545010022633 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/ko_KR/LC_MESSAGES/0000775000175100017510000000000013240545010024420 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po0000666000175100017510000000467613240544407027501 0ustar zuulzuul00000000000000# ByungYeol Woo , 2017. #zanata # Sungjin Kang , 2017. #zanata # johjuhyun , 2017. #zanata # minwook-shin , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: Heat Dashboard Release Notes\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-12-15 19:14+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-12-27 02:31+0000\n" "Last-Translator: ByungYeol Woo \n" "Language-Team: Korean (South Korea)\n" "Language: ko-KR\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A panel for ``Template Generator`` is newly added. There is not specific " "installation process. After installing heat-dashboard, this panel will be " "displayed along with ``Stacks``, ``Resource Types`` and ``Template " "Versions``." msgstr "" "``Template Generator``를 위한 패ë„ì´ ìƒˆë¡­ê²Œ 추가ë˜ì—ˆìŠµë‹ˆë‹¤. 특정한 설치 절차" "ê°€ 없습니다. heat 대시보드가 ì„¤ì¹˜ëœ ë‹¤ìŒ, ì´ íŒ¨ë„ì€ ``Stacks``, ``Resource " "Types``, ``Template Versions``ì— ë”°ë¼ì„œ 표시ë©ë‹ˆë‹¤." msgid "Current Series Release Notes" msgstr "최신 ì‹œë¦¬ì¦ˆì— ëŒ€í•œ 릴리즈 노트" msgid "Heat Dashboard Release Notes" msgstr "Heat 대시보드 릴리즈 노트" msgid "" "Heat support in OpenStack Dashboard is now split into a separated python " "package." msgstr "" "ì˜¤í”ˆìŠ¤íƒ ëŒ€ì‹œë³´ë“œì—서 ì§€ì›í•˜ëŠ” Heat는 현재 별ë„ì˜ íŒŒì´ì¬ 패키지로 나누어져 있" "습니다." msgid "" "Heat support in OpenStack Dashboard is now split into a separete package " "``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading " "OpenStack Dashboard to Queens release and add ``enabled`` file for Heat " "Dashboard. For detail information, see https://docs.openstack.org/heat-" "dashboard/latest/." msgstr "" "ì˜¤í”ˆìŠ¤íƒ ëŒ€ì‹œë³´ë“œì—서 ì§€ì›í•˜ëŠ” Heat는 현재 ``heat-dashboard``ë¼ëŠ” ë³„ê°œì˜ íŒ¨í‚¤" "지로 나뉘어 있습니다. ì˜¤í”ˆìŠ¤íƒ ëŒ€ì‹œë³´ë“œë¥¼ Queens 릴리즈로 업그레ì´ë“œí•œ ë‹¤ìŒ " "``heat-dashboard``를 설치하고 Head ëŒ€ì‹œë³´ë“œì— ``enabled`` 파ì¼ì„ 추가할 í•„ìš”" "ê°€ 있습니다. ìžì„¸í•œ ì‚¬í•­ì€ https://docs.openstack.org/heat-dashboard/" "latest/ 를 참조하세요." msgid "New Features" msgstr "새로운 기능" msgid "Prelude" msgstr "서문" heat-dashboard-1.0.2/releasenotes/source/_static/0000775000175100017510000000000013240545010022015 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/_static/.placeholder0000666000175100017510000000000013240544407024301 0ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/source/conf.py0000666000175100017510000002141513240544407021704 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'openstackdocstheme', 'reno.sphinxext', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Heat Dashboard Release Notes' copyright = u'2017, OpenStack Foundation' # openstackdocstheme options repository_name = 'openstack/heat-dashboard' bug_project = 'heat-dashboard' bug_tag = 'doc' html_last_updated_fmt = '%Y-%m-%d %H:%M' # Release notes are version independent, no need to set version and release release = '' version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'HeatDashboardReleaseNotesdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'HeatDashboardReleaseNotes.tex', u'Heat Dashboard Release Notes Documentation', u'OpenStack Foundation', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'HeatDashboardReleaseNotes', u'Heat Dashboard Release Notes Documentation', [u'OpenStack Foundation'], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'HeatDashboardReleaseNotes', u'Heat Dashboard Release Notes Documentation', u'OpenStack Foundation', 'HeatDashboardReleaseNotes', 'Dashboard for Heat', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] heat-dashboard-1.0.2/releasenotes/notes/0000775000175100017510000000000013240545010020217 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/notes/.placeholder0000666000175100017510000000000013240544407022503 0ustar zuulzuul00000000000000heat-dashboard-1.0.2/releasenotes/notes/template-generator-panel-decc3ec172bfa1dd.yaml0000666000175100017510000000041013240544407030570 0ustar zuulzuul00000000000000--- features: - | A panel for ``Template Generator`` is newly added. There is not specific installation process. After installing heat-dashboard, this panel will be displayed along with ``Stacks``, ``Resource Types`` and ``Template Versions``. heat-dashboard-1.0.2/releasenotes/notes/split-out-from-horizon-1d1eabed58eb885e.yaml0000666000175100017510000000070713240544407030153 0ustar zuulzuul00000000000000--- prelude: > Heat support in OpenStack Dashboard is now split into a separated python package. features: - | Heat support in OpenStack Dashboard is now split into a separete package ``heat-dashboard``. You need to install ``heat-dashboard`` after upgrading OpenStack Dashboard to Queens release and add ``enabled`` file for Heat Dashboard. For detail information, see https://docs.openstack.org/heat-dashboard/latest/. heat-dashboard-1.0.2/tox.ini0000666000175100017510000000600613240544407015726 0ustar zuulzuul00000000000000[tox] envlist = py27dj18,py27dj19,py27dj110,py27dj111,py35dj18,py35dj19,py35dj110,py35dj111,pep8,releasenotes minversion = 2.3.2 skipsdist = True [testenv] usedevelop = True install_command = {toxinidir}/tools/tox_install.sh \ {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} \ {opts} {packages} setenv = VIRTUAL_ENV={envdir} INTEGRATION_TESTS=0 NOSE_WITH_OPENSTACK=1 NOSE_OPENSTACK_COLOR=1 NOSE_OPENSTACK_RED=0.05 NOSE_OPENSTACK_YELLOW=0.025 NOSE_OPENSTACK_SHOW_ELAPSED=1 deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = py27: {[unit_tests]commands} py35: {[unit_tests]commands} [unit_tests] commands = python manage.py test heat_dashboard.test --settings=heat_dashboard.test.settings [testenv:pep8] commands = flake8 {posargs} [testenv:venv] commands = {posargs} [testenv:cover] commands = coverage erase coverage run --source=heat_dashboard {toxinidir}/manage.py test heat_dashboard.test.tests --settings=heat_dashboard.test.settings {posargs} coverage xml coverage html [testenv:py27dj18] basepython = python2.7 commands = pip install django>=1.8,<1.9 {[unit_tests]commands} [testenv:py27dj19] basepython = python2.7 commands = pip install django>=1.9,<1.10 {[unit_tests]commands} [testenv:py27dj110] basepython = python2.7 commands = pip install django>=1.10,<1.11 {[unit_tests]commands} [testenv:py27dj111] basepython = python2.7 commands = pip install django>=1.11,<2.0 {[unit_tests]commands} [testenv:py35] basepython = python3.5 commands = {[unit_tests]commands} [testenv:py35dj18] basepython = python3.5 commands = pip install django>=1.8,<1.9 {[unit_tests]commands} [testenv:py35dj19] basepython = python3.5 commands = pip install django>=1.9,<1.10 {[unit_tests]commands} [testenv:py35dj110] basepython = python3.5 commands = pip install django>=1.10,<1.11 {[unit_tests]commands} [testenv:py35dj111] basepython = python3.5 commands = pip install django>=1.11,<2.0 {[unit_tests]commands} [testenv:docs] deps = -r{toxinidir}/doc/requirements.txt commands = python setup.py build_sphinx [testenv:releasenotes] deps = -r{toxinidir}/doc/requirements.txt commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html [hacking] local-check-factory = horizon.hacking.checks.factory [flake8] exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules,.tmp max-complexity = 20 import-order-style = pep8 [testenv:npm] passenv = HOME DISPLAY commands = nodeenv -p npm install npm run {posargs:test} [doc8] # File extensions to check extensions = .rst, .yaml # Maximal line length should be 80 but we have some overlong lines. # Let's not get far more in. max-line-length = 80 # Disable some doc8 checks: # D000: Check RST validity # - cannot handle "none" for code-block directive ignore = D000 heat-dashboard-1.0.2/babel-django.cfg0000666000175100017510000000021013240544407017370 0ustar zuulzuul00000000000000[extractors] django = django_babel.extract:extract_django [python: **.py] [django: **/templates/**.html] [django: **/templates/**.csv] heat-dashboard-1.0.2/test-requirements.txt0000666000175100017510000000202413240544407020650 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. # Order matters to the pip dependency resolver, so sorting this file # changes how packages are installed. New dependencies should be # added in alphabetical order, however, some dependencies may need to # be installed in a specific order. # # Hacking should appear first in case something else depends on pep8 hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 # coverage!=4.4,>=4.0 # Apache-2.0 django-nose>=1.4.4 # BSD doc8>=0.6.0 # Apache-2.0 flake8-import-order==0.12 # LGPLv3 mock>=2.0.0 # BSD mox3>=0.20.0 # Apache-2.0 nodeenv>=0.9.4 # BSD nose>=1.3.7 # LGPL nose-exclude>=0.3.0 # LGPL nosehtmloutput>=0.0.3 # Apache-2.0 nosexcover>=1.0.10 # BSD openstack.nose-plugin>=0.7 # Apache-2.0 testtools>=2.2.0 # MIT # This also needs xvfb library installed on your OS http://tarballs.openstack.org/horizon/horizon-master.tar.gz#egg=horizon heat-dashboard-1.0.2/setup.py0000666000175100017510000000200613240544407016121 0ustar zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) heat-dashboard-1.0.2/ChangeLog0000664000175100017510000005461713240545005016171 0ustar zuulzuul00000000000000CHANGES ======= 1.0.2 ----- * Imported Translations from Zanata * Revert "Drop django <= 1.10 support" * Imported Translations from Zanata * Drop django <= 1.10 support * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Delete hard-coding lines of locale * Imported Translations from Zanata * i18n: Annotate template generator django template properly * Correct django template pattern in babel-django.cfg * Correct security group pull down option * Imported Translations from Zanata * fix error url * Imported Translations from Zanata * Zuul: Remove project name 1.0.1 ----- * Change location of conf files in README * Fix file path typo in devstack/plugin.sh * Ensure json files are provided in the package * Imported Translations from Zanata * Optimise how to retrieve pull-down options * Include policy in tree for ease of deployment * Imported Translations from Zanata * Updated from global requirements * Modify select/change template modal description * Updated from global requirements * Create doc/requirements.txt * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Update the home page 1.0.0 ----- * fix typo in releasenote * Added leftover change in horizon * comment out logging configuration for heatclient * Update plugin.sh to resolve a couple of issues * Fix nova server networks config options * Add user doc of template generator * Deleted locale dir & Updated babel-django.cfg * Split out heat own items from Horizon settings * Migrate Heat relevant docs to Heat Dashboard * Remove unnecessary \`$locationProvider\` settings * Change rewriteLinks to false * Align tox\_install.sh with other projects * Fix mistake in devstack installation procedure * Partially Revert "Updated release note toward Queens release." * Updated release note toward Queens release * Fix installation procedure for heat\_policy.json according to Horizon team's advice * Change page header name to Template Generator * Submit generated template file directly * Added procedure to enable heat\_policy.json * Remove test.py * Fix installation procedure due to lack of process * Remove setting of version/release from releasenotes * Updated from global requirements * Taken over policy file for heat from Horizon repository * In future, Horizon team is planning to remove heat relevant logic like, - Heat GUI part - API wrapper client - API rest endpoint creator (like api/rest/heat) * Updated from global requirements * Add resources svg to heat-dashboard * Consume horizon in-tree django variant jobs * Modify Neutron Router modal * Clean up npm package dependencies * Add in repo zuul job definition * Add initial files as devstack settings/documents/requirements * Add unittests for template generator angular * add docs * add release notes * fix tox.ini * add initial files * update files by working files * add template generator * move files * move all files under heat\_dashboard directory * flake8-import-order: Ensure to place project imports last * Make nosehtmloutput an optional test requirement * Add exceptions for action * Added SELECTABLE\_THEMES setting * Use doc8 check * Fix py27dj18 definition * Add '\*.pyc' clean up for unit\_tests * Add Django 1.11 tox env * Use flake8-import-order plugin * doc: cleanup formatting * Horizon Forms should allow themable number spinners * Split out FWaaS dashboard * Split out VPNaaS dashboard * test helper: Ensure to populate JS\_CATALOG in context * Add instance locked status on instances table * HTML test report only when nosehtmloutput is installed * Adds basic angular QoS panel to Horizon * Fix H405 (multi line docstring) warnings (openstack\_dashboard) * hacking: Specify white list rules in noqa explicity * New readonly panel for trunks * Enable some off-by-default hacking rules * Generate unit test HTML reports * Testing: mock add\_panel\_mocks() more flexible * Allow Chrome to start when tox is running npm * Delete instance,volume,etc confirmation is missing name or ID * Update the access\_and\_security url * Handle log message interpolation by the logger * Remove py34 in tox.ini * Drop py34 target in tox.ini * Remove all remaining vendor specific code * hacking: noqa cleanup in openstack\_dashboard * hacking: Drop import\_exceptions from tox.ini * Make extract\_messages quiet in pep8 test * Use ThemableSelectWidget for themable * Correct error in policy action name * Replace six.iteritems/itervalues with dict.items()/values() * Refactor Project Volumes stand-alone panel * Use more specific asserts in tests * Use "Default", "Value" and "DefaultValue" for Heat parameters * Pass environment variables of proxy to tox * Fake deprecated nova client properties * Add default common template to python table views * Adding identity ng-roles panel * Remove duplicated modal\_header statements * Revert "Add policy rules to project panels" * Add policy rules to project panels * Replace six.iteritems(iter) with iter.items() * Fixes inconsistency in Stacks filter label * Wrap api calls with tracing decorators * Add the Profiler panel to the Developer dashboard * Refactor tox & update docs * Remove local/enabled from test settings * Removing deprecate ceilometer code * Removing deprecated Swift UI code * Drop LBaaS v1 dashboard * Server-side filtering Orchestration * Flavors panel can switch to Angular * add ploop type to the list of image backends * Fix logspam in django 1.9 and django 1.10 tests * Make ResourceTypesTests skippable * Using /tmp for SECRET\_KEY in tests * Fix tox cover to not fail * Turn on docs warning check in document generation * Move Developer enabled/ files to contrib * Fix compatibility issues with Django 1.10 * Support for Glance v2 * Remove the lowercase case boolean type in heat param\_type * Enable Python 3.5 testing and fix tests * Fix error detection in horizon test suite * Hard-code stubbed novaclient api\_version to 2.1 * [TrivialFix] Ignore node\_modules while we run flake8 test * Use upper constraints for all jobs in tox.ini * Add filter action to Template Versions tables * Re-work static\_settings to clean up * Remove Orchestration Resource Types names restriction * Add ANGULAR\_FEATURES setting dict * Restrict user private network cidr input * Remove openstack/common from the exclude list of flake8 in tox * Make 'switch' between legacy and Angular Images * Update Django 1.10 tox env * Remove multi select option on Resource types table * Embed support for external data sinks into api.glance * Delete the useless API of heat * Pre-populate the Angular template cache and allow template overrides * Enable tox to run the subset test cases * Do not import local/enabled when to run test * Add Django 1.10 tox env * Escape angularjs templating in unsafe HTML * Fix coverage post job * Updating heat policy file * Implement video capture for failed tests * Handle non ASCII tenant names gracefully when downloading RC file * Use upper-constraints in tox test environments * Whitelist 'rm' in pep8 tox environment * Refactor Orchectration Stacks menu * Update tox.ini for pot files not in tree * [Trivial] Wrong policy for Heat resource type details * Heat Template Versions panel * removing httplib2 test dependency * Add filter function on resource type table * Enhances tox to not rely on run\_tests * Fix remaining Django 1.9 test failures * Pass environment data to update stack action * Remove PYTHONHASHSEED=0 from tox * Make no response notification(msg) level to INFO * Update URLs to Django 1.8+ style * Add "data\_required=True" check into heat rest api * Make ngcontainers the default Swift UI * Branding: Workflow cancel btn should be themable * Horizon support for Heat template versions * Fixing heatclient release compat issues * Add Swift REST API * Add some new heat-snapshot-api * Port last unit tests to Python 3 * Switch to use "# noqa" correctly * Port identity provider dashboard to Python 3 * Follow-up patch of bug: #1527457 * Port dashboard containers to Python 3 * [Django 1.9] Stop using django.utils.importlib * [Django 1.9] Remove testserver from expected\_url * Remove all pre-Django 1.8 workarounds * Add support for identity provider management * [Django 1.9] Replace django.utils.unittest * Port volume backup dashboard to Python 3 * Port loadbalancers tests to Python 3 * Modify 'admin' used by fixed string * Fixed the width of the stack template detail box * Add py27dj19 tox env * Delete some deprecated codes * Correcting heat resource drill down * Use new log style when LOG.error * Make it possible to pick False for default stack parameter value * Add handle get\_file when launch stack from horizon * Eliminate mutable default arguments * Add API services for system information * Add missing unit tests for Heat Stacks Details * Deprecated tox -downloadcache option removed * Delete the unused LOG configure code * Fixes heat templates hidden parameters are not loading problem * Add Developer Dashboard + Bootstrap Theme Preview * Fix errors showing in Network tests * Excising Sahara from Horizon * Force releasenotes warnings to be treated as errors * Make unit testing less reliant on HTML fragments * Adding download for openrc file for keystone v3 * Add version check for listing namespaces * Drop Django 1.7 support * Add reno for release notes management * Add breadcrumb to more details pages * Fix Python 3 issues in dashboard image tests * Port network topology tests to Python 3 * Port dashboard stack tests to Python 3 * Port dashboard router tests on Python 3 * Port project instance tests to Python 3 * tox: add /bin/bash to whitelist\_externals * py3: Fix unicode versus bytes issues * Adds config to disable the password in stack * Wrong url in stack preview detail page * In Stack Details do not display as links events leading to nowhere * Port admin metering tests to Python 3 * py3: Replace unicode with six.text\_type * Replace filter() with list-comprehension * Port remaining Horizon tests for Python 3 * py3: Add json attribute to HTTP response objects * Heat Stacks Details: Events table doesn't show up * Port horizon tabs tests to Python 3 * Port babel\_extract\_angular tests to Python 3 * Add missing MEDIA config in test settings * Fix Python 3 issue in horizon DataTable * Add icons for Heat Stacks BatchActions * Port openstack dashboard overview tests to Python 3 * Port horizon utils tests to Python 3 * Pass Heat environment through form variables too * Improving find static robustness * TestCase: add aliases to assert methods on py3 * Port horizon base tests to Python 3 * Replace SortedDict with OrderedDict * Port dashboard api access tests to Python 3 * Port password tests to Python 3 * Port horizon forms tests to Python 3 * Port error\_pages tests to Python 3 * Port config\_rest\_tests to Python 3 * Run a subset of tests on Python 3 * py3: Replace unicode with six.text\_type * Javascript Heat API * A few fixes to make the App Catalog plugin work * py3: replace reload with six.moves.reload\_module * py3: Replace basestring with six.string\_types * Fixes Selenium tests for openstack\_dashboard * remove django<1.7 from tests * Moving Trove to contrib * Move Horizon to pure plugin loading only * Fix the misspell Ochestration to Orchestration * Remove Router Dashboard * Fix static file paths in heat topology view * Use relative imports * Moving Sahara to contrib * Replace mox with mox3 * Removed JSHint * Switched from JSCS to ESLint * Turning off offline compression for integration test * Removing unnecessary test setting of dashboards * Escape the description param from heat template * Inherit environment variables for tests that use nodeenv * Heat topology display improvement * Establish baseline JSCS configuration * Fix addition of plugin panel to panel group * Fix addition of plugin panel to panel group * [Heat] Resource url mapping improvement * [Launch Instance Fix] Settings for volume name * Revert "Refactoring the exceptions lists" * Refactoring the exceptions lists * [Heat] Fix default values displaying for "Launch Stack" * Fixing changing WEBROOT from / * Use novaclient v2 instead v1\_1 * Heat resource url mapping improvement * Clean modal forms in Orchestration Stacks * Add "Preview Stack" action to Stacks table * Always show stack status reason in topology * Base dashboard Jasmine framework * REST API to support create instance angular (Neutron) * Adding policy rest endpoint for angular * Generate a drop down field for custom heat parameters * Refactor REST API tests for common code patterns * Add orchestration service status reporting * Read access to config via REST * Make the values of Stack Resource status be translatable * Network Rest API for Angular Front End * Cinder REST API for angular front end * Nova REST API for angular front end * Glance Rest API for Angular Front End * Reduce page title duplication in Stacks * Add missing stubs to project stacks tests * Reduced code duplication in creating page headers * Stack resources table improvement * made stack status value is translatable * Move to hacking 0.10 * Make params order fixed in stack forms * Remove unused import urlencode * Make test helpers properly inheritable/extendable * Fixes Resource id mapping with Heat Resources * added filter for stacks table * Add missing OS::Cinder::Volume resource url map * Updating stack resource urls mapping * Heat stack status column improvement * Correcting heat resource page title * Add "Suspend" and "Resume" actions to Stacks table * Resource types table improvement * Keystone REST API for angular front end * Add "Check Stack" action to Stacks table * Orchestration Resource types panel * Unify the syntax used for the {% ... %} delimter in Jinja2 templates * Switch from oslo.utils to oslo\_utils * we don't need to allow insecure any more * REST API for angular front end * Fixed display issues on Details Page caused by bootstrap 3 update * Clean up terminal output for stack details section * Documenting create\_stubs decorator for tests * Fixes Inconsistent usage of Detail / Details * Fixed row deletion for deleted stack * Split large methods into submethods to reduce max-complexity * Create titles without concatenation * Remove Python 2.6 classifier * Stack update call needs password * place the word "Info" with "Information" * 'Stack Template' tab for Heat Stack Details page * Move the panel mocks to a separate method on TestCase * Hide the "Host Aggregates" admin panel if not enabled * Add max-complexity to pep8 for Horizon * Do not log keystone token * Fix E128 errors in remaining openstack\_dashboard/ * Fix E128 errors in openstack\_dashboard/dashboards/project/ * Fix E127 errors in remaining openstack\_dashboard/ * Use strutils from oslo.utils * Fix E127 errors in openstack\_dashboard/dashboards/project/ * Add check for makemessages in tox.ini PEP8 * fixed errors when run\_tests.sh --makemessages * Revert file permissions changed unexpectedly * display boolean and json parameters in stack launch form * Add ':' inside translatable (Part 2 of 2) * Add dropdown actions to all details pages * Workaround for 'File exists' test failure * Remove #noqa from django.conf.urls.include * Fix concatenation in more misc actions * Reuse API client object in a request * Remove #noqa from two common imports and add them to import\_exceptions * swift: Respect the OPENSTACK\_SSL\_NO\_VERIFY setting * Enable flavors metadata update * Use integer instead of string for form max\_length * render stack parameters in the correct order * Allow translators to translate BatchActions * Add templates for bootstrap's horizontal forms * Work toward Python 3.4 support and testing * Render hidden stack parameters with a password field * Display Network panels based on neutron ext-list * Fix order of arguments in assertEqual * Add a config option to disable Router panel * Improve help messages on modals * Horizon changes for DVR * Domain Role assignment to Users * Exclude .ropeproject from flake8 checks * show correct link to compute instances in stack resource overview tab * Separating Identity Dashboard and using RBAC * Remove "builtins = \_" from tox.ini * Run the integration tests headlessly * Replace force\_unicode with force\_text * add Previous link to Project > Stacks table * Delete Stacks button doesn't work * Set python hash seed to 0 in tox.ini * Fix and enable H701 check "Empty localization string" * Fix and enable H702 \_() method check * Re-enable flake8 check * Fix Flake8 style warnings in openstack\_dashboard/ * Update Twitter Bootstrap to version 3 * Cleanup for Horizon fields * Run router dashboard unit tests by default * Fixing subproject test runs * Remove requirements style check * Fix multiple Cross-Site Scripting (XSS) vulnerabilities * Adding support for volume backups * Adding plugins panel for Sahara * Add jshint for javascript linting * Fix keystone warnings while building docs * Ensuring environment data is passed to heat template validate * Use six.add\_metaclass instead of \_\_metaclass\_\_ * Incorrect config item in local\_settings.py.example * Allow extensions to add Angular modules * replace dict.iteritems() with six.iteritems(dict) * Show default text for image format * Remove extraneous vim configuration comments * Added the field label to the field arguments * Use the latest Django 1.4 release to test Horizon * Fix formatting of heat exceptions * Fix tox does not pass arguments to nose * Introduces escaping in Horizon/Orchestration * Add tox env to build docs * Add pagination to stack list * Add logging handler for openstack\_auth in the tests * Plugin-based panel group configuration * Enable settings/change password on keystone v3 * Handle "null" time values for Stacks * Use built-in print() instead of print statement * Fix wrong links to volume detail * Fix project name in the table for Cisco N1K profiles * Remove I18N strings from test/settings.py * Adding django 1.6 support * Updated outdated docstring, fixed typo/space * Adding resource link to resource detail page in Heat view * Additional optional Environment data to heat template selection * Fixing heat stack status column * Heat Stack update view/form * Add flavor extra spec key templates * Sort requirement files in alphabetical order * Integration tests - running the tests * Use six.moves.urllib.parse instead of urlparse * Exclude local directory from flake8 tests * Replace assertEqual(None, \*) with assertIsNone in tests * Adding policy checks for heat * Fixing tests to work with keystoneclient 0.6.0 * Fix missing option in the test settings.py file * Remove delete action and bar when stack is DELETE\_COMPLETE * Fix misspellings in horizon * Remove leftovers of "# noqa" * Sync OPENSTACK\_KEYSTONE\_DEFAULT\_ROLE with keystone * Adding management\_url to test mock client * Passing stack\_id argument to get\_data view * Replace asserts in \_\_init\_\_ files with \_\_all\_\_ * Remove #noqa from most common imports and add them to import\_exceptions * Whitelist external netaddr requirement * Use memoized\_method decorator in views * Updates tox.ini to use new features * Extend options for custom flavor sorting when launching instances * Allow translators to control word order of BatchAction message * Common keystone version fallback * Set can\_set\_mount\_point default to False * Plugin-based dashboard configuration * Update troveclient to 1.0.0 * Heat Stack name is missing form validation * Gate on H4xx docstrings for pep8 * Fix "it's vs. its" typos * Gate on H102 Apache 2.0 license header not found for pep8 * Importing from trove-client compat first * Add option to disable server password fields * Add logging configuration for iso8601 module * Importing from trove-client compat * Fix django.conf.urls.defaults imports * Ignore irrelevant secgroup form field errors * Run flake8 tests automatically on ./run\_tests.sh * Disable H803 check * Remove unused LOG * Convert generator to list in Heat list API call * PEP8 E126 has been resolved * Make troveclient optional * FWaaS Horizon panel * Enable F403 and F999 check * VPNaaS UI implementation * Remove test string from translation files * PEP8 E121 has been resolved * Add Cisco N1K plugin support in Horizon * Make Image Service image formats configurable * Custom CA certificate for verifying SSL connections * Adding panels for trove * Remove encryption option for volumes * Add ceilometer api and the tests for it * Rename heat logical\_resource\_id to resource\_name * Adding RBAC policy system and checks for identity * Show Neutron floating IPs quotas on Overview * Small "H302 check" cleanup * Enable H302 check * Enable H201: do not write "except:" * Fix stack status displaying * Updated from global requirements * Updates Topology to correctly handle resources in the INIT state * Ensure the user monkey patching is done for the API tests * Add support for parsing jsonfied heat error * remove 'import \*' usage (or mark is #noqa) * Removed a comment from tox.ini that no longer applied * Enable pep8 F841 checking * Fixing the AJAX function location * Adding Heat Resource Topology to Horizon * Enable H304 check * Prompt for password on stack create * Adding the ability to set/use domain context * update Quantum references to Neutron * Implementation of a Heat stacks UI * Enable H306 check * Mock some more keystoneclient.Client properties for mox * Fix Further Pyflakes warnings * Enable hacking H101 test * python3: Introduce py33 to tox.ini * Manually mock service\_catalog in stub\_keystoneclient * Sort imports alphabetically * remove unused imports * Add HACKING.rst * Enable most of the pyflakes checks * Add security group rule templates * New tox environment for testing with Django 1.4 * Renames tools/pip-requires to requirements.txt * Group CRUD and Management in Admin Dashboard * Adding CRUD for roles * Adding Domain CRUD in Admin Dashboard * Preparing for Heat tests * Access to heat API via python-heatclient * Move to flake8 * Update Horizon for Django 1.5 compatibility * blueprint quantum-lbaas * Correctly mock keystoneclient.Client.auto\_token property with Mox * Added encryption support for volumes * Resolve API import issues (quantum) * Implements ability to upload local image to glance * Adds API Access information to Access & Security panel * Properly enable/disable project/user edit via setting * Quantum Floating IP support * Ensure to use api.. * Avoid cinder calls, when cinder is unavailable * Fixes for missing files in MANIFEST * Unifies Horizon conf * Client-side validation of password/confirmation match * Allow running tests individually * Enable quota data from multiple sources * Splits OpenStack Dashboard bits from framework app code * Provide utilities to automate secure secret key generation * Add ProjectTestingInterface to horizon * Revamp of testing machinery heat-dashboard-1.0.2/README.rst0000666000175100017510000000457413240544407016112 0ustar zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/heat-dashboard.svg :target: http://governance.openstack.org/reference/tags/index.html .. Change things from this point on ============== Heat Dashboard ============== Horizon plugin for Heat * License: Apache license * Source: http://git.openstack.org/cgit/openstack/heat-dashboard * Bugs: http://bugs.launchpad.net/heat-dashboard Use Heat Dashboard in DevStack ------------------------------ Set up your ``local.conf`` to enable heat-dashboard:: [[local|localrc]] enable_plugin heat-dashboard https://git.openstack.org/openstack/heat-dashboard .. note:: You also need to install Heat itself into DevStack to use Heat Dashboard. Manual Installation ------------------- Clone both Horizon and Heat Dashboard repositories:: git clone https://github.com/openstack/horizon git clone https://github.com/openstack/heat-dashboard Create a virtual environment and install Horizon relevant packages:: pip install -r horizon/requirements.txt Create your ``local_settings.py`` file:: cp horizon/openstack_dashboard/local/local_settings.py.example \ horizon/openstack_dashboard/local/local_settings.py Open newly created ``local_settings.py`` with your text editor, and set some parameter to connect to your OpenStack environment: - Set ``OPENSTACK_HOST`` as hostname or IP address of your OpenStack server. - Verify that the ``OPENSTACK_KEYSTONE_URL`` and ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your environment. (They should be correct unless you modified your OpenStack server to change them.) Install Heat Dashboard with all relevant packages to your Horizon environment:: pip install -e ./heat-dashboard/ Enable heat-dashboard plugin in your Horizon environment:: cp heat-dashboard/heat_dashboard/enabled/* \ horizon/openstack_dashboard/local/enabled cp heat-dashboard/heat_dashboard/conf/* \ horizon/openstack_dashboard/conf/ cp heat-dashboard/heat_dashboard/local_settings.d/* \ horizon/openstack_dashboard/local/local_settings.d/ Finally you can launch Horizon with Heat Dashboard plugin:: cd horizon python manage.py runserver 0.0.0.0:8080 Now you can connect to your Horizon including Heat Dashboard plugin from your browser with URL http://localhost:8080/. heat-dashboard-1.0.2/AUTHORS0000664000175100017510000001420213240545005015451 0ustar zuulzuul00000000000000Aaron Sahlin Abishek Subramanian Akihiro MOTOKI Akihiro Motoki Akihiro Motoki Alex Gaynor Ana Krivokapic Ana Malagon Andreas Jaeger Andrew Lazarev Antoine Abélard Ashish Chandra AvnishPal Beth Elwell Bo Wang Brianna Poulos Béla Vancsics Cady_Chen Chad Roberts ChenZheng Christian Berendt Chuck Short Cindy Lu Cody A.W. Somerville CristianFiorentino David Lyle David Lyle David Lyle Diana Clarke Diana Whitten Dirk Mueller Doug Fish Eddie Ramirez Felipe Reyes Fengqian Gao Gabriel Hurley Gary W. Smith George Peristerakis Gloria Gu Gábor Antal He Yongli Itxaka Ivan Kolodyazhny Jack Choy James E. Blair James E. Blair Janet Yu Jason E. Rist Jasper Capel Jean-Philippe Evrard Jeremy Stanley JiaHao Li Jianing YANG Jiri Tomasek Joe Gordon Jordan OMara Julie Pichon Julien Danjou Justin Pomeroy KC Wang KC Wang Kahou Lei Kanagaraj Manickam Kazunori Shinohara Keiichi Hikita Kenji Ishii Kevin Fox Kieran Spear Kun Huang Kun Huang LIU Yulong LIU-Yulong Ladislav Smola Lajos Katona Laura Frank Leandro I. Costantino Lin Hua Cheng LiuNanke Lucas Palm Mark McClain Masco Kaliyamoorthy Matt Borland Matt Borland Matt Riedemann Matthias Runge Maxim Nestratov Maxime Vidori Michael Dovgal Michael Krotscheck Michal Dulko Miguel Grinberg Mike Hagedorn Monty Taylor Nathan Reller Omri Gazitt OndÅ™ej Nový Paul Belanger Paul Karikh Peter Belanyi Radomir Dopieralski Rajat Vig Ramaraja Revon Mathews Richard Jones Rob Cresswell Rob Raymond Robert Myers Roman Rader Russell Sim Sam Betts Samantha Blanco Saro Chandra Bhooshan Sascha Peilicke Sascha Peilicke Sean Dague Sergei Chipiga Sergey Lukjanov Shane Wang Steve Baker Steve Leon Steve McLellan Sushil Kumar Tatiana Mazur Tatiana Ovchinnikova Thai Tran Thomas Bechtold Thomas Goirand Tim Schnell Timur Sufiev Travis Tripp Tyr Johanson Vic Howard Victor Stinner Vlad Okhrimenko Wu Wenxiang Xinni Ge Ying Zuo Yves-Gwenael Bourhis Zhenguo Niu Zuul absubram chen.qiaomin@99cloud.net dixiaoli eric jing.liuqing jlopezgu jolie kaz_shinohara kenji-ishii lawrancejing lin-hua-cheng lin-hua-cheng lingyongxu liyingjun lvxianguo nikunj2512 ricolin root shizhihui simon tianliang wangbo wei.ying xurong00037997 yaraat zhang.lei zhaozhilong zhu.rong zhurong heat-dashboard-1.0.2/babel-djangojs.cfg0000666000175100017510000000110113240544407017725 0ustar zuulzuul00000000000000[extractors] # We use a custom extractor to find translatable strings in AngularJS # templates. The extractor is included in horizon.utils for now. # See http://babel.pocoo.org/docs/messages/#referencing-extraction-methods for # details on how this works. angular = horizon.utils.babel_extract_angular:extract_angular [javascript: **.js] # We need to look into all static folders for HTML files. # The **/static ensures that we also search within # /openstack_dashboard/dashboards/XYZ/static which will ensure # that plugins are also translated. [angular: **/static/**.html] heat-dashboard-1.0.2/.zuul.yaml0000666000175100017510000000321413240544407016352 0ustar zuulzuul00000000000000- project: check: jobs: - horizon-openstack-tox-py27dj18: irrelevant-files: - ^.*\.rst$ - ^doc/.*$ - ^heat_dashboard/locale/.*$ - ^releasenotes/.*$ required-projects: - openstack/horizon - horizon-openstack-tox-py27dj19: irrelevant-files: - ^.*\.rst$ - ^doc/.*$ - ^heat_dashboard/locale/.*$ - ^releasenotes/.*$ required-projects: - openstack/horizon - horizon-openstack-tox-py27dj110: irrelevant-files: - ^.*\.rst$ - ^doc/.*$ - ^heat_dashboard/locale/.*$ - ^releasenotes/.*$ required-projects: - openstack/horizon gate: queue: heat-dashboard jobs: - horizon-openstack-tox-py27dj18: irrelevant-files: - ^.*\.rst$ - ^doc/.*$ - ^heat_dashboard/locale/.*$ - ^releasenotes/.*$ required-projects: - openstack/horizon - horizon-openstack-tox-py27dj19: irrelevant-files: - ^.*\.rst$ - ^doc/.*$ - ^heat_dashboard/locale/.*$ - ^releasenotes/.*$ required-projects: - openstack/horizon - horizon-openstack-tox-py27dj110: irrelevant-files: - ^.*\.rst$ - ^doc/.*$ - ^heat_dashboard/locale/.*$ - ^releasenotes/.*$ required-projects: - openstack/horizon heat-dashboard-1.0.2/LICENSE0000666000175100017510000002363713240544407015431 0ustar zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. heat-dashboard-1.0.2/karma.conf.js0000666000175100017510000000776513240544407017005 0ustar zuulzuul00000000000000// Karma configuration // Generated on Fri Oct 06 2017 11:56:14 GMT+0900 (JST) module.exports = function(config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['jasmine'], // list of files / patterns to load in the browser files: [ 'node_modules/angular/angular.min.js', 'node_modules/angular-ui-router/release/angular-ui-router.min.js', 'node_modules/angular-mocks/angular-mocks.js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/*.js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/*.module.js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/!(*.spec|*.module).js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/*.spec.js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/!(*.spec).js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/*.spec.js', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/*.html', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/*.html', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/*.svg', ], // list of files to exclude exclude: [ ], // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/!(*.spec).js': 'coverage', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/!(*.spec).js': 'coverage', 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/*.html': ['ng-html2js'], 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/*.html': ['ng-html2js'], 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/*.svg': ['ng-html2js'], }, ngHtml2JsPreprocessor: { // stripPrefix: './heat_dashboard/static/', // prependPrefix: 'undefined', cacheIdFromPath: function(filepath) { var cacheId; if (filepath.indexOf('.svg') != -1){ cacheId = filepath.replace('heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/', '{$ basePath $}'); } else if (filepath.indexOf('.html') != -1){ cacheId = filepath.replace('heat_dashboard/static/', 'undefined'); } console.log(filepath) return cacheId; }, moduleName: 'appTemplates', }, // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter reporters: ['progress', 'coverage'], // web server port port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes autoWatch: true, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: ['Chrome', ], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: false, // Concurrency level // how many browser should be started simultaneous concurrency: Infinity }) } heat-dashboard-1.0.2/heat_dashboard/0000775000175100017510000000000013240545010017326 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/conf/0000775000175100017510000000000013240545010020253 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/conf/heat_policy.json0000666000175100017510000001070013240544407023457 0ustar zuulzuul00000000000000{ "context_is_admin": "role:admin", "deny_stack_user": "not role:heat_stack_user", "deny_everybody": "!", "cloudformation:ListStacks": "rule:deny_stack_user", "cloudformation:CreateStack": "rule:deny_stack_user", "cloudformation:DescribeStacks": "rule:deny_stack_user", "cloudformation:DeleteStack": "rule:deny_stack_user", "cloudformation:UpdateStack": "rule:deny_stack_user", "cloudformation:CancelUpdateStack": "rule:deny_stack_user", "cloudformation:DescribeStackEvents": "rule:deny_stack_user", "cloudformation:ValidateTemplate": "rule:deny_stack_user", "cloudformation:GetTemplate": "rule:deny_stack_user", "cloudformation:EstimateTemplateCost": "rule:deny_stack_user", "cloudformation:DescribeStackResource": "", "cloudformation:DescribeStackResources": "rule:deny_stack_user", "cloudformation:ListStackResources": "rule:deny_stack_user", "cloudwatch:DeleteAlarms": "rule:deny_stack_user", "cloudwatch:DescribeAlarmHistory": "rule:deny_stack_user", "cloudwatch:DescribeAlarms": "rule:deny_stack_user", "cloudwatch:DescribeAlarmsForMetric": "rule:deny_stack_user", "cloudwatch:DisableAlarmActions": "rule:deny_stack_user", "cloudwatch:EnableAlarmActions": "rule:deny_stack_user", "cloudwatch:GetMetricStatistics": "rule:deny_stack_user", "cloudwatch:ListMetrics": "rule:deny_stack_user", "cloudwatch:PutMetricAlarm": "rule:deny_stack_user", "cloudwatch:PutMetricData": "", "cloudwatch:SetAlarmState": "rule:deny_stack_user", "actions:action": "rule:deny_stack_user", "build_info:build_info": "rule:deny_stack_user", "events:index": "rule:deny_stack_user", "events:show": "rule:deny_stack_user", "resource:index": "rule:deny_stack_user", "resource:metadata": "", "resource:signal": "", "resource:mark_unhealthy": "rule:deny_stack_user", "resource:show": "rule:deny_stack_user", "stacks:abandon": "rule:deny_stack_user", "stacks:create": "rule:deny_stack_user", "stacks:delete": "rule:deny_stack_user", "stacks:detail": "rule:deny_stack_user", "stacks:export": "rule:deny_stack_user", "stacks:generate_template": "rule:deny_stack_user", "stacks:global_index": "rule:deny_everybody", "stacks:index": "rule:deny_stack_user", "stacks:list_resource_types": "rule:deny_stack_user", "stacks:list_template_versions": "rule:deny_stack_user", "stacks:list_template_functions": "rule:deny_stack_user", "stacks:lookup": "", "stacks:preview": "rule:deny_stack_user", "stacks:resource_schema": "rule:deny_stack_user", "stacks:show": "rule:deny_stack_user", "stacks:template": "rule:deny_stack_user", "stacks:environment": "rule:deny_stack_user", "stacks:update": "rule:deny_stack_user", "stacks:update_patch": "rule:deny_stack_user", "stacks:preview_update": "rule:deny_stack_user", "stacks:preview_update_patch": "rule:deny_stack_user", "stacks:validate_template": "rule:deny_stack_user", "stacks:snapshot": "rule:deny_stack_user", "stacks:show_snapshot": "rule:deny_stack_user", "stacks:delete_snapshot": "rule:deny_stack_user", "stacks:list_snapshots": "rule:deny_stack_user", "stacks:restore_snapshot": "rule:deny_stack_user", "stacks:list_outputs": "rule:deny_stack_user", "stacks:show_output": "rule:deny_stack_user", "software_configs:global_index": "rule:deny_everybody", "software_configs:index": "rule:deny_stack_user", "software_configs:create": "rule:deny_stack_user", "software_configs:show": "rule:deny_stack_user", "software_configs:delete": "rule:deny_stack_user", "software_deployments:index": "rule:deny_stack_user", "software_deployments:create": "rule:deny_stack_user", "software_deployments:show": "rule:deny_stack_user", "software_deployments:update": "rule:deny_stack_user", "software_deployments:delete": "rule:deny_stack_user", "software_deployments:metadata": "", "service:index": "rule:context_is_admin", "resource_types:OS::Nova::Flavor": "rule:context_is_admin", "resource_types:OS::Cinder::EncryptedVolumeType": "rule:context_is_admin", "resource_types:OS::Cinder::VolumeType": "rule:context_is_admin", "resource_types:OS::Manila::ShareType": "rule:context_is_admin", "resource_types:OS::Neutron::QoSPolicy": "rule:context_is_admin", "resource_types:OS::Neutron::QoSBandwidthLimitRule": "rule:context_is_admin", "resource_types:OS::Nova::HostAggregate": "rule:context_is_admin" } heat-dashboard-1.0.2/heat_dashboard/test/0000775000175100017510000000000013240545010020305 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/settings.py0000666000175100017510000000240113240544407022527 0ustar zuulzuul00000000000000# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # Default to Horizons test settings to avoid any missing keys import heat_dashboard.enabled from openstack_dashboard.test.settings import * # noqa: F403,H303 from openstack_dashboard.utils import settings # pop these keys to avoid log warnings about deprecation # update_dashboards will populate them anyway HORIZON_CONFIG.pop('dashboards', None) HORIZON_CONFIG.pop('default_dashboard', None) # Update the dashboards with heat_dashboard enabled files # and current INSTALLED_APPS settings.update_dashboards( [ openstack_dashboard.enabled, heat_dashboard.enabled, ], HORIZON_CONFIG, INSTALLED_APPS ) # Remove duplicated apps INSTALLED_APPS = list(set(INSTALLED_APPS)) heat-dashboard-1.0.2/heat_dashboard/test/tests/0000775000175100017510000000000013240545010021447 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/tests/content/0000775000175100017510000000000013240545010023121 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/tests/content/test_stacks.py0000666000175100017510000012447013240544407026045 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json import re import django from django.conf import settings from django.core import exceptions from django.core.urlresolvers import reverse from django import http from django.test.utils import override_settings from django.utils import html from mox3.mox import IsA import six from heatclient.common import template_format as hc_format from heat_dashboard import api from heat_dashboard.test import helpers as test from openstack_dashboard import api as dashboard_api from heat_dashboard.content.stacks import forms from heat_dashboard.content.stacks import mappings from heat_dashboard.content.stacks import tables INDEX_TEMPLATE = 'project/stacks/index.html' INDEX_URL = reverse('horizon:project:stacks:index') DETAIL_URL = 'horizon:project:stacks:detail' class MockResource(object): def __init__(self, resource_type, physical_resource_id): self.resource_type = resource_type self.physical_resource_id = physical_resource_id class MappingsTests(test.TestCase): def test_mappings(self): def assertMappingUrl(url, resource_type, physical_resource_id): mock = MockResource(resource_type, physical_resource_id) mock_url = mappings.resource_to_url(mock) self.assertEqual(url, mock_url) assertMappingUrl( '/project/networks/subnets/aaa/detail', 'OS::Neutron::Subnet', 'aaa') assertMappingUrl( None, 'OS::Neutron::Subnet', None) assertMappingUrl( None, None, None) assertMappingUrl( None, 'AWS::AutoScaling::LaunchConfiguration', 'aaa') assertMappingUrl( '/project/instances/aaa/', 'AWS::EC2::Instance', 'aaa') assertMappingUrl( '/project/containers/container/aaa/', 'OS::Swift::Container', 'aaa') assertMappingUrl( None, 'Foo::Bar::Baz', 'aaa') assertMappingUrl( '/project/instances/aaa/', 'OS::Nova::Server', 'aaa') assertMappingUrl( '/project/stacks/stack/aaa/', 'OS::Heat::ResourceGroup', 'aaa') def test_stack_output(self): self.assertEqual(u'
foo
', mappings.stack_output('foo')) self.assertEqual(u'', mappings.stack_output(None)) outputs = ['one', 'two', 'three'] # On Python 3, the pretty JSON output doesn't add space before newline if six.PY3: expected_text = """[\n "one",\n "two",\n "three"\n]""" else: expected_text = """[\n "one", \n "two", \n "three"\n]""" self.assertEqual(u'
%s
' % html.escape(expected_text), mappings.stack_output(outputs)) outputs = {'foo': 'bar'} expected_text = """{\n "foo": "bar"\n}""" self.assertEqual(u'
%s
' % html.escape(expected_text), mappings.stack_output(outputs)) self.assertEqual( u'' 'http://www.example.com/foo', mappings.stack_output('http://www.example.com/foo')) class StackTests(test.TestCase): @override_settings(API_RESULT_PAGE_SIZE=2) @test.create_stubs({api.heat: ('stacks_list',)}) def test_index_paginated(self): stacks = self.stacks.list()[:5] filters = {} api.heat.stacks_list(IsA(http.HttpRequest), marker=None, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks, True, True]) api.heat.stacks_list(IsA(http.HttpRequest), marker=None, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks[:2], True, True]) api.heat.stacks_list(IsA(http.HttpRequest), marker=stacks[2].id, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks[2:4], True, True]) api.heat.stacks_list(IsA(http.HttpRequest), marker=stacks[4].id, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks[4:], True, True]) self.mox.ReplayAll() url = reverse('horizon:project:stacks:index') res = self.client.get(url) # get all self.assertEqual(len(res.context['stacks_table'].data), len(stacks)) self.assertTemplateUsed(res, INDEX_TEMPLATE) res = self.client.get(url) # get first page with 2 items self.assertEqual(len(res.context['stacks_table'].data), settings.API_RESULT_PAGE_SIZE) url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'), tables.StacksTable._meta.pagination_param, stacks[2].id) res = self.client.get(url) # get second page (items 2-4) self.assertEqual(len(res.context['stacks_table'].data), settings.API_RESULT_PAGE_SIZE) url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'), tables.StacksTable._meta.pagination_param, stacks[4].id) res = self.client.get(url) # get third page (item 5) self.assertEqual(len(res.context['stacks_table'].data), 1) @override_settings(API_RESULT_PAGE_SIZE=2) @test.create_stubs({api.heat: ('stacks_list',)}) def test_index_prev_paginated(self): stacks = self.stacks.list()[:3] filters = {} api.heat.stacks_list(IsA(http.HttpRequest), marker=None, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks, True, False]) api.heat.stacks_list(IsA(http.HttpRequest), marker=None, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks[:2], True, True]) api.heat.stacks_list(IsA(http.HttpRequest), marker=stacks[2].id, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([stacks[2:], True, True]) api.heat.stacks_list(IsA(http.HttpRequest), marker=stacks[2].id, paginate=True, sort_dir='asc', filters=filters) \ .AndReturn([stacks[:2], True, True]) self.mox.ReplayAll() url = reverse('horizon:project:stacks:index') res = self.client.get(url) # get all self.assertEqual(len(res.context['stacks_table'].data), len(stacks)) self.assertTemplateUsed(res, INDEX_TEMPLATE) res = self.client.get(url) # get first page with 2 items self.assertEqual(len(res.context['stacks_table'].data), settings.API_RESULT_PAGE_SIZE) url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'), tables.StacksTable._meta.pagination_param, stacks[2].id) res = self.client.get(url) # get second page (item 3) self.assertEqual(len(res.context['stacks_table'].data), 1) url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'), tables.StacksTable._meta.prev_pagination_param, stacks[2].id) res = self.client.get(url) # prev back to get first page with 2 pages self.assertEqual(len(res.context['stacks_table'].data), settings.API_RESULT_PAGE_SIZE) @test.create_stubs({api.heat: ('stack_create', 'template_validate'), dashboard_api.neutron: ('network_list_for_tenant', )}) def test_launch_stack(self): template = self.stack_templates.first() stack = self.stacks.first() api.heat.template_validate(IsA(http.HttpRequest), files={}, template=hc_format.parse(template.data)) \ .AndReturn(json.loads(template.validate)) api.heat.stack_create(IsA(http.HttpRequest), stack_name=stack.stack_name, timeout_mins=60, disable_rollback=True, template=None, parameters=IsA(dict), password='password', files=None) dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), self.tenant.id) \ .AndReturn(self.networks.list()) dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() url = reverse('horizon:project:stacks:select_template') res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/select_template.html') form_data = {'template_source': 'raw', 'template_data': template.data, 'referenced_files': {}, 'method': forms.TemplateForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/create.html') url = reverse('horizon:project:stacks:launch') form_data = {'template_source': 'raw', 'template_data': template.data, 'password': 'password', 'parameters': template.validate, 'stack_name': stack.stack_name, "timeout_mins": 60, "disable_rollback": True, "__param_DBUsername": "admin", "__param_LinuxDistribution": "F17", "__param_InstanceType": "m1.small", "__param_KeyName": "test", "__param_DBPassword": "admin", "__param_DBRootPassword": "admin", "__param_DBName": "wordpress", "__param_Network": self.networks.list()[0]['id'], 'method': forms.CreateStackForm.__name__} res = self.client.post(url, form_data) self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({api.heat: ('stack_create', 'template_validate'), dashboard_api.neutron: ('network_list_for_tenant', )}) def test_launch_stack_with_environment(self): template = self.stack_templates.first() environment = self.stack_environments.first() stack = self.stacks.first() api.heat.template_validate(IsA(http.HttpRequest), files={}, template=hc_format.parse(template.data), environment=environment.data) \ .AndReturn(json.loads(template.validate)) api.heat.stack_create(IsA(http.HttpRequest), stack_name=stack.stack_name, timeout_mins=60, disable_rollback=True, template=None, environment=environment.data, parameters=IsA(dict), password='password', files=None) dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), self.tenant.id) \ .AndReturn(self.networks.list()) dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() url = reverse('horizon:project:stacks:select_template') res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/select_template.html') form_data = {'template_source': 'raw', 'template_data': template.data, 'environment_source': 'raw', 'environment_data': environment.data, 'method': forms.TemplateForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/create.html') url = reverse('horizon:project:stacks:launch') form_data = {'template_source': 'raw', 'template_data': template.data, 'environment_source': 'raw', 'environment_data': environment.data, 'password': 'password', 'parameters': template.validate, 'stack_name': stack.stack_name, "timeout_mins": 60, "disable_rollback": True, "__param_DBUsername": "admin", "__param_LinuxDistribution": "F17", "__param_InstanceType": "m1.small", "__param_KeyName": "test", "__param_DBPassword": "admin", "__param_DBRootPassword": "admin", "__param_DBName": "wordpress", "__param_Network": self.networks.list()[0]['id'], 'method': forms.CreateStackForm.__name__} res = self.client.post(url, form_data) self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({api.heat: ('template_validate',)}) def test_launch_stack_with_hidden_parameters(self): template = { 'data': ('heat_template_version: 2013-05-23\n' 'parameters:\n' ' public_string:\n' ' type: string\n' ' secret_string:\n' ' type: string\n' ' hidden: true\n'), 'validate': { 'Description': 'No description', 'Parameters': { 'public_string': { 'Label': 'public_string', 'Description': '', 'Type': 'String', 'NoEcho': 'false' }, 'secret_string': { 'Label': 'secret_string', 'Description': '', 'Type': 'String', 'NoEcho': 'true' } } } } api.heat.template_validate( IsA(http.HttpRequest), files={}, template=hc_format.parse(template['data']))\ .AndReturn(template['validate']) self.mox.ReplayAll() url = reverse('horizon:project:stacks:select_template') res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/select_template.html') form_data = {'template_source': 'raw', 'template_data': template['data'], 'method': forms.TemplateForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/create.html') # ensure the fields were rendered correctly if (1, 10) <= django.VERSION < (2, 0): pattern = ('') secret = ('') else: pattern = ('') secret = ('') self.assertContains(res, pattern, html=True) self.assertContains(res, secret, html=True) @test.create_stubs({api.heat: ('template_validate',)}) def test_launch_stack_with_parameter_group(self): template = { 'data': ('heat_template_version: 2013-05-23\n' 'parameters:\n' ' last_param:\n' ' type: string\n' ' first_param:\n' ' type: string\n' ' middle_param:\n' ' type: string\n' 'parameter_groups:\n' '- parameters:\n' ' - first_param\n' ' - middle_param\n' ' - last_param\n'), 'validate': { 'Description': 'No description', 'Parameters': { 'last_param': { 'Label': 'last_param', 'Description': '', 'Type': 'String', 'NoEcho': 'false' }, 'first_param': { 'Label': 'first_param', 'Description': '', 'Type': 'String', 'NoEcho': 'false' }, 'middle_param': { 'Label': 'middle_param', 'Description': '', 'Type': 'String', 'NoEcho': 'true' } }, 'ParameterGroups': [ { 'parameters': [ 'first_param', 'middle_param', 'last_param' ] } ] } } api.heat.template_validate( IsA(http.HttpRequest), files={}, template=hc_format.parse(template['data'])).\ AndReturn(template['validate']) self.mox.ReplayAll() url = reverse('horizon:project:stacks:select_template') res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/select_template.html') form_data = {'template_source': 'raw', 'template_data': template['data'], 'method': forms.TemplateForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/create.html') # ensure the fields were rendered in the correct order regex = re.compile('^.*>first_param<.*>middle_param<.*>last_param<.*$', flags=re.DOTALL) self.assertRegexpMatches(res.content.decode('utf-8'), regex) @test.create_stubs({api.heat: ('stack_create', 'template_validate')}) def test_launch_stack_parameter_types(self): template = { 'data': ('heat_template_version: 2013-05-23\n' 'parameters:\n' ' param1:\n' ' type: string\n' ' param2:\n' ' type: number\n' ' param3:\n' ' type: json\n' ' param4:\n' ' type: comma_delimited_list\n' ' param5:\n' ' type: boolean\n'), 'validate': { "Description": "No description", "Parameters": { "param1": { "Type": "String", "NoEcho": "false", "Description": "", "Label": "param1" }, "param2": { "Type": "Number", "NoEcho": "false", "Description": "", "Label": "param2" }, "param3": { "Type": "Json", "NoEcho": "false", "Description": "", "Label": "param3" }, "param4": { "Type": "CommaDelimitedList", "NoEcho": "false", "Description": "", "Label": "param4" }, "param5": { "Type": "Boolean", "NoEcho": "false", "Description": "", "Label": "param5" } } } } stack = self.stacks.first() api.heat.template_validate( IsA(http.HttpRequest), files={}, template=hc_format.parse(template['data']))\ .AndReturn(template['validate']) api.heat.stack_create(IsA(http.HttpRequest), stack_name=stack.stack_name, timeout_mins=60, disable_rollback=True, template=hc_format.parse(template['data']), parameters={'param1': 'some string', 'param2': 42, 'param3': '{"key": "value"}', 'param4': 'a,b,c', 'param5': True}, password='password', files={}) self.mox.ReplayAll() url = reverse('horizon:project:stacks:select_template') res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/select_template.html') form_data = {'template_source': 'raw', 'template_data': template['data'], 'method': forms.TemplateForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/create.html') # ensure the fields were rendered correctly if (1, 10) <= django.VERSION < (2, 0): input_str = ('') else: input_str = ('') self.assertContains(res, input_str.format(3, 'text'), html=True) self.assertContains(res, input_str.format(4, 'text'), html=True) if (1, 11) <= django.VERSION < (2, 0): input_str_param2 = ('') elif (1, 10) <= django.VERSION < (1, 11): input_str_param2 = ('') else: input_str_param2 = ('') self.assertContains(res, input_str_param2, html=True) # post some sample data and make sure it validates url = reverse('horizon:project:stacks:launch') form_data = {'template_source': 'raw', 'template_data': template['data'], 'password': 'password', 'parameters': json.dumps(template['validate']), 'stack_name': stack.stack_name, "timeout_mins": 60, "disable_rollback": True, "__param_param1": "some string", "__param_param2": 42, "__param_param3": '{"key": "value"}', "__param_param4": "a,b,c", "__param_param5": True, 'method': forms.CreateStackForm.__name__} res = self.client.post(url, form_data) self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({api.heat: ('stack_update', 'stack_get', 'template_get', 'template_validate'), dashboard_api.neutron: ('network_list_for_tenant', )}) def test_edit_stack_template(self): template = self.stack_templates.first() stack = self.stacks.first() # GET to template form api.heat.stack_get(IsA(http.HttpRequest), stack.id).AndReturn(stack) # POST template form, validation api.heat.template_validate(IsA(http.HttpRequest), files={}, template=hc_format.parse(template.data)) \ .AndReturn(json.loads(template.validate)) # GET to edit form api.heat.stack_get(IsA(http.HttpRequest), stack.id).AndReturn(stack) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) # POST to edit form api.heat.stack_get(IsA(http.HttpRequest), stack.id).AndReturn(stack) fields = { 'stack_name': stack.stack_name, 'disable_rollback': True, 'timeout_mins': 61, 'password': 'password', 'template': None, 'parameters': IsA(dict), 'files': None } api.heat.stack_update(IsA(http.HttpRequest), stack_id=stack.id, **fields) dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() url = reverse('horizon:project:stacks:change_template', args=[stack.id]) res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/change_template.html') form_data = {'template_source': 'raw', 'template_data': template.data, 'method': forms.ChangeTemplateForm.__name__} res = self.client.post(url, form_data) url = reverse('horizon:project:stacks:edit_stack', args=[stack.id, ]) form_data = {'template_source': 'raw', 'template_data': template.data, 'password': 'password', 'parameters': template.validate, 'stack_name': stack.stack_name, 'stack_id': stack.id, "timeout_mins": 61, "disable_rollback": True, "__param_DBUsername": "admin", "__param_LinuxDistribution": "F17", "__param_InstanceType": "m1.small", "__param_KeyName": "test", "__param_DBPassword": "admin", "__param_DBRootPassword": "admin", "__param_DBName": "wordpress", "__param_Network": self.networks.list()[0]['id'], 'method': forms.EditStackForm.__name__} res = self.client.post(url, form_data) self.assertRedirectsNoFollow(res, INDEX_URL) def test_launch_stack_form_invalid_name_digit(self): self._test_launch_stack_invalid_name('2_StartWithDigit') def test_launch_stack_form_invalid_name_underscore(self): self._test_launch_stack_invalid_name('_StartWithUnderscore') def test_launch_stack_form_invalid_name_point(self): self._test_launch_stack_invalid_name('.StartWithPoint') @test.create_stubs({dashboard_api.neutron: ('network_list_for_tenant', )}) def _test_launch_stack_invalid_name(self, name): dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() template = self.stack_templates.first() url = reverse('horizon:project:stacks:launch') form_data = {'template_source': 'raw', 'template_data': template.data, 'password': 'password', 'parameters': template.validate, 'stack_name': name, "timeout_mins": 60, "disable_rollback": True, "__param_DBUsername": "admin", "__param_LinuxDistribution": "F17", "__param_InstanceType": "m1.small", "__param_KeyName": "test", "__param_DBPassword": "admin", "__param_DBRootPassword": "admin", "__param_DBName": "wordpress", "__param_Network": self.networks.list()[0]['id'], 'method': forms.CreateStackForm.__name__} res = self.client.post(url, form_data) error = ('Name must start with a letter and may only contain letters, ' 'numbers, underscores, periods and hyphens.') self.assertFormErrors(res, 1) self.assertFormError(res, "form", 'stack_name', error) def _test_stack_action(self, action): stack = self.stacks.first() filters = {} api.heat.stacks_list(IsA(http.HttpRequest), marker=None, paginate=True, sort_dir='desc', filters=filters) \ .AndReturn([self.stacks.list(), True, True]) getattr(api.heat, 'action_%s' % action)(IsA(http.HttpRequest), stack.id).AndReturn(stack) self.mox.ReplayAll() form_data = {"action": "stacks__%s__%s" % (action, stack.id)} res = self.client.post(INDEX_URL, form_data) self.assertNoFormErrors(res) self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({api.heat: ('stacks_list', 'action_check',)}) def test_check_stack(self): self._test_stack_action('check') @test.create_stubs({api.heat: ('stacks_list', 'action_suspend',)}) def test_suspend_stack(self): self._test_stack_action('suspend') @test.create_stubs({api.heat: ('stacks_list', 'action_resume',)}) def test_resume_stack(self): self._test_stack_action('resume') @test.create_stubs({api.heat: ('stack_preview', 'template_validate')}) def test_preview_stack(self): template = self.stack_templates.first() stack = self.stacks.first() api.heat.template_validate(IsA(http.HttpRequest), files={}, template=hc_format.parse(template.data)) \ .AndReturn(json.loads(template.validate)) api.heat.stack_preview(IsA(http.HttpRequest), stack_name=stack.stack_name, timeout_mins=60, disable_rollback=True, template=None, parameters=IsA(dict), files=None).AndReturn(stack) self.mox.ReplayAll() url = reverse('horizon:project:stacks:preview_template') res = self.client.get(url) self.assertTemplateUsed(res, 'project/stacks/preview_template.html') form_data = {'template_source': 'raw', 'template_data': template.data, 'method': forms.PreviewTemplateForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/preview.html') url = reverse('horizon:project:stacks:preview') form_data = {'template_source': 'raw', 'template_data': template.data, 'parameters': template.validate, 'stack_name': stack.stack_name, "timeout_mins": 60, "disable_rollback": True, "__param_DBUsername": "admin", "__param_LinuxDistribution": "F17", "__param_InstanceType": "m1.small", "__param_KeyName": "test", "__param_DBPassword": "admin", "__param_DBRootPassword": "admin", "__param_DBName": "wordpress", 'method': forms.PreviewStackForm.__name__} res = self.client.post(url, form_data) self.assertTemplateUsed(res, 'project/stacks/preview_details.html') self.assertEqual(res.context['stack_preview']['stack_name'], stack.stack_name) @test.create_stubs({api.heat: ('stack_get', 'template_get', 'resources_list')}) def test_detail_stack_topology(self): stack = self.stacks.first() template = self.stack_templates.first() api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn(stack) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) api.heat.resources_list(IsA(http.HttpRequest), stack.stack_name) \ .AndReturn([]) self.mox.ReplayAll() url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), '='.join(['tab', 'stack_details__stack_topology'])]) res = self.client.get(url) tab = res.context['tab_group'].get_tab('topology') d3_data = tab.data['d3_data'] self.assertEqual(tab.template_name, 'project/stacks/_detail_topology.html') # status is CREATE_COMPLETE, so we expect the topology to display it self.assertIn('info_box', d3_data) self.assertIn('stack-green.svg', d3_data) self.assertIn('Create Complete', d3_data) # @test.create_stubs({api.heat: ('stack_get', 'template_get'), # project_api: ('d3_data',)}) @test.create_stubs({api.heat: ('stack_get', 'template_get', 'resources_list')}) def test_detail_stack_overview(self): stack = self.stacks.first() template = self.stack_templates.first() api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn(stack) api.heat.resources_list(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn([]) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) # project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ # .AndReturn(json.dumps({"nodes": [], "stack": {}})) self.mox.ReplayAll() url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), '='.join(['tab', 'stack_details__stack_overview'])]) res = self.client.get(url) tab = res.context['tab_group'].get_tab('overview') overview_data = tab.data['stack'] self.assertEqual(tab.template_name, 'project/stacks/_detail_overview.html') self.assertEqual(stack.stack_name, overview_data.stack_name) # @test.create_stubs({api.heat: ('stack_get', # 'template_get', 'resources_list'), # project_api: ('d3_data',)}) @test.create_stubs({api.heat: ('stack_get', 'template_get', 'resources_list')}) def test_detail_stack_resources(self): stack = self.stacks.first() template = self.stack_templates.first() api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn(stack) api.heat.resources_list(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn([]) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) # Needs to move into JSONView test # because this part will be called from Ajax # project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ # .AndReturn(json.dumps({"nodes": [], "stack": {}})) self.mox.ReplayAll() url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), '='.join(['tab', 'stack_details__resource_overview'])]) res = self.client.get(url) tab = res.context['tab_group'].get_tab('resources') self.assertEqual(tab.template_name, 'project/stacks/_detail_resources.html') @test.create_stubs({api.heat: ('stack_get', 'template_get')}) def test_detail_stack_template(self): stack = self.stacks.first() template = self.stack_templates.first() api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(stack) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) self.mox.ReplayAll() url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), '='.join(['tab', 'stack_details__stack_template'])]) res = self.client.get(url) tab = res.context['tab_group'].get_tab('stack_template') template_data = tab.data['stack_template'] self.assertEqual(tab.template_name, 'project/stacks/_stack_template.html') self.assertIn(json.loads(template.validate)['Description'], template_data) @test.create_stubs({api.heat: ('resource_get', 'resource_metadata_get')}) def test_resource_view(self): stack = self.stacks.first() resource = self.heat_resources.first() metadata = {} api.heat.resource_get( IsA(http.HttpRequest), stack.id, resource.resource_name) \ .AndReturn(resource) api.heat.resource_metadata_get( IsA(http.HttpRequest), stack.id, resource.resource_name) \ .AndReturn(metadata) self.mox.ReplayAll() url = reverse('horizon:project:stacks:resource', args=[stack.id, resource.resource_name]) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') self.assertTemplateUsed(res, 'project/stacks/_resource_overview.html') self.assertEqual(res.context['resource'].logical_resource_id, resource.logical_resource_id) class TemplateFormTests(test.TestCase): class SimpleFile(object): def __init__(self, name, data): self.name = name self.data = data def read(self): return self.data def test_create_upload_form_attributes(self): attrs = forms.create_upload_form_attributes( 'env', 'url', 'Environment') self.assertEqual(attrs['data-envsource-url'], 'Environment') def test_clean_file_upload_form_url(self): kwargs = {'next_view': 'Launch Stack'} t = forms.TemplateForm({}, **kwargs) precleaned = { 'template_url': 'http://templateurl.com', } t.clean_uploaded_files('template', 'template', precleaned, {}) self.assertEqual(precleaned['template_url'], 'http://templateurl.com') def test_clean_file_upload_form_multiple(self): kwargs = {'next_view': 'Launch Stack'} t = forms.TemplateForm({}, **kwargs) precleaned = { 'template_url': 'http://templateurl.com', 'template_data': 'http://templateurl.com', } self.assertRaises( exceptions.ValidationError, t.clean_uploaded_files, 'template', 'template', precleaned, {}) def test_clean_file_upload_form_invalid_json(self): kwargs = {'next_view': 'Launch Stack'} t = forms.TemplateForm({}, **kwargs) precleaned = { 'template_data': 'http://templateurl.com', } json_str = '{notvalidjson::::::json/////json' files = {'template_upload': self.SimpleFile('template_name', json_str)} self.assertRaises( exceptions.ValidationError, t.clean_uploaded_files, 'template', 'template', precleaned, files) def test_clean_file_upload_form_valid_data(self): kwargs = {'next_view': 'Launch Stack'} t = forms.TemplateForm({}, **kwargs) precleaned = { 'template_data': 'http://templateurl.com', } json_str = '{"isvalid":"json"}' files = {'template_upload': self.SimpleFile('template_name', json_str)} t.clean_uploaded_files('template', 'template', precleaned, files) self.assertEqual( json_str, precleaned['template_data']) heat-dashboard-1.0.2/heat_dashboard/test/tests/content/test_template_versions.py0000666000175100017510000000567213240544407030322 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from django.core.urlresolvers import reverse from django import http from mox3.mox import IsA from heat_dashboard import api from heat_dashboard.test import helpers as test class TemplateVersionsTests(test.TestCase): INDEX_URL = reverse('horizon:project:template_versions:index') @test.create_stubs({api.heat: ('template_version_list',)}) def test_index(self): api.heat.template_version_list( IsA(http.HttpRequest)).AndReturn(self.template_versions.list()) self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed( res, 'project/template_versions/index.html') self.assertContains(res, 'HeatTemplateFormatVersion.2012-12-12') @test.create_stubs({api.heat: ('template_version_list',)}) def test_index_exception(self): api.heat.template_version_list( IsA(http.HttpRequest)).AndRaise(self.exceptions.heat) self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed( res, 'project/template_versions/index.html') self.assertEqual(len(res.context['table'].data), 0) self.assertMessageCount(res, error=1) @test.create_stubs({api.heat: ('template_function_list',)}) def test_detail_view(self): t_version = self.template_versions.first().version t_functions = self.template_functions.list() api.heat.template_function_list( IsA(http.HttpRequest), t_version).AndReturn(t_functions) self.mox.ReplayAll() url = reverse('horizon:project:template_versions:details', args=[t_version]) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') self.assertNoMessages() @test.create_stubs({api.heat: ('template_function_list',)}) def test_detail_view_with_exception(self): t_version = self.template_versions.first().version api.heat.template_function_list( IsA(http.HttpRequest), t_version).\ AndRaise(self.exceptions.heat) self.mox.ReplayAll() url = reverse('horizon:project:template_versions:details', args=[t_version]) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') self.assertEqual(len(res.context['table'].data), 0) self.assertMessageCount(res, error=1) heat-dashboard-1.0.2/heat_dashboard/test/tests/content/test_resource_types.py0000666000175100017510000000342513240544407027624 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from django.core.urlresolvers import reverse from django import http from mox3.mox import IsA from heat_dashboard import api from heat_dashboard.test import helpers as test class ResourceTypesTests(test.TestCase): @test.create_stubs({api.heat: ('resource_types_list',)}) def test_index(self): filters = {} api.heat.resource_types_list( IsA(http.HttpRequest), filters=filters).AndReturn( self.resource_types.list()) self.mox.ReplayAll() res = self.client.get( reverse('horizon:project:resource_types:index')) self.assertTemplateUsed( res, 'horizon/common/_data_table_view.html') self.assertContains(res, 'AWS::CloudFormation::Stack') @test.create_stubs({api.heat: ('resource_type_get',)}) def test_detail_view(self): rt = self.api_resource_types.first() api.heat.resource_type_get( IsA(http.HttpRequest), rt['resource_type']).AndReturn(rt) self.mox.ReplayAll() url = reverse('horizon:project:resource_types:details', args=[rt['resource_type']]) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') self.assertNoMessages() heat-dashboard-1.0.2/heat_dashboard/test/tests/content/test_template_generator.py0000666000175100017510000001064713240544407030436 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import json from mox3.mox import IsA from django.core.urlresolvers import reverse from django import http from openstack_dashboard import api as dashboard_api from heat_dashboard import api from heat_dashboard.test import helpers as test class TemplateGeneratorTests(test.TestCase): def test_index(self): self.client.get(reverse('horizon:project:template_generator:index')) self.assertTemplateUsed( template_name='project/template_generator/index.html') @test.create_stubs({ api.heat: ('template_version_list', ), dashboard_api.neutron: ( 'network_list', 'subnet_list', 'tenant_floating_ip_list', 'port_list', 'security_group_list', 'router_list', 'policy_list'), dashboard_api.cinder: ( 'volume_list', 'volume_snapshot_list', 'volume_type_list', 'volume_backup_list'), dashboard_api.glance: ('image_list_detailed', ), dashboard_api.nova: ('availability_zone_list', 'flavor_list', 'server_list', 'keypair_list')}) def test_option(self): volumes = self.cinder_volumes.list() volume_snapshots = self.cinder_volume_snapshots.list() volume_types = self.cinder_volume_types.list() volume_backups = self.cinder_volume_backups.list() images = self.imagesV2.list() networks = self.networks.list() subnets = self.subnets.list() floating_ips = self.floating_ips.list() ports = self.ports.list() security_groups = self.security_groups.list() routers = self.routers.list() qos_policies = self.qos_policies.list() availability_zones = self.availability_zones.list() flavors = self.flavors.list() instances = self.servers.list() keypairs = self.keypairs.list() template_versions = self.template_versions.list() dashboard_api.cinder.volume_list( IsA(http.HttpRequest)).AndReturn(volumes) dashboard_api.cinder.volume_snapshot_list( IsA(http.HttpRequest)).AndReturn(volume_snapshots) dashboard_api.cinder.volume_type_list( IsA(http.HttpRequest)).AndReturn(volume_types) dashboard_api.cinder.volume_backup_list( IsA(http.HttpRequest)).AndReturn(volume_backups) dashboard_api.glance.image_list_detailed( IsA(http.HttpRequest)).AndReturn(images) dashboard_api.neutron.network_list( IsA(http.HttpRequest)).AndReturn(networks) dashboard_api.neutron.subnet_list( IsA(http.HttpRequest)).AndReturn(subnets) dashboard_api.neutron.tenant_floating_ip_list( IsA(http.HttpRequest), True).AndReturn(floating_ips) dashboard_api.neutron.port_list( IsA(http.HttpRequest)).AndReturn(ports) dashboard_api.neutron.security_group_list( IsA(http.HttpRequest)).AndReturn(security_groups) dashboard_api.neutron.router_list( IsA(http.HttpRequest)).AndReturn(routers) dashboard_api.neutron.policy_list( IsA(http.HttpRequest)).AndReturn(qos_policies) dashboard_api.nova.availability_zone_list( IsA(http.HttpRequest)).AndReturn(availability_zones) dashboard_api.nova.flavor_list( IsA(http.HttpRequest)).AndReturn(flavors) dashboard_api.nova.server_list( IsA(http.HttpRequest)).AndReturn(instances) dashboard_api.nova.keypair_list( IsA(http.HttpRequest)).AndReturn(keypairs) api.heat.template_version_list( IsA(http.HttpRequest)).AndReturn(template_versions) self.mox.ReplayAll() resp = self.client.get(reverse( 'horizon:project:template_generator:apis')) data = resp.content if isinstance(data, bytes): data = data.decode('utf-8') json_data = json.loads(data) self.assertEqual(len(json_data.keys()), 20) heat-dashboard-1.0.2/heat_dashboard/test/tests/content/__init__.py0000666000175100017510000000000013240544407025233 0ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/tests/api/0000775000175100017510000000000013240545010022220 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/tests/api/heat_tests.py0000666000175100017510000003271713240544407024762 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import six from django.conf import settings from django.test.utils import override_settings from heat_dashboard import api from heat_dashboard.test import helpers as test from horizon import exceptions class HeatApiTests(test.APITestCase): def test_stack_list(self): api_stacks = self.stacks.list() limit = getattr(settings, 'API_RESULT_LIMIT', 1000) heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.list(limit=limit, sort_dir='desc', sort_key='created_at',) \ .AndReturn(iter(api_stacks)) self.mox.ReplayAll() stacks, has_more, has_prev = api.heat.stacks_list(self.request) self.assertItemsEqual(stacks, api_stacks) self.assertFalse(has_more) self.assertFalse(has_prev) @override_settings(API_RESULT_PAGE_SIZE=2) def test_stack_list_sort_options(self): # Verify that sort_dir and sort_key work api_stacks = self.stacks.list() limit = getattr(settings, 'API_RESULT_LIMIT', 1000) sort_dir = 'asc' sort_key = 'size' heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.list(limit=limit, sort_dir=sort_dir, sort_key=sort_key,) \ .AndReturn(iter(api_stacks)) self.mox.ReplayAll() stacks, has_more, has_prev = api.heat.stacks_list(self.request, sort_dir=sort_dir, sort_key=sort_key) self.assertItemsEqual(stacks, api_stacks) self.assertFalse(has_more) self.assertFalse(has_prev) @override_settings(API_RESULT_PAGE_SIZE=20) def test_stack_list_pagination_less_page_size(self): api_stacks = self.stacks.list() page_size = settings.API_RESULT_PAGE_SIZE sort_dir = 'desc' sort_key = 'created_at' heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.list(limit=page_size + 1, sort_dir=sort_dir, sort_key=sort_key,) \ .AndReturn(iter(api_stacks)) self.mox.ReplayAll() stacks, has_more, has_prev = api.heat.stacks_list(self.request, sort_dir=sort_dir, sort_key=sort_key, paginate=True) expected_stacks = api_stacks[:page_size] self.assertItemsEqual(stacks, expected_stacks) self.assertFalse(has_more) self.assertFalse(has_prev) @override_settings(API_RESULT_PAGE_SIZE=10) def test_stack_list_pagination_equal_page_size(self): api_stacks = self.stacks.list() page_size = settings.API_RESULT_PAGE_SIZE sort_dir = 'desc' sort_key = 'created_at' heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.list(limit=page_size + 1, sort_dir=sort_dir, sort_key=sort_key,) \ .AndReturn(iter(api_stacks)) self.mox.ReplayAll() stacks, has_more, has_prev = api.heat.stacks_list(self.request, sort_dir=sort_dir, sort_key=sort_key, paginate=True) expected_stacks = api_stacks[:page_size] self.assertItemsEqual(stacks, expected_stacks) self.assertFalse(has_more) self.assertFalse(has_prev) @override_settings(API_RESULT_PAGE_SIZE=2) def test_stack_list_pagination_marker(self): page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20) sort_dir = 'desc' sort_key = 'created_at' marker = 'nonsense' api_stacks = self.stacks.list() heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.list(limit=page_size + 1, marker=marker, sort_dir=sort_dir, sort_key=sort_key,) \ .AndReturn(iter(api_stacks[:page_size + 1])) self.mox.ReplayAll() stacks, has_more, has_prev = api.heat.stacks_list(self.request, marker=marker, paginate=True, sort_dir=sort_dir, sort_key=sort_key,) self.assertEqual(len(stacks), page_size) self.assertItemsEqual(stacks, api_stacks[:page_size]) self.assertTrue(has_more) self.assertTrue(has_prev) @override_settings(API_RESULT_PAGE_SIZE=2) def test_stack_list_pagination_marker_prev(self): page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20) sort_dir = 'asc' sort_key = 'created_at' marker = 'nonsense' api_stacks = self.stacks.list() heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.list(limit=page_size + 1, marker=marker, sort_dir=sort_dir, sort_key=sort_key,) \ .AndReturn(iter(api_stacks[:page_size + 1])) self.mox.ReplayAll() stacks, has_more, has_prev = api.heat.stacks_list(self.request, marker=marker, paginate=True, sort_dir=sort_dir, sort_key=sort_key,) self.assertEqual(len(stacks), page_size) self.assertItemsEqual(stacks, api_stacks[:page_size]) self.assertTrue(has_more) self.assertTrue(has_prev) def test_template_get(self): api_stacks = self.stacks.list() stack_id = api_stacks[0].id mock_data_template = self.stack_templates.list()[0] heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.template(stack_id).AndReturn(mock_data_template) self.mox.ReplayAll() template = api.heat.template_get(self.request, stack_id) self.assertEqual(mock_data_template.data, template.data) def test_stack_create(self): api_stacks = self.stacks.list() stack = api_stacks[0] heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() form_data = {'timeout_mins': 600} password = 'secret' heatclient.stacks.create(**form_data).AndReturn(stack) self.mox.ReplayAll() returned_stack = api.heat.stack_create(self.request, password, **form_data) from heatclient.v1 import stacks self.assertIsInstance(returned_stack, stacks.Stack) def test_stack_update(self): api_stacks = self.stacks.list() stack = api_stacks[0] stack_id = stack.id heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() form_data = {'timeout_mins': 600} password = 'secret' heatclient.stacks.update(stack_id, **form_data).AndReturn(stack) self.mox.ReplayAll() returned_stack = api.heat.stack_update(self.request, stack_id, password, **form_data) from heatclient.v1 import stacks self.assertIsInstance(returned_stack, stacks.Stack) def test_snapshot_create(self): stack_id = self.stacks.first().id snapshot_create = self.stack_snapshot_create.list()[0] heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.snapshot(stack_id).AndReturn(snapshot_create) self.mox.ReplayAll() returned_snapshot_create_info = api.heat.snapshot_create(self.request, stack_id) self.assertEqual(returned_snapshot_create_info, snapshot_create) def test_snapshot_list(self): stack_id = self.stacks.first().id snapshot_list = self.stack_snapshot.list() heatclient = self.stub_heatclient() heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks.snapshot_list(stack_id).AndReturn(snapshot_list) self.mox.ReplayAll() returned_snapshots = api.heat.snapshot_list(self.request, stack_id) self.assertItemsEqual(returned_snapshots, snapshot_list) def test_get_template_files_with_template_data(self): tmpl = ''' # comment heat_template_version: 2013-05-23 resources: server1: type: OS::Nova::Server properties: flavor: m1.medium image: cirros ''' expected_files = {} files = api.heat.get_template_files(template_data=tmpl)[0] self.assertEqual(files, expected_files) def test_get_template_files(self): tmpl = ''' # comment heat_template_version: 2013-05-23 resources: server1: type: OS::Nova::Server properties: flavor: m1.medium image: cirros user_data_format: RAW user_data: get_file: http://test.example/example ''' expected_files = {u'http://test.example/example': b'echo "test"'} url = 'http://test.example/example' data = b'echo "test"' self.mox.StubOutWithMock(six.moves.urllib.request, 'urlopen') six.moves.urllib.request.urlopen(url).AndReturn( six.BytesIO(data)) self.mox.ReplayAll() files = api.heat.get_template_files(template_data=tmpl)[0] self.assertEqual(files, expected_files) def test_get_template_files_with_template_url(self): url = 'https://test.example/example.yaml' data = b''' # comment heat_template_version: 2013-05-23 resources: server1: type: OS::Nova::Server properties: flavor: m1.medium image: cirros user_data_format: RAW user_data: get_file: http://test.example/example ''' url2 = 'http://test.example/example' data2 = b'echo "test"' expected_files = {'http://test.example/example': b'echo "test"'} self.mox.StubOutWithMock(six.moves.urllib.request, 'urlopen') six.moves.urllib.request.urlopen(url).AndReturn( six.BytesIO(data)) six.moves.urllib.request.urlopen(url2).AndReturn( six.BytesIO(data2)) self.mox.ReplayAll() files = api.heat.get_template_files(template_url=url)[0] self.assertEqual(files, expected_files) def test_get_template_files_invalid(self): tmpl = ''' # comment heat_template_version: 2013-05-23 resources: server1: type: OS::Nova::Server properties: flavor: m1.medium image: cirros user_data_format: RAW user_data: get_file: file:///example ''' try: api.heat.get_template_files(template_data=tmpl)[0] except exceptions.GetFileError: self.assertRaises(exceptions.GetFileError) def test_template_version_list(self): api_template_versions = self.template_versions.list() heatclient = self.stub_heatclient() heatclient.template_versions = self.mox.CreateMockAnything() heatclient.template_versions.list().AndReturn(api_template_versions) self.mox.ReplayAll() template_versions = api.heat.template_version_list(self.request) self.assertItemsEqual(template_versions, api_template_versions) def test_template_function_list(self): template_version = self.template_versions.first().version api_template_functions = self.template_functions.list() heatclient = self.stub_heatclient() heatclient.template_versions = self.mox.CreateMockAnything() heatclient.template_versions.get( template_version).AndReturn(api_template_functions) self.mox.ReplayAll() template_functions = api.heat.template_function_list( self.request, template_version) self.assertItemsEqual(template_functions, api_template_functions) heat-dashboard-1.0.2/heat_dashboard/test/tests/api/heat_rest_tests.py0000666000175100017510000000472313240544407026013 0ustar zuulzuul00000000000000# (c) Copyright 2015 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json import mock from heat_dashboard.api.rest import heat from heat_dashboard.test import helpers as test from openstack_dashboard import api class ValidateRestTestCase(test.TestCase): @mock.patch.object(heat.api, 'heat') def test_validate_post(self, hc): body = '''{"template_url":"http://localhost/template.yaml"}''' request = self.mock_rest_request(body=body) hc.template_validate.return_value = ({'Description': 'foo'}) response = heat.Validate().post(request) self.assertStatusCode(response, 200) self.assertEqual(response.json, {"Description": "foo"}) kwargs = json.loads(body) hc.template_validate.assert_called_once_with(request, **kwargs) class HeatRestTestCase(test.TestCase): # # Services # @test.create_stubs({api.base: ('is_service_enabled',)}) @mock.patch.object(heat.api, 'heat') def test_services_get(self, hc): request = self.mock_rest_request(GET={}) api.base.is_service_enabled(request, 'orchestration').AndReturn(True) hc.service_list.return_value = [ mock.Mock(**{'to_dict.return_value': {'id': '1'}}), mock.Mock(**{'to_dict.return_value': {'id': '2'}}) ] self.mox.ReplayAll() response = heat.Services().get(request) self.assertStatusCode(response, 200) self.assertEqual(response.content.decode('utf-8'), '{"items": [{"id": "1"}, {"id": "2"}]}') hc.service_list.assert_called_once_with(request) @test.create_stubs({api.base: ('is_service_enabled',)}) def test_services_get_disabled(self): request = self.mock_rest_request(GET={}) api.base.is_service_enabled(request, 'orchestration').AndReturn(False) self.mox.ReplayAll() response = heat.Services().get(request) self.assertStatusCode(response, 501) heat-dashboard-1.0.2/heat_dashboard/test/tests/api/__init__.py0000666000175100017510000000000013240544407024332 0ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/tests/__init__.py0000666000175100017510000000000013240544407023561 0ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/test_data/0000775000175100017510000000000013240545010022255 5ustar zuulzuul00000000000000heat-dashboard-1.0.2/heat_dashboard/test/test_data/utils.py0000666000175100017510000001032713240544407024005 0ustar zuulzuul00000000000000# Copyright 2012 Nebula, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. def load_test_data(load_onto=None): from heat_dashboard.test.test_data import cinder_data from heat_dashboard.test.test_data import exceptions from heat_dashboard.test.test_data import glance_data from heat_dashboard.test.test_data import heat_data from heat_dashboard.test.test_data import keystone_data from heat_dashboard.test.test_data import neutron_data from heat_dashboard.test.test_data import nova_data # The order of these loaders matters, some depend on others. loaders = ( exceptions.data, keystone_data.data, glance_data.data, nova_data.data, cinder_data.data, neutron_data.data, # swift_data.data, heat_data.data, ) if load_onto: for data_func in loaders: data_func(load_onto) return load_onto else: return TestData(*loaders) class TestData(object): """Holder object for test data. Any functions passed to the init method will be called with the ``TestData`` object as their only argument. They can then load data onto the object as desired. The idea is to use the instantiated object like this:: >>> import glance_data >>> TEST = TestData(glance_data.data) >>> TEST.images.list() [, ] >>> TEST.images.first() You can load as little or as much data as you like as long as the loaders don't conflict with each other. See the :class:`~openstack_dashboard.test.test_data.utils.TestDataContainer` class for a list of available methods. """ def __init__(self, *args): for data_func in args: data_func(self) class TestDataContainer(object): """A container for test data objects. The behavior of this class is meant to mimic a "manager" class, which has convenient shortcuts for common actions like "list", "filter", "get", and "add". """ def __init__(self): self._objects = [] def add(self, *args): """Add a new object to this container. Generally this method should only be used during data loading, since adding data during a test can affect the results of other tests. """ for obj in args: if obj not in self._objects: self._objects.append(obj) def list(self): """Returns a list of all objects in this container.""" return self._objects def filter(self, filtered=None, **kwargs): """Returns objects whose attributes match the given kwargs.""" if filtered is None: filtered = self._objects try: key, value = kwargs.popitem() except KeyError: # We're out of filters, return return filtered def get_match(obj): return hasattr(obj, key) and getattr(obj, key) == value filtered = [obj for obj in filtered if get_match(obj)] return self.filter(filtered=filtered, **kwargs) def get(self, **kwargs): """Returns a single object whose attributes match the given kwargs. An error will be raised if the arguments provided don't return exactly one match. """ matches = self.filter(**kwargs) if not matches: raise Exception("No matches found.") elif len(matches) > 1: raise Exception("Multiple matches found.") else: return matches.pop() def first(self): """Returns the first object from this container.""" return self._objects[0] def count(self): return len(self._objects) heat-dashboard-1.0.2/heat_dashboard/test/test_data/keystone_data.py0000666000175100017510000003150713240544407025502 0ustar zuulzuul00000000000000# Copyright 2012 Nebula, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import copy from datetime import timedelta from django.conf import settings from django.utils import datetime_safe from keystoneclient import access from keystoneclient.v2_0 import tenants from keystoneclient.v2_0 import users from keystoneclient.v3.contrib.federation import identity_providers from keystoneclient.v3.contrib.federation import mappings from keystoneclient.v3.contrib.federation import protocols from keystoneclient.v3 import domains from openstack_auth import user as auth_user from heat_dashboard.test.test_data import utils # Dummy service catalog with all service. # All endpoint URLs should point to example.com. # Try to keep them as accurate to real data as possible (ports, URIs, etc.) SERVICE_CATALOG = [ {"type": "compute", "name": "nova", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.nova.example.com:8774/v2", "internalURL": "http://int.nova.example.com:8774/v2", "publicURL": "http://public.nova.example.com:8774/v2"}, {"region": "RegionTwo", "adminURL": "http://admin.nova2.example.com:8774/v2", "internalURL": "http://int.nova2.example.com:8774/v2", "publicURL": "http://public.nova2.example.com:8774/v2"}]}, {"type": "volumev2", "name": "cinderv2", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.nova.example.com:8776/v2", "internalURL": "http://int.nova.example.com:8776/v2", "publicURL": "http://public.nova.example.com:8776/v2"}, {"region": "RegionTwo", "adminURL": "http://admin.nova.example.com:8776/v2", "internalURL": "http://int.nova.example.com:8776/v2", "publicURL": "http://public.nova.example.com:8776/v2"}]}, {"type": "image", "name": "glance", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.glance.example.com:9292", "internalURL": "http://int.glance.example.com:9292", "publicURL": "http://public.glance.example.com:9292"}]}, {"type": "identity", "name": "keystone", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.keystone.example.com:35357/v2.0", "internalURL": "http://int.keystone.example.com:5000/v2.0", "publicURL": "http://public.keystone.example.com:5000/v2.0"}]}, {"type": "object-store", "name": "swift", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.swift.example.com:8080/", "internalURL": "http://int.swift.example.com:8080/", "publicURL": "http://public.swift.example.com:8080/"}]}, {"type": "network", "name": "neutron", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.neutron.example.com:9696/", "internalURL": "http://int.neutron.example.com:9696/", "publicURL": "http://public.neutron.example.com:9696/"}]}, {"type": "ec2", "name": "EC2 Service", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.nova.example.com:8773/services/Admin", "publicURL": "http://public.nova.example.com:8773/services/Cloud", "internalURL": "http://int.nova.example.com:8773/services/Cloud"}]}, {"type": "orchestration", "name": "Heat", "endpoints_links": [], "endpoints": [ {"region": "RegionOne", "adminURL": "http://admin.heat.example.com:8004/v1", "publicURL": "http://public.heat.example.com:8004/v1", "internalURL": "http://int.heat.example.com:8004/v1"}]} ] def data(TEST): # Make a deep copy of the catalog to avoid persisting side-effects # when tests modify the catalog. TEST.service_catalog = copy.deepcopy(SERVICE_CATALOG) TEST.tokens = utils.TestDataContainer() TEST.domains = utils.TestDataContainer() TEST.users = utils.TestDataContainer() # TEST.groups = utils.TestDataContainer() TEST.tenants = utils.TestDataContainer() # TEST.role_assignments = utils.TestDataContainer() # TEST.roles = utils.TestDataContainer() # TEST.ec2 = utils.TestDataContainer() TEST.identity_providers = utils.TestDataContainer() TEST.idp_mappings = utils.TestDataContainer() TEST.idp_protocols = utils.TestDataContainer() # admin_role_dict = {'id': '1', # 'name': 'admin'} # admin_role = roles.Role(roles.RoleManager, admin_role_dict, loaded=True) member_role_dict = {'id': "2", 'name': settings.OPENSTACK_KEYSTONE_DEFAULT_ROLE} # member_role = roles.Role(roles.RoleManager, # member_role_dict, loaded=True) # TEST.roles.add(admin_role, member_role) # TEST.roles.admin = admin_role # TEST.roles.member = member_role domain_dict = {'id': "1", 'name': 'test_domain', 'description': "a test domain.", 'enabled': True} domain_dict_2 = {'id': "2", 'name': 'disabled_domain', 'description': "a disabled test domain.", 'enabled': False} domain_dict_3 = {'id': "3", 'name': 'another_test_domain', 'description': "another test domain.", 'enabled': True} domain = domains.Domain(domains.DomainManager, domain_dict) disabled_domain = domains.Domain(domains.DomainManager, domain_dict_2) another_domain = domains.Domain(domains.DomainManager, domain_dict_3) TEST.domains.add(domain, disabled_domain, another_domain) TEST.domain = domain # Your "current" domain user_dict = {'id': "1", 'name': 'test_user', 'description': 'test_description', 'email': 'test@example.com', 'password': 'password', 'token': 'test_token', 'project_id': '1', 'enabled': True, 'domain_id': "1"} user = users.User(None, user_dict) user_dict = {'id': "2", 'name': 'user_two', 'description': 'test_description', 'email': 'two@example.com', 'password': 'password', 'token': 'test_token', 'project_id': '1', 'enabled': True, 'domain_id': "1"} user2 = users.User(None, user_dict) user_dict = {'id': "3", 'name': 'user_three', 'description': 'test_description', 'email': 'three@example.com', 'password': 'password', 'token': 'test_token', 'project_id': '1', 'enabled': True, 'domain_id': "1"} user3 = users.User(None, user_dict) user_dict = {'id': "4", 'name': 'user_four', 'description': 'test_description', 'email': 'four@example.com', 'password': 'password', 'token': 'test_token', 'project_id': '2', 'enabled': True, 'domain_id': "2"} user4 = users.User(None, user_dict) user_dict = {'id': "5", 'name': 'user_five', 'description': 'test_description', 'email': None, 'password': 'password', 'token': 'test_token', 'project_id': '2', 'enabled': True, 'domain_id': "1"} user5 = users.User(None, user_dict) TEST.users.add(user, user2, user3, user4, user5) TEST.user = user # Your "current" user TEST.user.service_catalog = copy.deepcopy(SERVICE_CATALOG) tenant_dict = {'id': "1", 'name': 'test_tenant', 'description': "a test tenant.", 'enabled': True, 'domain_id': '1', 'domain_name': 'test_domain'} tenant_dict_2 = {'id': "2", 'name': 'disabled_tenant', 'description': "a disabled test tenant.", 'enabled': False, 'domain_id': '2', 'domain_name': 'disabled_domain'} tenant_dict_3 = {'id': "3", 'name': u'\u4e91\u89c4\u5219', 'description': "an unicode-named tenant.", 'enabled': True, 'domain_id': '2', 'domain_name': 'disabled_domain'} tenant = tenants.Tenant(tenants.TenantManager, tenant_dict) disabled_tenant = tenants.Tenant(tenants.TenantManager, tenant_dict_2) tenant_unicode = tenants.Tenant(tenants.TenantManager, tenant_dict_3) TEST.tenants.add(tenant, disabled_tenant, tenant_unicode) TEST.tenant = tenant # Your "current" tenant tomorrow = datetime_safe.datetime.now() + timedelta(days=1) expiration = tomorrow.isoformat() scoped_token_dict = { 'access': { 'token': { 'id': "test_token_id", 'expires': expiration, 'tenant': tenant_dict, 'tenants': [tenant_dict]}, 'user': { 'id': "test_user_id", 'name': "test_user", 'roles': [member_role_dict]}, 'serviceCatalog': TEST.service_catalog } } scoped_access_info = access.AccessInfo.factory(resp=None, body=scoped_token_dict) unscoped_token_dict = { 'access': { 'token': { 'id': "test_token_id", 'expires': expiration}, 'user': { 'id': "test_user_id", 'name': "test_user", 'roles': [member_role_dict]}, 'serviceCatalog': TEST.service_catalog } } unscoped_access_info = access.AccessInfo.factory(resp=None, body=unscoped_token_dict) scoped_token = auth_user.Token(scoped_access_info) unscoped_token = auth_user.Token(unscoped_access_info) TEST.tokens.add(scoped_token, unscoped_token) TEST.token = scoped_token # your "current" token. TEST.tokens.scoped_token = scoped_token TEST.tokens.unscoped_token = unscoped_token idp_dict_1 = {'id': 'idp_1', 'description': 'identity provider 1', 'enabled': True, 'remote_ids': ['rid_1', 'rid_2']} idp_1 = identity_providers.IdentityProvider( identity_providers.IdentityProviderManager, idp_dict_1, loaded=True) idp_dict_2 = {'id': 'idp_2', 'description': 'identity provider 2', 'enabled': True, 'remote_ids': ['rid_3', 'rid_4']} idp_2 = identity_providers.IdentityProvider( identity_providers.IdentityProviderManager, idp_dict_2, loaded=True) TEST.identity_providers.add(idp_1, idp_2) idp_mapping_dict = { "id": "mapping_1", "rules": [ { "local": [ { "user": { "name": "{0}" } }, { "group": { "id": "0cd5e9" } } ], "remote": [ { "type": "UserName" }, { "type": "orgPersonType", "not_any_of": [ "Contractor", "Guest" ] } ] } ] } idp_mapping = mappings.Mapping( mappings.MappingManager(None), idp_mapping_dict) TEST.idp_mappings.add(idp_mapping) idp_protocol_dict_1 = {'id': 'protocol_1', 'mapping_id': 'mapping_1'} idp_protocol = protocols.Protocol( protocols.ProtocolManager, idp_protocol_dict_1, loaded=True) TEST.idp_protocols.add(idp_protocol) heat-dashboard-1.0.2/heat_dashboard/test/test_data/glance_data.py0000666000175100017510000003713013240544407025070 0ustar zuulzuul00000000000000# Copyright 2012 Nebula, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from glanceclient.v1 import images from openstack_dashboard import api from heat_dashboard.test.test_data import utils class Namespace(dict): def __repr__(self): return "" % self._info def __init__(self, info): super(Namespace, self).__init__() self.__dict__.update(info) self.update(info) self._info = info def as_json(self, indent=4): return self.__dict__ class APIResourceV2(dict): _base_props = [ 'id', 'name', 'status', 'visibility', 'protected', 'checksum', 'owner', 'size', 'virtual_size', 'container_format', 'disk_format', 'created_at', 'updated_at', 'tags', 'direct_url', 'min_ram', 'min_disk', 'self', 'file', 'schema', 'locations'] def __getattr__(self, item): if item == 'schema': return {'properties': {k: '' for k in self._base_props}} else: return self.get(item) def data(TEST): TEST.images = utils.TestDataContainer() TEST.images_api = utils.TestDataContainer() TEST.snapshots = utils.TestDataContainer() TEST.metadata_defs = utils.TestDataContainer() TEST.imagesV2 = utils.TestDataContainer() # Snapshots snapshot_dict = {'name': u'snapshot', 'container_format': u'ami', 'id': 3, 'status': "active", 'owner': TEST.tenant.id, 'properties': {'image_type': u'snapshot'}, 'is_public': False, 'protected': False} snapshot_dict_no_owner = {'name': u'snapshot 2', 'container_format': u'ami', 'id': 4, 'status': "active", 'owner': None, 'properties': {'image_type': u'snapshot'}, 'is_public': False, 'protected': False} snapshot_dict_queued = {'name': u'snapshot 2', 'container_format': u'ami', 'id': 5, 'status': "queued", 'owner': TEST.tenant.id, 'properties': {'image_type': u'snapshot'}, 'is_public': False, 'protected': False} snapshot = images.Image(images.ImageManager(None), snapshot_dict) TEST.snapshots.add(api.glance.Image(snapshot)) snapshot = images.Image(images.ImageManager(None), snapshot_dict_no_owner) TEST.snapshots.add(api.glance.Image(snapshot)) snapshot = images.Image(images.ImageManager(None), snapshot_dict_queued) TEST.snapshots.add(api.glance.Image(snapshot)) # Images image_dict = {'id': '007e7d55-fe1e-4c5c-bf08-44b4a4964822', 'name': 'public_image', 'disk_format': u'qcow2', 'status': "active", 'size': 20 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': TEST.tenant.id, 'container_format': 'novaImage', 'properties': {'image_type': u'image'}, 'is_public': True, 'protected': False, 'min_ram': 0, 'created_at': '2014-02-14T20:56:53'} public_image = images.Image(images.ImageManager(None), image_dict) image_dict = {'id': 'a001c047-22f8-47d0-80a1-8ec94a9524fe', 'name': 'private_image', 'status': "active", 'size': 10 * 1024 ** 2, 'virtual_size': 20 * 1024 ** 2, 'min_disk': 0, 'owner': TEST.tenant.id, 'container_format': 'aki', 'is_public': False, 'protected': False, 'min_ram': 0, 'created_at': '2014-03-14T12:56:53'} private_image = images.Image(images.ImageManager(None), image_dict) image_dict = {'id': 'd6936c86-7fec-474a-85c5-5e467b371c3c', 'name': 'protected_images', 'status': "active", 'owner': TEST.tenant.id, 'size': 2 * 1024 ** 3, 'virtual_size': None, 'min_disk': 30, 'container_format': 'novaImage', 'properties': {'image_type': u'image'}, 'is_public': True, 'protected': True, 'min_ram': 0, 'created_at': '2014-03-16T06:22:14'} protected_image = images.Image(images.ImageManager(None), image_dict) image_dict = {'id': '278905a6-4b52-4d1e-98f9-8c57bb25ba32', 'name': None, 'status': "active", 'size': 5 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': TEST.tenant.id, 'container_format': 'novaImage', 'properties': {'image_type': u'image'}, 'is_public': True, 'protected': False, 'min_ram': 0} public_image2 = images.Image(images.ImageManager(None), image_dict) image_dict = {'id': '710a1acf-a3e3-41dd-a32d-5d6b6c86ea10', 'name': 'private_image 2', 'status': "active", 'size': 30 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': TEST.tenant.id, 'container_format': 'aki', 'is_public': False, 'protected': False, 'min_ram': 0} private_image2 = images.Image(images.ImageManager(None), image_dict) image_dict = {'id': '7cd892fd-5652-40f3-a450-547615680132', 'name': 'private_image 3', 'status': "active", 'size': 2 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': TEST.tenant.id, 'container_format': 'aki', 'is_public': False, 'protected': False, 'min_ram': 0} private_image3 = images.Image(images.ImageManager(None), image_dict) # A shared image. Not public and not local tenant. image_dict = {'id': 'c8756975-7a3b-4e43-b7f7-433576112849', 'name': 'shared_image 1', 'status': "active", 'size': 8 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': 'someothertenant', 'container_format': 'aki', 'is_public': False, 'protected': False, 'min_ram': 0} shared_image1 = images.Image(images.ImageManager(None), image_dict) # "Official" image. Public and tenant matches an entry # in IMAGES_LIST_FILTER_TENANTS. image_dict = {'id': 'f448704f-0ce5-4d34-8441-11b6581c6619', 'name': 'official_image 1', 'status': "active", 'size': 2 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': 'officialtenant', 'container_format': 'aki', 'is_public': True, 'protected': False, 'min_ram': 0} official_image1 = images.Image(images.ImageManager(None), image_dict) image_dict = {'id': 'a67e7d45-fe1e-4c5c-bf08-44b4a4964822', 'name': 'multi_prop_image', 'status': "active", 'size': 20 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': TEST.tenant.id, 'container_format': 'novaImage', 'properties': {'description': u'a multi prop image', 'foo': u'foo val', 'bar': u'bar val'}, 'is_public': True, 'protected': False} multi_prop_image = images.Image(images.ImageManager(None), image_dict) # An image without name being returned based on current api image_dict = {'id': 'c8756975-7a3b-4e43-b7f7-433576112849', 'status': "active", 'size': 8 * 1024 ** 3, 'virtual_size': None, 'min_disk': 0, 'owner': 'someothertenant', 'container_format': 'aki', 'is_public': False, 'protected': False} no_name_image = images.Image(images.ImageManager(None), image_dict) TEST.images_api.add(public_image, private_image, protected_image, public_image2, private_image2, private_image3, shared_image1, official_image1, multi_prop_image) TEST.images.add(api.glance.Image(public_image), api.glance.Image(private_image), api.glance.Image(protected_image), api.glance.Image(public_image2), api.glance.Image(private_image2), api.glance.Image(private_image3), api.glance.Image(shared_image1), api.glance.Image(official_image1), api.glance.Image(multi_prop_image)) TEST.empty_name_image = api.glance.Image(no_name_image) image_v2_dicts = [{ 'checksum': 'eb9139e4942121f22bbc2afc0400b2a4', 'container_format': 'novaImage', 'created_at': '2014-02-14T20:56:53', 'direct_url': 'swift+config://ref1/glance/' 'da8500d5-8b80-4b9c-8410-cc57fb8fb9d5', 'disk_format': u'qcow2', 'file': '/v2/images/' 'da8500d5-8b80-4b9c-8410-cc57fb8fb9d5/file', 'id': '007e7d55-fe1e-4c5c-bf08-44b4a4964822', 'kernel_id': 'f6ebd5f0-b110-4406-8c1e-67b28d4e85e7', 'locations': [ {'metadata': {}, 'url': 'swift+config://ref1/glance/' 'da8500d5-8b80-4b9c-8410-cc57fb8fb9d5'}], 'min_ram': 0, 'name': 'public_image', 'image_type': u'image', 'min_disk': 0, 'owner': TEST.tenant.id, 'protected': False, 'ramdisk_id': '868efefc-4f2d-4ed8-82b1-7e35576a7a47', 'size': 20 * 1024 ** 3, 'status': 'active', 'tags': ['active_image'], 'updated_at': '2015-08-31T19:37:45Z', 'virtual_size': None, 'visibility': 'public' }, { 'checksum': None, 'container_format': 'novaImage', 'created_at': '2014-03-16T06:22:14', 'disk_format': None, 'image_type': u'image', 'file': '/v2/images/885d1cb0-9f5c-4677-9d03-175be7f9f984/file', 'id': 'd6936c86-7fec-474a-85c5-5e467b371c3c', 'locations': [], 'min_disk': 30, 'min_ram': 0, 'name': 'protected_images', 'owner': TEST.tenant.id, 'protected': True, 'size': 2 * 1024 ** 3, 'status': "active", 'tags': ['empty_image'], 'updated_at': '2015-09-01T22:37:32Z', 'virtual_size': None, 'visibility': 'public' }, { 'checksum': 'e533283e6aac072533d1d091a7d2e413', 'container_format': 'novaImage', 'created_at': '2015-09-02T00:31:16Z', 'disk_format': 'qcow2', 'file': '/v2/images/10ca6b6b-48f4-43ac-8159-aa9e9353f5e4/file', 'id': 'a67e7d45-fe1e-4c5c-bf08-44b4a4964822', 'image_type': 'an image type', 'min_disk': 0, 'min_ram': 0, 'name': 'multi_prop_image', 'owner': TEST.tenant.id, 'protected': False, 'size': 20 * 1024 ** 3, 'status': 'active', 'tags': ['custom_property_image'], 'updated_at': '2015-09-02T00:31:17Z', 'virtual_size': None, 'visibility': 'public', 'description': u'a multi prop image', 'foo': u'foo val', 'bar': u'bar val' }] for fixture in image_v2_dicts: apiresource = APIResourceV2(fixture) TEST.imagesV2.add(api.glance.Image(apiresource)) metadef_dict = { 'namespace': 'namespace_1', 'display_name': 'Namespace 1', 'description': 'Mock desc 1', 'resource_type_associations': [ { 'created_at': '2014-08-21T08:39:43Z', 'prefix': 'mock', 'name': 'mock name' } ], 'visibility': 'public', 'protected': True, 'created_at': '2014-08-21T08:39:43Z', 'properties': { 'cpu_mock:mock': { 'default': '1', 'type': 'integer', 'description': 'Number of mocks.', 'title': 'mocks' } } } metadef = Namespace(metadef_dict) TEST.metadata_defs.add(metadef) metadef_dict = { 'namespace': 'namespace_2', 'display_name': 'Namespace 2', 'description': 'Mock desc 2', 'resource_type_associations': [ { 'created_at': '2014-08-21T08:39:43Z', 'prefix': 'mock', 'name': 'mock name' } ], 'visibility': 'private', 'protected': False, 'created_at': '2014-08-21T08:39:43Z', 'properties': { 'hdd_mock:mock': { 'default': '2', 'type': 'integer', 'description': 'Number of mocks.', 'title': 'mocks' } } } metadef = Namespace(metadef_dict) TEST.metadata_defs.add(metadef) metadef_dict = { 'namespace': 'namespace_3', 'display_name': 'Namespace 3', 'description': 'Mock desc 3', 'resource_type_associations': [ { 'created_at': '2014-08-21T08:39:43Z', 'prefix': 'mock', 'name': 'mock name' } ], 'visibility': 'public', 'protected': False, 'created_at': '2014-08-21T08:39:43Z', 'properties': { 'gpu_mock:mock': { 'default': '2', 'type': 'integer', 'description': 'Number of mocks.', 'title': 'mocks' } } } metadef = Namespace(metadef_dict) TEST.metadata_defs.add(metadef) metadef_dict = { 'namespace': 'namespace_4', 'display_name': 'Namespace 4', 'description': 'Mock desc 4', 'resource_type_associations': [ { 'created_at': '2014-08-21T08:39:43Z', 'prefix': 'mock', 'name': 'OS::Cinder::Volume', 'properties_target': 'user' } ], 'visibility': 'public', 'protected': True, 'created_at': '2014-08-21T08:39:43Z', 'properties': { 'ram_mock:mock': { 'default': '2', 'type': 'integer', 'description': 'Number of mocks.', 'title': 'mocks' } } } metadef = Namespace(metadef_dict) TEST.metadata_defs.add(metadef) heat-dashboard-1.0.2/heat_dashboard/test/test_data/nova_data.py0000666000175100017510000001654213240544407024606 0ustar zuulzuul00000000000000# Copyright 2012 Nebula, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from novaclient.v2 import availability_zones from novaclient.v2 import flavors from novaclient.v2 import keypairs from novaclient.v2 import servers from heat_dashboard.test.test_data import utils class FlavorExtraSpecs(dict): def __repr__(self): return "" % self._info def __init__(self, info): super(FlavorExtraSpecs, self).__init__() self.__dict__.update(info) self.update(info) self._info = info SERVER_DATA = """ { "server": { "OS-EXT-SRV-ATTR:instance_name": "instance-00000005", "OS-EXT-SRV-ATTR:host": "instance-host", "OS-EXT-STS:task_state": null, "addresses": { "private": [ { "version": 4, "addr": "10.0.0.1" } ] }, "links": [ { "href": "%(host)s/v1.1/%(tenant_id)s/servers/%(server_id)s", "rel": "self" }, { "href": "%(host)s/%(tenant_id)s/servers/%(server_id)s", "rel": "bookmark" } ], "image": { "id": "%(image_id)s", "links": [ { "href": "%(host)s/%(tenant_id)s/images/%(image_id)s", "rel": "bookmark" } ] }, "OS-EXT-STS:vm_state": "active", "flavor": { "id": "%(flavor_id)s", "links": [ { "href": "%(host)s/%(tenant_id)s/flavors/%(flavor_id)s", "rel": "bookmark" } ] }, "id": "%(server_id)s", "user_id": "%(user_id)s", "OS-DCF:diskConfig": "MANUAL", "accessIPv4": "", "accessIPv6": "", "progress": null, "OS-EXT-STS:power_state": 1, "config_drive": "", "status": "%(status)s", "updated": "2012-02-28T19:51:27Z", "hostId": "c461ea283faa0ab5d777073c93b126c68139e4e45934d4fc37e403c2", "key_name": "%(key_name)s", "name": "%(name)s", "created": "2012-02-28T19:51:17Z", "tenant_id": "%(tenant_id)s", "metadata": {"someMetaLabel": "someMetaData", "somehtmllabel": "
{$ dtype.name $} {$ diskbus.name $}
{$ eformat.name $} Delete On Termination
{$ source.name $}
{$ image.name $} {$ vol.name $} {$ volss.name $}
{$ alloc_net.name $} network subnet port floating_ip
{$ nw.name $} {$ subnet.name $} {$ port.name $} {$ fip.id $}
Please input a valid IP address.
Show Password
{$ fup.name $} (Default) {$ iup.name $} (Default)
That doesn't look like a valid uuid.
Config Drive {$ dc.name $} (Default) {$ udf.name $} (Default) {$ sct.name $} (Default) {$ udup.name $} (Default)
././@LongLink0000000000000000000000000000022600000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-red.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000400113240544407033776 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022700000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-blue.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000400113240544407033776 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022600000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.spec.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000003175013240544407034011 0ustar zuulzuul00000000000000(function() { 'use strict'; describe('component os-nova-server', function(){ beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); beforeEach(module('appTemplates')); var $scope, $isolateScope, $compile; var hotgenGlobals, hotgenUtils; var element; beforeEach(inject(function($injector) { $scope = $injector.get('$rootScope').$new(); $compile = $injector.get('$compile'); hotgenGlobals = $injector.get('hotgenGlobals'); hotgenUtils = $injector.get('hotgenUtils'); hotgenGlobals.update_resource_options({ networks: [{id: 'network1-id', name: 'network1-id'}], subnets: [{id: 'subnet1-id', name: 'subnet1-id'}], ports: [{id: 'port1-id', name: 'port1-id'}], volumes: [{id: 'volume1-id', name: 'volume1-id'}], floatingips: [{id: 'ipaddress', name: 'ipaddress'}], security_groups: [{id: 'secgroup-id1', name: 'secgroup-id1'}], keypairs: [{id: 'keyname1', name: 'keyname1'}], }); $scope.resource = {}; $scope.dependson = []; $scope.connectedoptions = []; $scope.resourceForm = {}; // element will enable you to test your directive's element on the DOM element = $compile(angular.element(''))($scope); // Digest needs to be called to set any values on the directive's scope $scope.$digest(); $isolateScope = element.isolateScope(); })); it('find tab title Properties', function() { expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with no connectedoptions set', function() { element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with connectedoptions set', function(){ $scope.resource = {image: 'image-id', key_name: 'keyname', security_groups: ['secgroup-01'], block_device_mapping_v2: [ {volume_id: '{ get_resource: vol01 }'}, {image: 'image-id'}, {image: '{ get_resource: image01 }'}, {snapshot_id: 'snapshot-id'}, {ignore: 'ignore'} ], networks: [{network: '{ get_resource: network01 }'}, {subnet: '{ get_resource: subnet01 }'}, {port: '{ get_resource: port01 }'}, {floating_ip: '{ get_resource: floatingip01 }'}, {ignore: 'ignore'} ], } $scope.connectedoptions = { 'networks.network': [{value: 'network-id'}, {value: '{ get_resource: network01 }'}], 'networks.subnet': [{value: 'subnet-id'}, {value: '{ get_resource: subnet01 }'}], 'networks.port': [{value: 'port-id'}, {value: '{ get_resource: port01 }'}], 'networks.floating_ip': [{value: 'floatingip'}, {value: '{ get_resource: floatingip01 }'}], key_name: 'keyname', security_groups: [{value: 'secgroup-id'}], 'block_device_mapping_v2.volume_id': [{value: 'volume-id'}, {value: '{ get_resource: vol01 }'}], } element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); $isolateScope.update_boot_source(); for (var i in $scope.resource.block_device_mapping_v2){ $isolateScope.update_source(i); } for (var i in $scope.resource.networks){ $isolateScope.update_nwconfig(i); } expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with connectedoptions set with error', function(){ $scope.resource = {image: 'image-id', key_name: 'keyname', security_groups: ['secgroup-01'], block_device_mapping_v2: [ {volume_id: '{ get_resource: vol01 }'}, {image: 'image-id'}, {image: '{ get_resource: image01 }'}, {snapshot_id: 'snapshot-id'}, {ignore: 'ignore'} ], networks: [{network: '{ get_resource: network01 }'}, {subnet: '{ get_resource: subnet01 }'}, {port: '{ get_resource: port01 }'}, {floating_ip: '{ get_resource: floatingip01 }'} ], } $scope.connectedoptions = { 'networks.network': [{value: 'network-id'}, {value: '{ get_resource: network01 }'}], 'networks.subnet': [{value: 'subnet-id'}, {value: '{ get_resource: subnet01 }'}], 'networks.port': [{value: 'port-id'}, {value: '{ get_resource: port01 }'}], 'networks.floating_ip': [{value: 'floatingip'}, {value: '{ get_resource: floatingip01 }'}], key_name: 'keyname', security_groups: [{value: 'secgroup-id'}], 'block_device_mapping_v2.volume_id': [{value: 'volume-id'}, {value: '{ get_resource: vol01 }'}], } spyOn(hotgenUtils, 'filter_and_return_get_resource_element').and.callFake(function(){ return [{}] }); element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with boot from image snapshot', function(){ $scope.resource = {image_snapshot: 'image-id'} element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); $isolateScope.update_boot_source(); expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with boot from volume ', function(){ $scope.resource = {volume: 'vol-id'} element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); $isolateScope.update_boot_source(); expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with boot from volume snapshot', function(){ $scope.resource = {volume_snapshot: 'vol-id'} element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); $isolateScope.update_boot_source(); expect(element.find('span').html()).toContain("Basic"); }); it('find tab title with boot from nothing ', function(){ $scope.resource = {ignore: 'nothing'} element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); $isolateScope.update_boot_source(); expect(element.find('span').html()).toContain("Basic"); }); it('$scope.show_passwd should be successfully watched', function() { $isolateScope.show_passwd = true; $isolateScope.$digest(); expect($isolateScope.show_passwd_type).toEqual('text'); $isolateScope.show_passwd = false; $isolateScope.$digest(); expect($isolateScope.show_passwd_type).toEqual('password'); }); it('metadata should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_metadata(); expect($scope.resource.metadata.length).toEqual(2); }); it('metadata should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.delete_metadata(); expect($scope.resource.metadata.length).toEqual(0); }); it('personality should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_personality(); expect($scope.resource.personality.length).toEqual(2); }); it('personality should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.delete_personality(); expect($scope.resource.personality.length).toEqual(0); }); it('block_device_mapping should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_block_device_mapping(); expect($scope.resource.block_device_mapping.length).toEqual(1); }); it('block_device_mapping should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_block_device_mapping(); $ctrl.delete_block_device_mapping(0); expect($scope.resource.block_device_mapping.length).toEqual(0); }); it('block_device_mapping_v2 should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_block_device_mapping_v2(); expect($scope.resource.block_device_mapping_v2.length).toEqual(1); }); it('block_device_mapping_v2 should be successfully deleted', function() { $scope.resource = {block_device_mapping_v2: [{volume_id: 'vol-01'}]} element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); var $ctrl = $isolateScope.$ctrl; $ctrl.delete_block_device_mapping_v2(0); expect($scope.resource.block_device_mapping_v2.length).toEqual(0); }); it('networks should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_networks(); expect($scope.resource.networks.length).toEqual(1); }); it('networks should be successfully deleted', function() { $scope.resource = {networks: [{network: 'network-01'}]}; element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); var $ctrl = $isolateScope.$ctrl; $ctrl.delete_networks(0); expect($scope.resource.networks.length).toEqual(0); }); it('scheduler_hints should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_scheduler_hints(); expect($scope.resource.scheduler_hints.length).toEqual(2); }); it('scheduler_hints should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.delete_scheduler_hints(); expect($scope.resource.scheduler_hints.length).toEqual(0); }); }); })(); ././@LongLink0000000000000000000000000000023000000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-green.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000377513240544407034017 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022200000000000011211 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000377513240544407034017 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022700000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server-gray.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000377313240544407034015 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022100000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000006510013240544407034005 0ustar zuulzuul00000000000000(function(angular) { 'use strict'; // OS::Nova::Server angular.module('horizon.dashboard.project.heat_dashboard.template_generator').value('osNovaServerSettings', { resource_key: "OS__Nova__Server", admin: false, icon: { class: 'fa-desktop ', name: 'OS::Nova::Server', code: '\uf108', color: '#483dff' }, label: 'name', modal_component: '', edge_settings: { 'OS__Cinder__Volume': { 'type': 'property', 'property': 'block_device_mapping_v2.volume_id', 'limit': 99, 'occupied': true, 'lonely': true, }, 'OS__Nova__KeyPair': { 'type': 'property', 'property': 'key_name', 'limit': 1, }, 'OS__Neutron__Net': { 'type': 'property', 'property': 'networks.network', 'limit': 99, }, 'OS__Neutron__FloatingIP': { 'type': 'property', 'property': 'networks.floating_ip', 'limit': 99, }, 'OS__Neutron__Subnet': { 'type': 'property', 'property': 'networks.subnet', 'limit': 99, }, 'OS__Neutron__Port': { 'type': 'property', 'property': 'networks.port', 'limit': 99, }, 'OS__Neutron__SecurityGroup': { 'type': 'property', 'property': 'security_groups', 'limit': 99, }, }, necessary_properties: { 'flavor': null } } ); angular.module('horizon.dashboard.project.heat_dashboard.template_generator') .run(['osNovaServerSettings', 'hotgenGlobals', function(osNovaServerSettings, hotgenGlobals){ hotgenGlobals.update_resource_icons( osNovaServerSettings.resource_key, osNovaServerSettings.icon); hotgenGlobals.update_node_labels( osNovaServerSettings.resource_key, osNovaServerSettings.label); hotgenGlobals.update_resource_components( osNovaServerSettings.resource_key, osNovaServerSettings.modal_component); // for (var i in osNovaServerSettings.edge_settings){ // if (osNovaServerSettings.edge_settings[i].modal){ // hotgenGlobals.update_resource_components( // osNovaServerSettings.resource_key+'_'+i, // osNovaServerSettings.edge_settings[i].modal); // } // } hotgenGlobals.update_edge_directions( osNovaServerSettings.resource_key, osNovaServerSettings.edge_settings); }]); function osNovaServerController($scope, hotgenGlobals, hotgenNotify, hotgenUtils, validationRules) { this.$onInit = function(){ if (typeof this.connectedoptions === 'undefined'){ $scope.connected_options = [] } else{ $scope.connected_options = this.connectedoptions; } if (typeof this.instance.metadata === 'undefined'){ this.instance.metadata = [{}]; } if (typeof this.instance.tags === 'undefined'){ this.instance.tags = []; } if (typeof this.instance.scheduler_hints === 'undefined'){ this.instance.scheduler_hints = [{}]; } if (typeof this.instance.personality === 'undefined'){ this.instance.personality = [{}]; } if (typeof this.instance.block_device_mapping === 'undefined'){ this.instance.block_device_mapping = []; } if (typeof this.instance.security_groups === 'undefined'){ this.instance.security_groups = []; } if (typeof this.instance.block_device_mapping_v2 === 'undefined'){ this.instance.block_device_mapping_v2 = []; } if (typeof this.instance.networks === 'undefined'){ this.instance.networks = []; } this.disable = { 'key_name': false, 'security_groups': [], 'block_device_mapping_v2.volume_id': [], 'networks': {}, } if (this.instance.image){ $scope.boot_source = 'image'; } else if (this.instance.image_snapshot){ $scope.boot_source = 'image_snapshot'; } else if (this.instance.volume){ $scope.boot_source = 'volume'; } else if (this.instance.volume_snapshot){ $scope.boot_source = 'volume_snapshot'; } if ( $scope.connected_options.key_name && $scope.connected_options.key_name.length > 0){ this.instance['key_name'] = $scope.connected_options.key_name[0].value; this.disable.key_name = true; } var old_array = hotgenUtils.filter_and_return_get_resource_element(this.instance['security_groups']); if ( $scope.connected_options.security_groups && $scope.connected_options.security_groups.length > 0){ for (var idx in $scope.connected_options.security_groups){ this.instance['security_groups'].push($scope.connected_options.security_groups[idx].value); this.disable.security_groups.push($scope.connected_options.security_groups[idx].value); } } var old_array = hotgenUtils.filter_and_return_get_resource_element(this.instance['block_device_mapping_v2'], 'volume_id'); var exist_volume_map = {} for (var idx in old_array){ if (old_array[idx].volume_id && old_array[idx].volume_id.length > 0 ){ exist_volume_map[old_array[idx].volume_id] = old_array[idx]; } } this.disable.length = 0; $scope.bdpv2_source = {}; if ( $scope.connected_options['block_device_mapping_v2.volume_id'] && $scope.connected_options['block_device_mapping_v2.volume_id'].length > 0){ for (var idx in $scope.connected_options['block_device_mapping_v2.volume_id']){ var connected_vol_id = $scope.connected_options['block_device_mapping_v2.volume_id'][idx].value; var item = exist_volume_map[connected_vol_id]; if (item == null){ item = {volume_id: connected_vol_id} } this.instance.block_device_mapping_v2.push(item); this.disable['block_device_mapping_v2.volume_id'].push(connected_vol_id); } } for (var idx in this.instance.block_device_mapping_v2){ var disk = this.instance.block_device_mapping_v2[idx]; var source = ''; if (disk.volume_id && disk.volume_id != '') { source = 'volume'; } else if (disk.image && disk.image != '') { source = 'image'; } else if (disk.snapshot_id && disk.snapshot_id != '') { source = 'volume_snapshot'; } $scope.bdpv2_source[idx.toString()] = source; } var old_net_array = hotgenUtils.filter_and_return_get_resource_element(this.instance['networks'], 'network'); var exist_network_map = {} for (var idx in old_net_array){ if (old_net_array[idx].network && old_net_array[idx].network.length > 0 ){ exist_network_map[old_net_array[idx].network] = old_net_array[idx]; } } var old_subnet_array = hotgenUtils.filter_and_return_get_resource_element(this.instance['networks'], 'subnet'); var exist_subnet_map = {} for (var idx in old_subnet_array){ if (old_subnet_array[idx].subnet && old_subnet_array[idx].subnet.length > 0 ){ exist_subnet_map[old_subnet_array[idx].subnet] = old_subnet_array[idx]; } } var old_port_array = hotgenUtils.filter_and_return_get_resource_element(this.instance['networks'], 'port'); var exist_port_map = {} for (var idx in old_port_array){ if (old_port_array[idx].port && old_port_array[idx].port.length > 0 ){ exist_port_map[old_port_array[idx].port] = old_port_array[idx]; } } var old_fip_array = hotgenUtils.filter_and_return_get_resource_element(this.instance['networks'], 'floating_ip'); var exist_fip_map = {} for (var idx in old_fip_array){ if (old_fip_array[idx].floating_ip && old_fip_array[idx].floating_ip.length > 0 ){ exist_fip_map[old_fip_array[idx].floating_ip] = old_fip_array[idx]; } } if ( $scope.connected_options['networks.network'] && $scope.connected_options['networks.network'].length > 0){ for (var idx in $scope.connected_options['networks.network']){ var connected_nw_id = $scope.connected_options['networks.network'][idx].value; var item = exist_network_map[connected_nw_id]; if (item == null){ item = {network: connected_nw_id} } this.disable.networks[this.instance.networks.length.toString()] = true; $scope.how2config_networks[this.instance.networks.length.toString()] = 'network'; this.instance.networks.push(item); } } if ( $scope.connected_options['networks.subnet'] && $scope.connected_options['networks.subnet'].length > 0){ for (var idx in $scope.connected_options['networks.subnet']){ var connected_subnet_id = $scope.connected_options['networks.subnet'][idx].value; var item = exist_subnet_map[connected_subnet_id]; if (item == null){ item = {subnet: connected_subnet_id} } this.disable.networks[this.instance.networks.length] = true; $scope.how2config_networks[this.instance.networks.length.toString()] = 'subnet'; this.instance.networks.push(item); } } if ( $scope.connected_options['networks.port'] && $scope.connected_options['networks.port'].length > 0){ for (var idx in $scope.connected_options['networks.port']){ var connected_port_id = $scope.connected_options['networks.port'][idx].value; var item = exist_port_map[connected_port_id]; if (item == null){ item = {port: connected_port_id} } this.disable.networks[this.instance.networks.length] = true; $scope.how2config_networks[this.instance.networks.length.toString()] = 'port'; this.instance.networks.push(item); } } if ( $scope.connected_options['networks.floating_ip'] && $scope.connected_options['networks.floating_ip'].length > 0){ for (var idx in $scope.connected_options['networks.floating_ip']){ var connected_fip_id = $scope.connected_options['networks.floating_ip'][idx].value; var item = exist_fip_map[connected_fip_id]; if (item == null){ item = {floating_ip: connected_fip_id} } this.disable.networks[this.instance.networks.length] = true; $scope.how2config_networks[this.instance.networks.length.toString()] = 'floating_ip'; this.instance.networks.push(item); } } for (var idx in this.instance.networks){ var netconfig = this.instance.networks[idx]; var source = ''; if (netconfig.network && netconfig.network != '') { source = 'network'; } else if (netconfig.subnet && netconfig.subnet != '') { source = 'subnet'; } else if (netconfig.port && netconfig.port != '') { source = 'port'; } else if (netconfig.floating_ip && netconfig.floating_ip != '') { source = 'floating_ip'; } $scope.how2config_networks[idx.toString()] = source; } $scope.update = { keypairs: $scope.get_keypairs_options(), networks: $scope.get_networks_options(), subnets: $scope.get_subnets_options(), floatingips: $scope.get_floatingips_options(), ports: $scope.get_ports_options(), security_groups: $scope.get_security_groups_options(), volumes: $scope.get_volumes_options(), } $scope.dependson = this.dependson; } $scope.show_passwd = false; $scope.show_passwd_type = "password"; $scope.bdpv2_source = {}; // Mark the source selected of every block_device_mapping_v2 item. $scope.how2config_networks = {} $scope.update_boot_source = function(){ if ($scope.boot_source == 'image'){ this.$ctrl.instance.image_snapshot = null; this.$ctrl.instance.volume = null; this.$ctrl.instance.volume_snapshot = null; } else if ($scope.boot_source == 'image_snapshot'){ this.$ctrl.instance.image = null; this.$ctrl.instance.volume = null; this.$ctrl.instance.volume_snapshot = null; } else if ($scope.boot_source == 'volume'){ this.$ctrl.instance.image = null; this.$ctrl.instance.image_snapshot = null; this.$ctrl.instance.volume_snapshot = null; } else if ($scope.boot_source == 'volume_snapshot'){ this.$ctrl.instance.image = null; this.$ctrl.instance.image_snapshot = null; this.$ctrl.instance.volume = null; } } $scope.update_source = function (index) { if ($scope.bdpv2_source[index] == 'volume'){ this.$ctrl.instance.block_device_mapping_v2[index].image = null; this.$ctrl.instance.block_device_mapping_v2[index].snapshot_id = null; } else if ($scope.bdpv2_source[index] == 'volume_snapshot'){ this.$ctrl.instance.block_device_mapping_v2[index].volume_id = null; this.$ctrl.instance.block_device_mapping_v2[index].image = null; } else if ($scope.bdpv2_source[index] == 'image'){ this.$ctrl.instance.block_device_mapping_v2[index].volume_id = null; this.$ctrl.instance.block_device_mapping_v2[index].snapshot_id = null; } } $scope.update_nwconfig = function (index) { if ($scope.how2config_networks[index] == 'network'){ this.$ctrl.instance.networks[index].subnet = null; this.$ctrl.instance.networks[index].port = null; this.$ctrl.instance.networks[index].floating_ip = null; } else if ($scope.how2config_networks[index] == 'subnet'){ this.$ctrl.instance.networks[index].network = null; this.$ctrl.instance.networks[index].port = null; this.$ctrl.instance.networks[index].floating_ip = null; } else if ($scope.how2config_networks[index] == 'port'){ this.$ctrl.instance.networks[index].subnet = null; this.$ctrl.instance.networks[index].network = null; this.$ctrl.instance.networks[index].floating_ip = null; } else if ($scope.how2config_networks[index] == 'floating_ip'){ this.$ctrl.instance.networks[index].subnet = null; this.$ctrl.instance.networks[index].port = null; this.$ctrl.instance.networks[index].network = null; } } $scope.$watch("show_passwd", function(newValue, oldValue) { $scope.show_passwd_type = $scope.show_passwd ? "text" : "password"; }); $scope.options = hotgenGlobals.get_resource_options(); $scope.get_security_groups_options = function(){ if ('security_groups' in $scope.connected_options){ var resource_secgroups = []; for (var idx in $scope.connected_options.security_groups){ var item = $scope.connected_options.security_groups[idx]; resource_secgroups.push({ id: item.value, name: item.value }) } return $scope.options.security_groups.concat(resource_secgroups); } return $scope.options.security_groups; } $scope.get_volumes_options = function(){ if ('block_device_mapping_v2.volume_id' in $scope.connected_options){ var resource_volumes = []; for (var idx in $scope.connected_options['block_device_mapping_v2.volume_id']){ var item = $scope.connected_options['block_device_mapping_v2.volume_id'][idx]; resource_volumes.push({ id: item.value, name: item.value }) } return $scope.options.volumes.concat(resource_volumes); } return $scope.options.volumes; } $scope.get_keypairs_options = function(){ if ('key_name' in $scope.connected_options){ var resource_keypair = []; for (var idx in $scope.connected_options.key_name){ var item = $scope.connected_options.key_name[idx]; resource_keypair.push({ name: item.value }) } return $scope.options.keypairs.concat(resource_keypair); } return $scope.options.keypairs; } $scope.get_networks_options = function(){ if ('networks.network' in $scope.connected_options){ var resource_nw = []; for (var idx in $scope.connected_options['networks.network']){ var item = $scope.connected_options['networks.network'][idx]; resource_nw.push({ id: item.value, name: item.value }) } return $scope.options.networks.concat(resource_nw); } return $scope.options.networks; } $scope.get_subnets_options = function(){ if ('networks.subnet' in $scope.connected_options){ var resource_subnet = []; for (var idx in $scope.connected_options['networks.subnet']){ var item = $scope.connected_options['networks.subnet'][idx]; resource_subnet.push({ id: item.value, name: item.value }) } return $scope.options.subnets.concat(resource_subnet); } return $scope.options.subnets; } $scope.get_floatingips_options = function(){ if ('networks.floating_ip' in $scope.connected_options){ var resource_fip = []; for (var idx in $scope.connected_options['networks.floating_ip']){ var item = $scope.connected_options['networks.floating_ip'][idx]; resource_fip.push({ id: item.value, }) } return $scope.options.floatingips.concat(resource_fip); } return $scope.options.floatingips; } $scope.get_ports_options = function(){ if ('networks.port' in $scope.connected_options){ var resource_port = []; for (var idx in $scope.connected_options['networks.port']){ var item = $scope.connected_options['networks.port'][idx]; resource_port.push({ id: item.value, name: item.value }) } return $scope.options.ports.concat(resource_port); } return $scope.options.ports; } $scope.block_device_mapping_v2 = true; $scope.deployment_swift_data = {}; $scope.show_more = false; $scope.options.boot_sources = [ {'id': 'image', 'name': 'image'}, {'id': 'image_snapshot', 'name': 'image snapshot'}, {'id': 'volume', 'name': 'volume'}, {'id': 'volume_snapshot', 'name': 'volume snapshot'} ]; $scope.options.volume_sources = [ {'id': 'volume', 'name': 'volume'}, {'id': 'volume_snapshot', 'name': 'volume snapshot'} ]; $scope.options.volume_sources_v2 = [ {'id': 'image', 'name': 'image'}, {'id': 'volume', 'name': 'volume'}, {'id': 'volume_snapshot', 'name': 'volume snapshot'} ]; $scope.options.flavor_update_policies = [ {'name': 'RESIZE', 'default': true}, {'name': 'REPLACE'}, ]; $scope.options.image_update_policies = [ {'name': 'REBUILD', 'default': true}, {'name': 'REPLACE'}, {'name': 'REBUILD_PRESERVE_EPHEMERAL'}, ]; $scope.options.disk_configs = [ {'name': 'AUTO', 'default': true}, {'name': 'MANUAL'}, ]; $scope.options.software_config_transports = [ {'name': 'POLL_SERVER_CFN', 'default': true}, {'name': 'POLL_SERVER_HEAT'}, {'name': 'POLL_TEMP_URL'}, {'name': 'ZAQAR_MESSAGE'}, ]; $scope.options.user_data_update_policies = [ {'name': 'REPLACE', 'default': true}, {'name': 'IGNORE'}, ]; $scope.options.user_data_formats = [ {'name': 'HEAT_CFNTOOLS', 'default': true}, {'name': 'RAW'}, {'name': 'SOFTWARE_CONFIG'} ]; $scope.options.disk_types = [ {'name': 'disk'}, {'name': 'cdrom'}, ] $scope.options.disk_buses = [ {'name': 'ide'}, {'name': 'lame_bus'}, {'name': 'scsi'}, {'name': 'usb'}, {'name': 'virtio'}, ]; $scope.options.ephemeral_formats = [ {'name': 'ext2'}, {'name': 'ext3'}, {'name': 'ext4'}, {'name': 'xfs'}, {'name': 'ntfs'}, ]; $scope.options.allocate_networks = [{'name': 'none'}, {'name': 'auto'}]; $scope.validate_name = validationRules['name']; $scope.validate_ip_address = validationRules['ip_address']; $scope.validate_uuid4 = validationRules['uuid4']; this.delete_metadata = function(index){ this.instance.metadata.splice(index, 1) } this.add_metadata = function(){ this.instance.metadata.push({}) } this.delete_personality = function(index){ this.instance.personality.splice(index, 1) } this.add_personality = function(){ this.instance.personality.push({}) } this.delete_block_device_mapping = function(index){ this.instance.block_device_mapping.splice(index, 1) } this.add_block_device_mapping = function(){ this.instance.block_device_mapping.push({}) } this.delete_block_device_mapping_v2 = function(index){ for (var i = index; i <= this.instance.block_device_mapping_v2.length; i=i+1){ $scope.bdpv2_source[i] = $scope.bdpv2_source[i+1]; } this.instance.block_device_mapping_v2.splice(index, 1) } this.add_block_device_mapping_v2 = function(){ this.instance.block_device_mapping_v2.push({}) } this.delete_networks = function(index){ for (var i = index; i < this.instance.networks.length; i=i+1){ $scope.how2config_networks[i] = $scope.how2config_networks[i+1]; } delete $scope.how2config_networks[this.instance.networks.length]; this.instance.networks.splice(index, 1); for (var i = index; i < this.instance.networks.length; i=i+1){ this.disable.networks[i] = this.disable.networks[i+1]; } delete this.disable.networks[this.instance.networks.length]; } this.add_networks = function(){ this.instance.networks.push({}) } this.delete_scheduler_hints = function(index){ this.instance.scheduler_hints.splice(index, 1) } this.add_scheduler_hints= function(){ this.instance.scheduler_hints.push({}) } } osNovaServerController.$inject = ['$scope', 'hotgenGlobals', 'hotgenNotify', 'hotgenUtils', 'horizon.dashboard.project.heat_dashboard.template_generator.validationRules', ]; osNovaServerPath.$inject = ['horizon.dashboard.project.heat_dashboard.template_generator.basePath']; function osNovaServerPath(basePath){ return basePath + 'js/resources/os__nova__server/os__nova__server.html'; } angular.module('horizon.dashboard.project.heat_dashboard.template_generator').component('osNovaServer', { templateUrl: osNovaServerPath, controller: osNovaServerController, bindings:{ 'instance': '=', 'dependson': '=', 'connectedoptions': '<', 'formReference': '<', } }); })(window.angular); ././@LongLink0000000000000000000000000000017700000000000011222 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000775000175100017510000000000013240545010033766 5ustar zuulzuul00000000000000././@LongLink0000000000000000000000000000023000000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-red.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000611713240544407034010 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000023200000000000011212 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-green.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000611313240544407034004 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022500000000000011214 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.htmlheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000570713240544407034014 0ustar zuulzuul00000000000000
You must supply a name.
That doesn't look like a valid name.
Too long name.
That doesn't look like a valid public key.
Too long name.
save private key
That doesn't look like a valid user.
././@LongLink0000000000000000000000000000023000000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.spec.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000230213240544407034000 0ustar zuulzuul00000000000000(function() { 'use strict'; describe('component os-nova-keypair', function(){ beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); beforeEach(module('appTemplates')); var $scope, $isolateScope, $compile; var hotgenGlobals; var element; beforeEach(inject(function($injector) { $scope = $injector.get('$rootScope').$new(); $compile = $injector.get('$compile'); $scope.resource = {}; $scope.dependson = []; $scope.resourceForm = {}; // element will enable you to test your directive's element on the DOM element = $compile(angular.element(''+ ''))($scope); // Digest needs to be called to set any values on the directive's scope $scope.$digest(); $isolateScope = element.isolateScope(); })); it('find tab title Properties', function() { expect(element.find('span').html()).toContain("Properties"); }); }); })(); ././@LongLink0000000000000000000000000000022300000000000011212 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000526413240544407034012 0ustar zuulzuul00000000000000(function(angular) { 'use strict'; // OS::Nova::KeyPair angular.module('horizon.dashboard.project.heat_dashboard.template_generator').value('osNovaKeypairSettings', { resource_key: "OS__Nova__KeyPair", admin: false, icon: { class: 'fa-key ', name: 'OS::Nova::KeyPair', code: '\uf084', color: '#483dff' }, label: 'name', outputs: [ {'property': 'private_key', } ], modal_component: '', edge_settings: null, necessary_properties: { 'name': null }, } ); angular.module('horizon.dashboard.project.heat_dashboard.template_generator') .run(['osNovaKeypairSettings', 'hotgenGlobals', function( osNovaKeypairSettings, hotgenGlobals){ hotgenGlobals.update_resource_icons( osNovaKeypairSettings.resource_key, osNovaKeypairSettings.icon); hotgenGlobals.update_resource_components( osNovaKeypairSettings.resource_key, osNovaKeypairSettings.modal_component); hotgenGlobals.update_node_labels( osNovaKeypairSettings.resource_key, osNovaKeypairSettings.label); hotgenGlobals.set_resource_outputs( osNovaKeypairSettings.resource_key, osNovaKeypairSettings.outputs); }]); function osNovaKeypairController($scope, hotgenGlobals, validationRules){ $scope.options = hotgenGlobals.get_resource_options(); $scope.admin = $scope.options.auth.admin; this.$onInit = function(){ $scope.dependson = this.dependson; } $scope.validate_name = validationRules['name']; $scope.validate_keypair = validationRules['keypair']; } osNovaKeypairController.$inject = ['$scope', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.validationRules', ]; osNovaKeypairPath.$inject = ['horizon.dashboard.project.heat_dashboard.template_generator.basePath']; function osNovaKeypairPath(basePath){ return basePath + 'js/resources/os__nova__keypair/os__nova__keypair.html'; } angular.module('horizon.dashboard.project.heat_dashboard.template_generator').component('osNovaKeypair', { templateUrl: osNovaKeypairPath, controller: osNovaKeypairController, bindings:{ 'keypair': '=', 'dependson': '=', 'formReference': '<', } }); })(window.angular); ././@LongLink0000000000000000000000000000023100000000000011211 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-blue.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000612013240544407034002 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000022400000000000011213 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000611313240544407034004 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000023100000000000011211 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair-gray.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000612013240544407034002 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000017600000000000011221 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000775000175100017510000000000013240545010033766 5ustar zuulzuul00000000000000././@LongLink0000000000000000000000000000022600000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.spec.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000417113240544407034006 0ustar zuulzuul00000000000000(function() { 'use strict'; describe('component os-neutron-net', function(){ beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); beforeEach(module('appTemplates')); var $scope, $isolateScope, $compile; var element; beforeEach(inject(function($injector) { $scope = $injector.get('$rootScope').$new(); $compile = $injector.get('$compile'); $scope.resource = {}; $scope.dependson = []; $scope.resourceForm = {}; // element will enable you to test your directive's element on the DOM element = $compile(angular.element(''+ ''))($scope); // Digest needs to be called to set any values on the directive's scope $scope.$digest(); $isolateScope = element.isolateScope(); })); it('find tab title Properties', function() { expect(element.find('span').html()).toContain("Properties"); }); it('find tab title Properties with resource properties set', function() { $scope.resource = { tags: [], dhcp_agent_ids: [], admin_state_up: true, value_specs: []}; element = $compile(angular.element(''+ ''))($scope); $scope.$digest(); expect(element.find('span').html()).toContain("Properties"); }); it('value_spec should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_value_specs(); expect($scope.resource.value_specs.length).toEqual(2); }); it('value_spec should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.delete_value_specs(); expect($scope.resource.value_specs.length).toEqual(0); }); }); })(); ././@LongLink0000000000000000000000000000023000000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-green.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000300213240544407033776 0ustar zuulzuul00000000000000 Layer 1././@LongLink0000000000000000000000000000022600000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-red.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000300613240544407034002 0ustar zuulzuul00000000000000 Layer 1././@LongLink0000000000000000000000000000022300000000000011212 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.htmlheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000001257113240544407034011 0ustar zuulzuul00000000000000
That doesn't look like a valid network name.
Too long network name.
Please input a valid DNS Domain.
Admin State UP Port Security Enabled Shared
{$ 'Show More Properties' | translate $}
{$ qos.name $} ({$ qos.id $})
That doesn't look like a valid tenant id.
././@LongLink0000000000000000000000000000022700000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-gray.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000300613240544407034002 0ustar zuulzuul00000000000000 Layer 1././@LongLink0000000000000000000000000000022200000000000011211 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000300213240544407033776 0ustar zuulzuul00000000000000 Layer 1././@LongLink0000000000000000000000000000022700000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net-blue.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000300613240544407034002 0ustar zuulzuul00000000000000 Layer 1././@LongLink0000000000000000000000000000022100000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000657313240544407034016 0ustar zuulzuul00000000000000(function(angular) { 'use strict'; // OS::Neutron::Net angular.module('horizon.dashboard.project.heat_dashboard.template_generator').value('osNeutronNetSettings', { resource_key: "OS__Neutron__Net", admin: false, icon: { class: 'fa-cloud', name: 'OS::Neutron::Net', code: '\uf0c2', color: '#40a5f2' }, label: 'name', modal_component: '', edge_settings: null, necessary_properties: null } ); angular.module('horizon.dashboard.project.heat_dashboard.template_generator') .run(['osNeutronNetSettings', 'hotgenGlobals', function(osNeutronNetSettings, hotgenGlobals){ hotgenGlobals.update_resource_icons( osNeutronNetSettings.resource_key, osNeutronNetSettings.icon); hotgenGlobals.update_resource_components( osNeutronNetSettings.resource_key, osNeutronNetSettings.modal_component); hotgenGlobals.update_edge_directions( osNeutronNetSettings.resource_key, osNeutronNetSettings.edge_settings); hotgenGlobals.update_node_labels( osNeutronNetSettings.resource_key, osNeutronNetSettings.label); }]); function osNeutronNetController($scope, hotgenGlobals, validationRules){ this.$onInit = function(){ this.admin = $scope.options.auth.admin; if (typeof this.network.tags == 'undefined'){ this.network.tags = [] } if (typeof this.network.dhcp_agent_ids === 'undefined'){ this.network.dhcp_agent_ids = []; } if (typeof this.network.admin_state_up === 'undefined'){ this.network.admin_state_up = true; } if (typeof this.network.value_specs == 'undefined'){ this.network.value_specs = [{}] } $scope.dependson = this.dependson; }; this.add_value_specs = function(){ this.network.value_specs.push({}) } this.delete_value_specs = function(index){ this.network.value_specs.splice(index, 1) } $scope.options = hotgenGlobals.get_resource_options(); $scope.qos_policies = $scope.options.qos_policies; $scope.show_more = false; $scope.validate_name = validationRules['name']; $scope.validate_domain = validationRules['domain']; $scope.validate_uuid_nohyphe = validationRules['uuid_nohyphen']; } osNeutronNetController.$inject = ['$scope', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.validationRules', ]; osNeutronNetPath.$inject = ['horizon.dashboard.project.heat_dashboard.template_generator.basePath']; function osNeutronNetPath(basePath){ return basePath + 'js/resources/os__neutron__net/os__neutron__net.html'; } angular.module('horizon.dashboard.project.heat_dashboard.template_generator').component('osNeutronNet', { templateUrl: osNeutronNetPath, controller: osNeutronNetController, bindings:{ 'network': '=', 'dependson': '=', 'formReference': '<', } }); })(window.angular); ././@LongLink0000000000000000000000000000020100000000000011206 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000775000175100017510000000000013240545010033766 5ustar zuulzuul00000000000000././@LongLink0000000000000000000000000000023100000000000011211 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.htmlheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000001440513240544407034007 0ustar zuulzuul00000000000000
That doesn't look like a valid network name.
Too long network name.
{$ nw.name $}
That doesn't look like a valid ip address.
{$ subnet.name $}
Admin State UP Enable SNAT
{$ 'Show More Properties' | translate $}
Distributed HA
././@LongLink0000000000000000000000000000022700000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000001552713240544407034015 0ustar zuulzuul00000000000000(function(angular) { 'use strict'; // OS::Neutron::Router angular.module('horizon.dashboard.project.heat_dashboard.template_generator').value('osNeutronRouterSettings', { resource_key: "OS__Neutron__Router", // admin: true, icon: { class: 'fa-life-bouy', name: 'OS::Neutron::Router', code: '\uf1cd', color: '#40a5f2' }, label: 'name', modal_component: '', edge_settings: { 'OS__Neutron__Subnet': { 'type': 'property', 'property': 'ext_fixed_ips.subnet', 'limit': 99, }, 'OS__Neutron__Net': { 'type': 'property', 'property': 'external_gateway_info.network', 'limit': 1, }, }, necessary_properties: null } ); angular.module('horizon.dashboard.project.heat_dashboard.template_generator') .run(['osNeutronRouterSettings', 'hotgenGlobals', function(osNeutronRouterSettings, hotgenGlobals){ hotgenGlobals.update_resource_icons( osNeutronRouterSettings.resource_key, osNeutronRouterSettings.icon); hotgenGlobals.update_node_admin( osNeutronRouterSettings.resource_key, osNeutronRouterSettings.admin); hotgenGlobals.update_resource_components( osNeutronRouterSettings.resource_key, osNeutronRouterSettings.modal_component); hotgenGlobals.update_edge_directions( osNeutronRouterSettings.resource_key, osNeutronRouterSettings.edge_settings); hotgenGlobals.update_node_labels( osNeutronRouterSettings.resource_key, osNeutronRouterSettings.label); }]); function osNeutronRouterController($scope, hotgenGlobals, validationRules) { this.$onInit = function(){ if (typeof this.connectedoptions === 'undefined'){ $scope.connected_options = [] } else{ $scope.connected_options = this.connectedoptions; } if (typeof this.router.external_gateway_info === 'undefined'){ this.router.external_gateway_info = {"external_fixed_ips": [{}]}; } if (typeof this.router.l3_agent_ids === 'undefined'){ this.router.l3_agent_ids = []; } if (typeof this.router.tags == 'undefined'){ this.router.tags = [] } if (typeof this.router.admin_state_up === 'undefined'){ this.router.admin_state_up = true; } if (typeof this.router.value_specs == 'undefined'){ this.router.value_specs = [{}] } this.disable = { 'subnets': [], 'network': false, } if ( $scope.connected_options['ext_fixed_ips.subnet'] && $scope.connected_options['ext_fixed_ips.subnet'].length > 0){ for (var idx in $scope.connected_options['ext_fixed_ips.subnet']){ this.router.external_gateway_info.external_fixed_ips.splice(0,0, {subnet: $scope.connected_options['ext_fixed_ips.subnet'][idx].value}); this.disable.subnets.push($scope.connected_options['ext_fixed_ips.subnet'][idx].value); } } if ( $scope.connected_options['external_gateway_info.network'] && $scope.connected_options['external_gateway_info.network'].length > 0){ this.router.external_gateway_info['network'] = $scope.connected_options['external_gateway_info.network'][0].value; this.disable.network = true } $scope.update = {subnets: $scope.get_subnets_options(), networks: $scope.get_networks_options()} $scope.dependson = this.dependson; }; $scope.options = hotgenGlobals.get_resource_options(); $scope.show_more = false; $scope.validate_name = validationRules['name']; $scope.validate_ip_address = validationRules['ip_address']; this.add_external_fixed_ip = function(){ this.router.external_gateway_info.external_fixed_ips.push({}) } this.delete_external_fixed_ip = function(index){ this.router.external_gateway_info.external_fixed_ips.splice(index, 1) } this.add_value_specs = function(){ this.router.value_specs.push({}) } this.delete_value_specs = function(index){ this.router.value_specs.splice(index, 1) } $scope.get_networks_options = function(){ if ('external_gateway_info.network' in $scope.connected_options){ var resource_networks = []; for (var idx in $scope.connected_options['external_gateway_info.network']){ var item = $scope.connected_options['external_gateway_info.network'][idx]; resource_networks.push({ id: item.value, name: item.value }) } return $scope.options.networks.concat(resource_networks); } return $scope.options.networks; } $scope.get_subnets_options = function(){ if ('ext_fixed_ips.subnet' in $scope.connected_options){ var resource_subnets = []; for (var idx in $scope.connected_options['ext_fixed_ips.subnet']){ var item = $scope.connected_options['ext_fixed_ips.subnet'][idx]; resource_subnets.push({ id: item.value, name: item.value }) } return $scope.options.subnets.concat(resource_subnets); } return $scope.options.subnets; } } osNeutronRouterController.$inject = ['$scope', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.validationRules', ]; osNeutronRouterPath.$inject = ['horizon.dashboard.project.heat_dashboard.template_generator.basePath']; function osNeutronRouterPath(basePath){ return basePath + 'js/resources/os__neutron__router/os__neutron__router.html'; } angular.module('horizon.dashboard.project.heat_dashboard.template_generator').component('osNeutronRouter', { templateUrl: osNeutronRouterPath, controller: osNeutronRouterController, bindings:{ 'router': '=', 'dependson': '=', 'connectedoptions': '<', 'formReference': '<', } }); })(window.angular); ././@LongLink0000000000000000000000000000023500000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-blue.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000251213240544407034003 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000023400000000000011214 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.spec.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000752313240544407034012 0ustar zuulzuul00000000000000(function() { 'use strict'; describe('component os-neutron-router', function(){ beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); beforeEach(module('appTemplates')); var $scope, $isolateScope, $compile; var hotgenGlobals; var element; beforeEach(inject(function($injector) { $scope = $injector.get('$rootScope').$new(); $compile = $injector.get('$compile'); hotgenGlobals = $injector.get('hotgenGlobals'); hotgenGlobals.update_resource_options({ networks: [{id: 'network1-id', name: 'network1-id'}], subnets: [{id: 'subnet1-id', name: 'subnet-id'}] }); $scope.resource = {}; $scope.dependson = []; $scope.connectedoptions = []; $scope.resourceForm = {}; // element will enable you to test your directive's element on the DOM element = $compile(angular.element(''))($scope); // Digest needs to be called to set any values on the directive's scope $scope.$digest(); $isolateScope = element.isolateScope(); })); it('find tab title Properties', function() { expect(element.find('span').html()).toContain("Properties"); }); it('find tab title with no connectedoptions set', function() { element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); expect(element.find('span').html()).toContain("Properties"); }); it('find tab title with connectedoptions set', function(){ $scope.resource = {'external_gateway_info.network': 'network-id', 'ext_fixed_ips.subnet': ['subnet-id'],} $scope.connectedoptions = {'external_gateway_info.network': [{value: 'network-id'}], 'ext_fixed_ips.subnet': [{value: 'subnet-id'}], }; element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); expect(element.find('span').html()).toContain("Properties"); }); it('value_spec should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_value_specs(); expect($scope.resource.value_specs.length).toEqual(2); }); it('value_spec should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.delete_value_specs(); expect($scope.resource.value_specs.length).toEqual(0); }); it('external_fixed_ip should be successfully added', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.add_external_fixed_ip(); expect($scope.resource.external_gateway_info.external_fixed_ips.length).toEqual(2); }); it('external_fixed_ip should be successfully deleted', function() { var $ctrl = $isolateScope.$ctrl; $ctrl.delete_external_fixed_ip(); expect($scope.resource.external_gateway_info.external_fixed_ips.length).toEqual(0); }); }); })(); ././@LongLink0000000000000000000000000000023400000000000011214 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-red.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000251213240544407034003 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000023500000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-gray.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000251213240544407034003 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000023600000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router-green.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000250613240544407034006 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000023000000000000011210 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000250613240544407034006 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000020500000000000011212 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000775000175100017510000000000013240545010033766 5ustar zuulzuul00000000000000././@LongLink0000000000000000000000000000024500000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-blue.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000421213240544407034002 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000024100000000000011212 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.htmlheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000001215013240544407034002 0ustar zuulzuul00000000000000 {$ fnet.name $}
You must supply an floating network.
Please input a valid IP address.
Please input a valid IP address.
{$ 'Show More Properties' | translate $}
{$ fsubnet.name $} {$ port.name $}
Please input a valid DNS Domain.
Please input a valid DNS Name.
././@LongLink0000000000000000000000000000024400000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-red.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000421213240544407034002 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000024600000000000011217 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-green.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000420613240544407034005 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000024400000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.spec.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000707313240544407034012 0ustar zuulzuul00000000000000(function() { 'use strict'; describe('component os-neutron-floatingip', function(){ beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); beforeEach(module('appTemplates')); var $scope, $isolateScope, $compile; var hotgenGlobals; var element; beforeEach(inject(function($injector) { $scope = $injector.get('$rootScope').$new(); $compile = $injector.get('$compile'); hotgenGlobals = $injector.get('hotgenGlobals'); hotgenGlobals.update_resource_options({ floating_networks: [{id: 'floating-network1-id', name: 'floating-network1-id'}], floating_subnets: [{id: 'floating-subnet1-id', name: 'floating-subnet1-id'}], ports: [{id: 'port1-id', name: 'port1-id'}], }); $scope.resource = {}; $scope.dependson = []; $scope.connectedoptions = []; $scope.resourceForm = {}; // element will enable you to test your directive's element on the DOM element = $compile(angular.element(''))($scope); // Digest needs to be called to set any values on the directive's scope $scope.$digest(); $isolateScope = element.isolateScope(); })); it('find tab title Properties', function() { expect(element.find('span').html()).toContain("Properties"); }); it('find tab title with no connectedoptions set', function() { element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); expect(element.find('span').html()).toContain("Properties"); }); it('find tab title with connectedoptions set', function() { $scope.resource = {floating_network: 'floating-network-id', floating_subnet: 'floating-subnet-id', port_id: 'port_id'} $scope.connectedoptions = {floating_network: [{value: 'floating-network-id'}], floating_subnet: [{value: 'floating-subnet-id'}], port_id: [{value: 'port-id'}], }; element = $compile(angular.element(''))($scope); $scope.$digest(); $isolateScope = element.isolateScope(); expect(element.find('span').html()).toContain("Properties"); }); it('value_spec should be successfully added', function() { var $ctrl = element.isolateScope().$ctrl; $ctrl.add_value_specs(); expect($scope.resource.value_specs.length).toEqual(2); }); it('value_spec should be successfully deleted', function() { var $ctrl = element.isolateScope().$ctrl; $ctrl.delete_value_specs(); expect($scope.resource.value_specs.length).toEqual(0); }); }); })(); ././@LongLink0000000000000000000000000000023700000000000011217 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000001574113240544407034013 0ustar zuulzuul00000000000000(function(angular) { 'use strict'; /* OS::Neutron::FloatingIP */ angular.module('horizon.dashboard.project.heat_dashboard.template_generator').value('osNeutronFloatingipSettings', { resource_key: "OS__Neutron__FloatingIP", admin: false, icon: { class: 'fa-neuter', name: 'OS::Neutron::FloatingIP', code: '\uf22c', color: '#40a5f2' }, label: 'floating_ip_address', modal_component: '', edge_settings: { 'OS__Neutron__Net': { 'type': 'property', 'property': 'floating_network', 'limit': 1, }, 'OS__Neutron__Port': { 'type': 'property', 'property': 'port_id', 'limit': 1, }, 'OS__Neutron__Subnet': { 'type': 'property', 'property': 'floating_subnet', 'limit': 1, }, }, necessary_properties: { 'floating_network': ['OS__Neutron__Net'] }, } ) angular.module('horizon.dashboard.project.heat_dashboard.template_generator') .run(['osNeutronFloatingipSettings', 'hotgenGlobals', function(osNeutronFloatingipSettings, hotgenGlobals){ hotgenGlobals.update_node_labels( osNeutronFloatingipSettings.resource_key, osNeutronFloatingipSettings.label); hotgenGlobals.update_resource_icons( osNeutronFloatingipSettings.resource_key, osNeutronFloatingipSettings.icon); hotgenGlobals.update_resource_components( osNeutronFloatingipSettings.resource_key, osNeutronFloatingipSettings.modal_component); hotgenGlobals.update_edge_directions( osNeutronFloatingipSettings.resource_key, osNeutronFloatingipSettings.edge_settings); }]); function osNeutronFloatingipController($scope, hotgenGlobals, validationRules){ this.$onInit = function(){ if (typeof this.connectedoptions === 'undefined'){ $scope.connected_options = [] } else{ $scope.connected_options = this.connectedoptions; } $scope.dependson = this.dependson; this.disable = { 'floating_network': false, 'floating_subnet': false, 'port_id': false } $scope.update = { floating_networks: $scope.get_floating_network_options(), floating_subnets: $scope.get_floating_subnet_options(), ports: $scope.get_port_options(), } if (typeof this.floatingip.value_specs == 'undefined'){ this.floatingip.value_specs = [{}] } if ( $scope.connected_options.floating_network && $scope.connected_options.floating_network.length > 0){ this.floatingip['floating_network'] = $scope.connected_options.floating_network[0].value this.disable.floating_network = true } if ( $scope.connected_options.floating_subnet && $scope.connected_options.floating_subnet.length > 0){ this.floatingip['floating_subnet'] = $scope.connected_options.floating_subnet[0].value this.disable.floating_subnet = true } if ( $scope.connected_options.port_id && $scope.connected_options.port_id.length > 0){ this.floatingip['port_id'] = $scope.connected_options.port_id[0].value this.disable.port_id = true } } $scope.show_more = false; $scope.validate_ip_address = validationRules['ip_address']; $scope.options = hotgenGlobals.get_resource_options(); this.add_value_specs = function(){ this.floatingip.value_specs.push({}) } this.delete_value_specs = function(index){ this.floatingip.value_specs.splice(index, 1) } $scope.get_floating_network_options = function(){ if ('floating_network' in $scope.connected_options){ var resource_floating_network = []; for (var idx in $scope.connected_options.floating_network){ var item = $scope.connected_options.floating_network[idx]; resource_floating_network.push({ id: item.value, name: item.value }) } return $scope.options.floating_networks.concat(resource_floating_network); } return $scope.options.floating_networks; } $scope.get_floating_subnet_options = function(){ if ('floating_subnet' in $scope.connected_options){ var resource_floating_subnet = []; for (var idx in $scope.connected_options.floating_subnet){ var item = $scope.connected_options.floating_subnet[idx]; resource_floating_subnet.push({ id: item.value, name: item.value }) } return $scope.options.floating_subnets.concat(resource_floating_subnet); } return $scope.options.floating_subnets; } $scope.get_port_options = function(){ if ('port_id' in $scope.connected_options){ var resource_port = []; for (var idx in $scope.connected_options.port_id){ var item = $scope.connected_options.port_id[idx]; resource_port.push({ id: item.value, name: item.value }) } return $scope.options.ports.concat(resource_port); } return $scope.options.ports; } } osNeutronFloatingipController.$inject = ['$scope', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.validationRules', ]; osNeutronFloatingipPath.$inject = ['horizon.dashboard.project.heat_dashboard.template_generator.basePath']; function osNeutronFloatingipPath(basePath){ return basePath + 'js/resources/os__neutron__floatingip/os__neutron__floatingip.html'; } angular.module('horizon.dashboard.project.heat_dashboard.template_generator') .component('osNeutronFloatingip', { templateUrl: osNeutronFloatingipPath, controller: osNeutronFloatingipController, bindings:{ 'floatingip': '=', 'dependson': '=', 'formReference': '<', 'connectedoptions': '<', } }); })(window.angular); ././@LongLink0000000000000000000000000000024500000000000011216 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip-gray.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000421213240544407034002 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000024000000000000011211 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.svgheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/re0000666000175100017510000000420613240544407034005 0ustar zuulzuul00000000000000 Layer 1 ././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/ve0000775000175100017510000000000013240545010033772 5ustar zuulzuul00000000000000././@LongLink0000000000000000000000000000020100000000000011206 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-animate.min.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/ve0000666000175100017510000006216513240544407034021 0ustar zuulzuul00000000000000/* AngularJS v1.5.8 (c) 2010-2016 Google, Inc. http://angularjs.org License: MIT */ (function(R,B){'use strict';function Da(a,b,c){if(!a)throw Ma("areq",b||"?",c||"required");return a}function Ea(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;Y(a)&&(a=a.join(" "));Y(b)&&(b=b.join(" "));return a+" "+b}function Na(a){var b={};a&&(a.to||a.from)&&(b.to=a.to,b.from=a.from);return b}function Z(a,b,c){var d="";a=Y(a)?a:a&&G(a)&&a.length?a.split(/\s+/):[];s(a,function(a,l){a&&0=a&&(a=e,e=0,b.push(k),k=[]);k.push(g.fn);g.children.forEach(function(a){e++;c.push(a)});a--}k.length&&b.push(k);return b}(c)}var u=[],C=V(a);return function(n,Q,t){function H(a){a= a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];s(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function T(a){var b=[],c={};s(a,function(a,d){var h=y(a.element),e=0<=["enter","move"].indexOf(a.event),h=a.structural?H(h):[];if(h.length){var k=e?"to":"from";s(h,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][k]={animationID:d,element:F(a)}})}else b.push(a)});var d={},e={};s(c,function(c,k){var r=c.from, p=c.to;if(r&&p){var z=a[r.animationID],g=a[p.animationID],A=r.animationID.toString();if(!e[A]){var n=e[A]={structural:!0,beforeStart:function(){z.beforeStart();g.beforeStart()},close:function(){z.close();g.close()},classes:O(z.classes,g.classes),from:z,to:g,anchors:[]};n.classes.length?b.push(n):(b.push(z),b.push(g))}e[A].anchors.push({out:r.element,"in":p.element})}else r=r?r.animationID:p.animationID,p=r.toString(),d[p]||(d[p]=!0,b.push(a[r]))});return b}function O(a,b){a=a.split(" ");b=b.split(" "); for(var c=[],d=0;d=R&&b>=m&&(F=!0,k())}function N(){function b(){if(!w){M(!1);s(x,function(a){h.style[a[0]]=a[1]});T(a,f);e.addClass(a,ea);if(q.recalculateTimingStyles){na= h.className+" "+ga;ia=B(h,na);D=H(h,na,ia);ca=D.maxDelay;J=Math.max(ca,0);m=D.maxDuration;if(0===m){k();return}q.hasTransitions=0l.expectedEndTime)?n.cancel(l.timer):g.push(k)}N&&(p=n(c,p,!1),g[0]={timer:p,expectedEndTime:d},g.push(k),a.data("$$animateCss",g));if(fa.length)a.on(fa.join(" "),z);f.to&&(f.cleanupStyles&&Ka(A,h,Object.keys(f.to)),Ga(a,f))}}function c(){var b=a.data("$$animateCss");if(b){for(var d=1;d0)for(var q=n.length+1-l,r=0;q>r;r++)n[r].$close();b.get(o.templateUrl,{cache:d}).then(function(b){var d=c(b.data)(p);if(d.bind("webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",function(a){("opacity"===a.propertyName||0===a.currentTarget.style.opacity||a.originalEvent&&"opacity"===a.originalEvent.propertyName)&&(d.remove(),m.splice(m.indexOf(d),1),n.splice(n.indexOf(p),1),i())}),o.messageTemplate){for(var e,h=0;h=0;c--){var d=10,e=m[c],h=e[0].offsetHeight,i=b+h+d;e.attr("data-closing")?i+=20:b+=h+g,e.css("top",i+"px").css("margin-top","-"+(h+d)+"px").css("visibility","visible"),a++}};a(function(){i()}),o.duration>0&&a(function(){p.$close()},o.duration)},function(a){throw new Error("Template specified for cgNotify ("+o.templateUrl+") could not be loaded. "+a)});var s={};return s.close=function(){p.$close&&p.$close()},Object.defineProperty(s,"message",{get:function(){return p.$message},set:function(a){p.$message=a}}),n.push(p),s};return o.config=function(a){f=angular.isUndefined(a.startTop)?f:a.startTop,g=angular.isUndefined(a.verticalSpacing)?g:a.verticalSpacing,h=angular.isUndefined(a.duration)?h:a.duration,i=a.templateUrl?a.templateUrl:i,j=angular.isUndefined(a.position)?j:a.position,k=a.container?a.container:k,l=a.maximumOpen?a.maximumOpen:l},o.closeAll=function(){for(var a=m.length-1;a>=0;a--){var b=m[a];b.css("opacity",0)}},o}]),angular.module("cgNotify").run(["$templateCache",function(a){"use strict";a.put("angular-notify.html","
\n\n
\n {$ $message $}\n
\n\n"+'
\n \n
\n\n \n\n
')}]);././@LongLink0000000000000000000000000000017200000000000011215 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-uuid.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/ve0000666000175100017510000001751013240544407034013 0ustar zuulzuul00000000000000// angular-uuid created by Ivan Hayes @munkychop // MIT License - http://opensource.org/licenses/mit-license.php // -------------------------------------------------------------- // This is an AngularJS wrapper for the original node-uuid library // written by Robert Kieffer – https://github.com/broofa/node-uuid // MIT License - http://opensource.org/licenses/mit-license.php // The wrapped node-uuid library is at version 1.4.7 function AngularUUID () { 'use strict'; angular.module('angular-uuid',[]).factory('uuid', ['$window', nodeUUID]); function nodeUUID ($window) { // Unique ID creation requires a high quality random # generator. We feature // detect to determine the best RNG source, normalizing to a function that // returns 128-bits of randomness, since that's what's usually required var _rng, _mathRNG, _whatwgRNG; // Allow for MSIE11 msCrypto var _crypto = $window.crypto || $window.msCrypto; if (!_rng && _crypto && _crypto.getRandomValues) { // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto // // Moderately fast, high quality try { var _rnds8 = new Uint8Array(16); _whatwgRNG = _rng = function whatwgRNG() { _crypto.getRandomValues(_rnds8); return _rnds8; }; _rng(); } catch(e) {} } if (!_rng) { // Math.random()-based (RNG) // // If all else fails, use Math.random(). It's fast, but is of unspecified // quality. var _rnds = new Array(16); _mathRNG = _rng = function() { for (var i = 0, r; i < 16; i++) { if ((i & 0x03) === 0) { r = Math.random() * 0x100000000; } _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; } return _rnds; }; if ('undefined' !== typeof console && console.warn) { console.warn('[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()'); } } // Buffer class to use var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; // Maps for number <-> hex string conversion var _byteToHex = []; var _hexToByte = {}; for (var i = 0; i < 256; i++) { _byteToHex[i] = (i + 0x100).toString(16).substr(1); _hexToByte[_byteToHex[i]] = i; } // **`parse()` - Parse a UUID into it's component bytes** function parse(s, buf, offset) { var i = (buf && offset) || 0, ii = 0; buf = buf || []; s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) { if (ii < 16) { // Don't overflow! buf[i + ii++] = _hexToByte[oct]; } }); // Zero out remaining bytes if string was short while (ii < 16) { buf[i + ii++] = 0; } return buf; } // **`unparse()` - Convert UUID byte array (ala parse()) into a string** function unparse(buf, offset) { var i = offset || 0, bth = _byteToHex; return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; } // **`v1()` - Generate time-based UUID** // // Inspired by https://github.com/LiosK/UUID.js // and http://docs.python.org/library/uuid.html // random #'s we need to init node and clockseq var _seedBytes = _rng(); // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) var _nodeId = [ _seedBytes[0] | 0x01, _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5] ]; // Per 4.2.2, randomize (14 bit) clockseq var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; // Previous uuid creation time var _lastMSecs = 0, _lastNSecs = 0; // See https://github.com/broofa/node-uuid for API details function v1(options, buf, offset) { var i = buf && offset || 0; var b = buf || []; options = options || {}; var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; // UUID timestamps are 100 nano-second units since the Gregorian epoch, // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. var msecs = (options.msecs != null) ? options.msecs : new Date().getTime(); // Per 4.2.1.2, use count of uuid's generated during the current clock // cycle to simulate higher resolution clock var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000; // Per 4.2.1.2, Bump clockseq on clock regression if (dt < 0 && options.clockseq == null) { clockseq = clockseq + 1 & 0x3fff; } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new // time interval if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { nsecs = 0; } // Per 4.2.1.2 Throw error if too many uuids are requested if (nsecs >= 10000) { throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec'); } _lastMSecs = msecs; _lastNSecs = nsecs; _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch msecs += 12219292800000; // `time_low` var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; b[i++] = tl >>> 24 & 0xff; b[i++] = tl >>> 16 & 0xff; b[i++] = tl >>> 8 & 0xff; b[i++] = tl & 0xff; // `time_mid` var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; b[i++] = tmh >>> 8 & 0xff; b[i++] = tmh & 0xff; // `time_high_and_version` b[i++] = tmh >>> 24 & 0xf | 0x10; // include version b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` b[i++] = clockseq & 0xff; // `node` var node = options.node || _nodeId; for (var n = 0; n < 6; n++) { b[i + n] = node[n]; } return buf ? buf : unparse(b); } // **`v4()` - Generate random UUID** // See https://github.com/broofa/node-uuid for API details function v4(options, buf, offset) { // Deprecated - 'format' argument, as supported in v1.2 var i = buf && offset || 0; if (typeof(options) === 'string') { buf = (options === 'binary') ? new BufferClass(16) : null; options = null; } options = options || {}; var rnds = options.random || (options.rng || _rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` rnds[6] = (rnds[6] & 0x0f) | 0x40; rnds[8] = (rnds[8] & 0x3f) | 0x80; // Copy bytes to buffer, if provided if (buf) { for (var ii = 0; ii < 16; ii++) { buf[i + ii] = rnds[ii]; } } return buf || unparse(rnds); } // Export public API var uuid = v4; uuid.v1 = v1; uuid.v4 = v4; uuid.parse = parse; uuid.unparse = unparse; uuid.BufferClass = BufferClass; uuid._rng = _rng; uuid._mathRNG = _mathRNG; uuid._whatwgRNG = _whatwgRNG; return uuid; } } // check for Module/AMD support, otherwise call the uuid function to setup the angular module. if (typeof module !== 'undefined' && module.exports) { module.exports = new AngularUUID(); } else if (typeof define !== 'undefined' && define.amd) { // AMD. Register as an anonymous module. define (function() { return new AngularUUID(); }); } else { AngularUUID(); }././@LongLink0000000000000000000000000000020600000000000011213 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-messages.min.js.mapheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/ve0000666000175100017510000001767113240544407034023 0ustar zuulzuul00000000000000{ "version":3, "file":"angular-messages.min.js", "lineCount":11, "mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkB,CA6oB3BC,QAASA,EAAyB,EAAG,CACnC,MAAO,CAAC,UAAD,CAAa,QAAQ,CAACC,CAAD,CAAW,CACrC,MAAO,CACLC,SAAU,IADL,CAELC,WAAY,SAFP,CAGLC,SAAU,CAHL,CAILC,SAAU,CAAA,CAJL,CAKLC,QAAS,cALJ,CAMLC,KAAMA,QAAQ,CAACC,CAAD,CAAQC,CAAR,CAAiBC,CAAjB,CAAwBC,CAAxB,CAAwCC,CAAxC,CAAqD,CACjE,IAAIC,EAAcJ,CAAA,CAAQ,CAAR,CAAlB,CAEIK,CAFJ,CAGIC,EAAYL,CAAAM,UAAZD,EAA+BL,CAAAO,KAC/BC,EAAAA,CAAaR,CAAAS,aAAbD,EAAmCR,CAAAU,QACvC,KAAIC,EAAgBA,QAAQ,CAACC,CAAD,CAAQ,CAClCR,CAAA,CAAUQ,CAAA,CACHC,CAAA,CAAQD,CAAR,CAAA,CACGA,CADH,CAEGA,CAAAE,MAAA,CAAY,QAAZ,CAHA,CAIJ,IACNb,EAAAc,SAAA,EANkC,CAShCP,EAAJ,EACEG,CAAA,CAAcb,CAAAkB,MAAA,CAAYR,CAAZ,CAAd,CACA,CAAAV,CAAAmB,iBAAA,CAAuBT,CAAvB,CAAmCG,CAAnC,CAFF,EAIEA,CAAA,CAAcN,CAAd,CAnB+D,KAsB7Da,CAtB6D,CAsB7CC,CACpBlB,EAAAmB,SAAA,CAAwBjB,CAAxB,CAAqCgB,CAArC,CAAmD,CACjDE,KAAMA,QAAQ,CAACC,CAAD,CAAO,CACHlB,IAAAA,EAAAA,CAuCtB,EAAA,CADEmB,CAAJ,CACSV,CAAA,CAAQU,CAAR,CAAA,CAC0B,CAD1B,EACDA,CAAAC,QAAA,CAxCyBF,CAwCzB,CADC,CAEDC,CAAAE,eAAA,CAzCyBH,CAyCzB,CAHR,CADiC,IAAA,EArCzB,OAAO,EADY,CAD4B,CAIjDI,OAAQA,QAAQ,EAAG,CACZR,CAAL,EACEhB,CAAA,CAAY,QAAQ,CAACyB,CAAD;AAAMC,CAAN,CAAgB,CAClCrC,CAAAsC,MAAA,CAAeF,CAAf,CAAoB,IAApB,CAA0B5B,CAA1B,CACAmB,EAAA,CAAiBS,CAIjB,KAAIG,EAAaZ,CAAAY,WAAbA,CAAyC7B,CAAA8B,YAAA,EAK7Cb,EAAAc,GAAA,CAAkB,UAAlB,CAA8B,QAAQ,EAAG,CACnCd,CAAJ,EAAsBA,CAAAY,WAAtB,GAAoDA,CAApD,GACE7B,CAAAgC,WAAA,CAA0B9B,CAA1B,CACA,CAAAgB,CAAAe,OAAA,EAFF,CAIAN,EAAAO,SAAA,EALuC,CAAzC,CAXkC,CAApC,CAFe,CAJ8B,CA2BjDD,OAAQA,QAAQ,EAAG,CACjB,GAAIhB,CAAJ,CAAoB,CAClB,IAAIS,EAAMT,CACVA,EAAA,CAAiB,IACjB3B,EAAA6C,MAAA,CAAeT,CAAf,CAHkB,CADH,CA3B8B,CAAnD,CAvBiE,CAN9D,CAD8B,CAAhC,CAD4B,CA3oBrC,IAAIU,CAAJ,CACIxB,CADJ,CAEIyB,CAFJ,CAGIC,CAgQJlD,EAAAmD,OAAA,CAAe,YAAf,CAA6B,EAA7B,CAAiCC,QAA2B,EAAG,CAG7DJ,CAAA,CAAUhD,CAAAgD,QACVxB,EAAA,CAAUxB,CAAAwB,QACVyB,EAAA,CAAWjD,CAAAiD,SACXC,EAAA,CAASlD,CAAAU,QANoD,CAA/D,CAAA2C,UAAA,CAiFa,YAjFb,CAiF2B,CAAC,UAAD,CAAa,QAAQ,CAACnD,CAAD,CAAW,CAqKvDoD,QAASA,EAAY,CAAC7C,CAAD,CAAQ8C,CAAR,CAAc,CAClC,MAAQN,EAAA,CAASM,CAAT,CAAR,EAA0C,CAA1C,GAA0BA,CAAAC,OAA1B,EACOC,CAAA,CAAOhD,CAAAkB,MAAA,CAAY4B,CAAZ,CAAP,CAF2B,CAKnCE,QAASA,EAAM,CAACC,CAAD,CAAM,CACnB,MAAOT,EAAA,CAASS,CAAT,CAAA,CAAgBA,CAAAF,OAAhB,CAA6B,CAAEE,CAAAA,CADnB,CAtKrB,MAAO,CACLnD,QAAS,YADJ,CAELJ,SAAU,IAFL,CAGLwD,WAAY,CAAC,UAAD;AAAa,QAAb,CAAuB,QAAvB,CAAiC,QAAQ,CAACC,CAAD,CAAWC,CAAX,CAAmBC,CAAnB,CAA2B,CAyG9EC,QAASA,EAAmB,CAACC,CAAD,CAASC,CAAT,CAAkB,CAI5C,IAHA,IAAIC,EAAWD,CAAf,CACIE,EAAe,EAEnB,CAAOD,CAAP,EAAmBA,CAAnB,GAAgCF,CAAhC,CAAA,CAAwC,CACtC,IAAII,EAAUF,CAAAG,gBACd,IAAID,CAAJ,EAAeA,CAAAZ,OAAf,CACE,MAAOc,EAAA,CAASF,CAAT,CAKLF,EAAAK,WAAAf,OAAJ,EAAsE,EAAtE,GAAkCW,CAAAhC,QAAA,CAAqB+B,CAArB,CAAlC,EACEC,CAAAK,KAAA,CAAkBN,CAAlB,CACA,CAAAA,CAAA,CAAWA,CAAAK,WAAA,CAAoBL,CAAAK,WAAAf,OAApB,CAAiD,CAAjD,CAFb,EAGWU,CAAAO,gBAAJ,CACLP,CADK,CACMA,CAAAO,gBADN,EAGLP,CACA,CADWA,CAAAQ,WACX,CAAAP,CAAAK,KAAA,CAAkBN,CAAlB,CAJK,CAX+B,CAJI,CAxG9C,IAAIS,EAAO,IAAX,CACIC,EAAY,CADhB,CAEIC,EAAe,CAEnB,KAAAnC,YAAA,CAAmBoC,QAAoB,EAAG,CAAE,MAAOD,EAAA,EAAT,CAE1C,KAAIP,EAAW,IAAAA,SAAXA,CAA2B,EAA/B,CACIS,CADJ,CACiBC,CAEjB,KAAAC,OAAA,CAAcC,QAAQ,CAAChD,CAAD,CAAa,CACjCA,CAAA,CAAaA,CAAb,EAA2B,EAE3B6C,EAAA,CAAc,CAAA,CACdC,EAAA,CAAmB9C,CAanB,KAVA,IAAIiD,EAAW7B,CAAA,CAAaO,CAAb,CAAqBC,CAAAsB,mBAArB,CAAXD,EACW7B,CAAA,CAAaO,CAAb,CAAqBC,CAAAqB,SAArB,CADf,CAGIE,EAAoB,EAHxB,CAIIC,EAAc,EAJlB,CAKIC,EAAcZ,CAAAa,KALlB,CAMIC,EAAe,CAAA,CANnB,CAOIC,EAAgB,CAGpB,CAAsB,IAAtB,EAAOH,CAAP,CAAA,CAA4B,CAC1BG,CAAA,EACA;IAAI5D,EAAcyD,CAAAI,QAAlB,CAEIC,EAAc,CAAA,CACbH,EAAL,EACEzC,CAAA,CAAQd,CAAR,CAAoB,QAAQ,CAAC2D,CAAD,CAAQC,CAAR,CAAa,CAClCF,CAAAA,CAAL,EAAoBnC,CAAA,CAAOoC,CAAP,CAApB,EAAqC/D,CAAAE,KAAA,CAAiB8D,CAAjB,CAArC,EAEM,CAAAR,CAAA,CAAYQ,CAAZ,CAFN,GAKEF,CACA,CAHAN,CAAA,CAAYQ,CAAZ,CAGA,CAHmB,CAAA,CAGnB,CAAAhE,CAAAO,OAAA,EANF,CADuC,CAAzC,CAYEuD,EAAJ,CAGEH,CAHF,CAGiB,CAACN,CAHlB,CAKEE,CAAAb,KAAA,CAAuB1C,CAAvB,CAGFyD,EAAA,CAAcA,CAAAQ,KA1BY,CA6B5B/C,CAAA,CAAQqC,CAAR,CAA2B,QAAQ,CAACvD,CAAD,CAAc,CAC/CA,CAAAe,OAAA,EAD+C,CAAjD,CAIAwC,EAAA7B,OAAA,GAA6BkC,CAA7B,CACMxF,CAAA8F,SAAA,CAAkBpC,CAAlB,CAnEOqC,WAmEP,CAlESC,aAkET,CADN,CAEMhG,CAAA8F,SAAA,CAAkBpC,CAAlB,CAnESsC,aAmET,CApEOD,WAoEP,CApD2B,CAuDnCpC,EAAAjC,iBAAA,CAAwBkC,CAAAqC,WAAxB,EAA6CrC,CAAA,CAAO,KAAP,CAA7C,CAA4Da,CAAAM,OAA5D,CAGArB,EAAAjB,GAAA,CAAY,UAAZ,CAAwB,QAAQ,EAAG,CACjCK,CAAA,CAAQsB,CAAR,CAAkB,QAAQ,CAAC8B,CAAD,CAAO,CAC/BA,CAAAT,QAAA9C,OAAA,EAD+B,CAAjC,CADiC,CAAnC,CAMA,KAAAnB,SAAA,CAAgB2E,QAAQ,EAAG,CACpBtB,CAAL,GACEA,CACA,CADc,CAAA,CACd,CAAAlB,CAAAyC,WAAA,CAAkB,QAAQ,EAAG,CACvBvB,CAAJ,EACEC,CADF,EACsBL,CAAAM,OAAA,CAAYD,CAAZ,CAFK,CAA7B,CAFF,CADyB,CAW3B,KAAAjD,SAAA,CAAgBwE,QAAQ,CAACtC,CAAD,CAAUnC,CAAV,CAAuB,CAC7C,IAAI0E,EAAU5B,CAAA6B,SAAA,EACdnC,EAAA,CAASkC,CAAT,CAAA,CAAoB,CAClBb,QAAS7D,CADS,CAGF;IAAA,EAAA8B,CAAA,CAAS,CAAT,CAAA,CAwCd8C,EAAcpC,CAAA,CAxCsBkC,CAwCtB,CACb7B,EAAAa,KAAL,CAIE,CADImB,CACJ,CADY5C,CAAA,CAAoBC,CAApB,CA5CiBC,CA4CjB,CACZ,GACEyC,CAAAX,KACA,CADmBY,CAAAZ,KACnB,CAAAY,CAAAZ,KAAA,CAAaW,CAFf,GAIEA,CAAAX,KACA,CADmBpB,CAAAa,KACnB,CAAAb,CAAAa,KAAA,CAAYkB,CALd,CAJF,CACE/B,CAAAa,KADF,CACckB,CAzCdzC,EAAAI,gBAAA,CAA0BmC,CAC1B5B,EAAA,EAEAD,EAAAjD,SAAA,EAT6C,CAY/C,KAAAkB,WAAA,CAAkBgE,QAAQ,CAAC3C,CAAD,CAAU,CAClC,IAAI6B,EAAM7B,CAAAI,gBACV,QAAOJ,CAAAI,gBA+CP,KAAIqC,EAAcpC,CAAA,CA9CsBwB,CA8CtB,CAGlB,EADIa,CACJ,CADY5C,CAAA,CAhDMH,CAAAI,CAAS,CAATA,CAgDN,CAhDmBC,CAgDnB,CACZ,EACE0C,CAAAZ,KADF,CACeW,CAAAX,KADf,CAGEpB,CAAAa,KAHF,CAGckB,CAAAX,KAnDd,QAAOzB,CAAA,CAASwB,CAAT,CACPnB,EAAAjD,SAAA,EALkC,CAjG0C,CAApE,CAHP,CAJgD,CAAhC,CAjF3B,CAAA2B,UAAA,CA8Ra,mBA9Rb,CA+RI,CAAC,kBAAD,CAAqB,WAArB,CAAkC,UAAlC,CAA8C,QAAQ,CAACwD,CAAD,CAAmBC,CAAnB,CAA8BC,CAA9B,CAAwC,CAyB9FC,QAASA,EAAwB,CAACtG,CAAD,CAAUuG,CAAV,CAAe,CAE9C,IAAIhD,EAAU8C,CAAAG,gBAAA,CACVH,CAAAG,gBAAA,CAAyB,mBAAzB,CAA8CD,CAA9C,CADU,CAEVH,CAAA,CAAU,CAAV,CAAAK,cAAA,CAA2B,sBAA3B;AAAoDF,CAApD,CAA0D,GAA1D,CAFJ,CAGIG,EAASlE,CAAA,CAAOe,CAAP,CACbvD,EAAA2G,MAAA,CAAcD,CAAd,CAGA1G,EAAA4G,OAAA,EAT8C,CAvBhD,MAAO,CACLnH,SAAU,IADL,CAELI,QAAS,cAFJ,CAGLC,KAAMA,QAAQ,CAACqD,CAAD,CAASnD,CAAT,CAAkBC,CAAlB,CAAyB,CACrC,IAAIsG,EAAMtG,CAAA4G,kBAANN,EAAiCtG,CAAAsG,IACrCJ,EAAA,CAAiBI,CAAjB,CAAAO,KAAA,CAA2B,QAAQ,CAACC,CAAD,CAAO,CACpC5D,CAAA6D,YAAJ,GAEIzE,CAAA,CAASwE,CAAT,CAAJ,EAAuB,CAAAA,CAAAE,KAAA,EAAvB,CAEEX,CAAA,CAAyBtG,CAAzB,CAAkCuG,CAAlC,CAFF,CAKEF,CAAA,CAASU,CAAT,CAAA,CAAe5D,CAAf,CAAuB,QAAQ,CAAC+D,CAAD,CAAW,CACxClH,CAAA2G,MAAA,CAAcO,CAAd,CACAZ,EAAA,CAAyBtG,CAAzB,CAAkCuG,CAAlC,CAFwC,CAA1C,CAPF,CADwC,CAA1C,CAFqC,CAHlC,CAFuF,CAA9F,CA/RJ,CAAA5D,UAAA,CAqWa,WArWb,CAqW0BpD,CAAA,EArW1B,CAAAoD,UAAA,CAsYa,cAtYb,CAsY6BpD,CAAA,EAtY7B,CArQ2B,CAA1B,CAAD,CA6tBGF,MA7tBH,CA6tBWA,MAAAC,QA7tBX;", "sources":["angular-messages.js"], "names":["window","angular","ngMessageDirectiveFactory","$animate","restrict","transclude","priority","terminal","require","link","scope","element","attrs","ngMessagesCtrl","$transclude","commentNode","records","staticExp","ngMessage","when","dynamicExp","ngMessageExp","whenExp","assignRecords","items","isArray","split","reRender","$eval","$watchCollection","currentElement","messageCtrl","register","test","name","collection","indexOf","hasOwnProperty","attach","elm","newScope","enter","$$attachId","getAttachId","on","deregister","detach","$destroy","leave","forEach","isString","jqLite","module","initAngularHelpers","directive","isAttrTruthy","attr","length","truthy","val","controller","$element","$scope","$attrs","findPreviousMessage","parent","comment","prevNode","parentLookup","prevKey","$$ngMessageNode","messages","childNodes","push","previousSibling","parentNode","ctrl","latestKey","nextAttachId","this.getAttachId","renderLater","cachedCollection","render","this.render","multiple","ngMessagesMultiple","unmatchedMessages","matchedKeys","messageItem","head","messageFound","totalMessages","message","messageUsed","value","key","next","setClass","ACTIVE_CLASS","INACTIVE_CLASS","ngMessages","item","this.reRender","$evalAsync","this.register","nextKey","toString","messageNode","match","this.deregister","$templateRequest","$document","$compile","replaceElementWithMarker","src","$$createComment","createComment","marker","after","remove","ngMessagesInclude","then","html","$$destroyed","trim","contents"] } ././@LongLink0000000000000000000000000000017600000000000011221 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/angular-aria.min.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/ve0000666000175100017510000000752413240544407034017 0ustar zuulzuul00000000000000/* AngularJS v1.5.8 (c) 2010-2016 Google, Inc. http://angularjs.org License: MIT */ (function(t,p){'use strict';var b="BUTTON A INPUT TEXTAREA SELECT DETAILS SUMMARY".split(" "),l=function(a,c){if(-1!==c.indexOf(a[0].nodeName))return!0};p.module("ngAria",["ng"]).provider("$aria",function(){function a(a,b,m,h){return function(d,f,e){var q=e.$normalize(b);!c[q]||l(f,m)||e[q]||d.$watch(e[a],function(a){a=h?!a:!!a;f.attr(b,a)})}}var c={ariaHidden:!0,ariaChecked:!0,ariaReadonly:!0,ariaDisabled:!0,ariaRequired:!0,ariaInvalid:!0,ariaValue:!0,tabindex:!0,bindKeypress:!0,bindRoleForClick:!0}; this.config=function(a){c=p.extend(c,a)};this.$get=function(){return{config:function(a){return c[a]},$$watchExpr:a}}}).directive("ngShow",["$aria",function(a){return a.$$watchExpr("ngShow","aria-hidden",[],!0)}]).directive("ngHide",["$aria",function(a){return a.$$watchExpr("ngHide","aria-hidden",[],!1)}]).directive("ngValue",["$aria",function(a){return a.$$watchExpr("ngValue","aria-checked",b,!1)}]).directive("ngChecked",["$aria",function(a){return a.$$watchExpr("ngChecked","aria-checked",b,!1)}]).directive("ngReadonly", ["$aria",function(a){return a.$$watchExpr("ngReadonly","aria-readonly",b,!1)}]).directive("ngRequired",["$aria",function(a){return a.$$watchExpr("ngRequired","aria-required",b,!1)}]).directive("ngModel",["$aria",function(a){function c(c,h,d,f){return a.config(h)&&!d.attr(c)&&(f||!l(d,b))}function g(a,c){return!c.attr("role")&&c.attr("type")===a&&"INPUT"!==c[0].nodeName}function k(a,c){var d=a.type,f=a.role;return"checkbox"===(d||f)||"menuitemcheckbox"===f?"checkbox":"radio"===(d||f)||"menuitemradio"=== f?"radio":"range"===d||"progressbar"===f||"slider"===f?"range":""}return{restrict:"A",require:"ngModel",priority:200,compile:function(b,h){var d=k(h,b);return{pre:function(a,e,c,b){"checkbox"===d&&(b.$isEmpty=function(a){return!1===a})},post:function(f,e,b,n){function h(){return n.$modelValue}function k(a){e.attr("aria-checked",b.value==n.$viewValue)}function l(){e.attr("aria-checked",!n.$isEmpty(n.$viewValue))}var m=c("tabindex","tabindex",e,!1);switch(d){case "radio":case "checkbox":g(d,e)&&e.attr("role", d);c("aria-checked","ariaChecked",e,!1)&&f.$watch(h,"radio"===d?k:l);m&&e.attr("tabindex",0);break;case "range":g(d,e)&&e.attr("role","slider");if(a.config("ariaValue")){var p=!e.attr("aria-valuemin")&&(b.hasOwnProperty("min")||b.hasOwnProperty("ngMin")),r=!e.attr("aria-valuemax")&&(b.hasOwnProperty("max")||b.hasOwnProperty("ngMax")),s=!e.attr("aria-valuenow");p&&b.$observe("min",function(a){e.attr("aria-valuemin",a)});r&&b.$observe("max",function(a){e.attr("aria-valuemax",a)});s&&f.$watch(h,function(a){e.attr("aria-valuenow", a)})}m&&e.attr("tabindex",0)}!b.hasOwnProperty("ngRequired")&&n.$validators.required&&c("aria-required","ariaRequired",e,!1)&&b.$observe("required",function(){e.attr("aria-required",!!b.required)});c("aria-invalid","ariaInvalid",e,!0)&&f.$watch(function(){return n.$invalid},function(a){e.attr("aria-invalid",!!a)})}}}}}]).directive("ngDisabled",["$aria",function(a){return a.$$watchExpr("ngDisabled","aria-disabled",b,!1)}]).directive("ngMessages",function(){return{restrict:"A",require:"?ngMessages", link:function(a,b,g,k){b.attr("aria-live")||b.attr("aria-live","assertive")}}}).directive("ngClick",["$aria","$parse",function(a,c){return{restrict:"A",compile:function(g,k){var m=c(k.ngClick,null,!0);return function(c,d,f){if(!l(d,b)&&(a.config("bindRoleForClick")&&!d.attr("role")&&d.attr("role","button"),a.config("tabindex")&&!d.attr("tabindex")&&d.attr("tabindex",0),a.config("bindKeypress")&&!f.ngKeypress))d.on("keypress",function(a){function b(){m(c,{$event:a})}var d=a.which||a.keyCode;32!==d&& 13!==d||c.$apply(b)})}}}}]).directive("ngDblclick",["$aria",function(a){return function(c,g,k){!a.config("tabindex")||g.attr("tabindex")||l(g,b)||g.attr("tabindex",0)}}])})(window,window.angular); //# sourceMappingURL=angular-aria.min.js.map ././@LongLink0000000000000000000000000000016700000000000011221 Lustar 00000000000000heat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/json2yaml.jsheat-dashboard-1.0.2/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/ve0000666000175100017510000000450113240544407034007 0ustar zuulzuul00000000000000(function (self) { /* * TODO, lots of concatenation (slow in js) */ var spacing = " "; function getType(obj) { var type = typeof obj; if (obj instanceof Array) { return 'array'; } else if (type == 'string') { return 'string'; } else if (type == 'boolean') { return 'boolean'; } else if (type == 'number') { return 'number'; } else if (type == 'undefined' || obj === null) { return 'null'; } else { return 'hash'; } } function convert(obj, ret) { var type = getType(obj); switch(type) { case 'array': convertArray(obj, ret); break; case 'hash': convertHash(obj, ret); break; case 'string': convertString(obj, ret); break; case 'null': ret.push('null'); break; case 'number': ret.push(obj.toString()); break; case 'boolean': ret.push(obj ? 'true' : 'false'); break; } } function convertArray(obj, ret) { for (var i=0; i=31&&e.keyCode<=90},isNumPadKey:function(e){return 3===e.location&&e.keyCode>=97&&e.keyCode<=105},isMetaKey:function(e){return e.keyCode>=91&&e.keyCode<=93},isFnLockKey:function(e){return e.keyCode>=112&&e.keyCode<=145},isNavigationKey:function(e){var t=c.KEY_CODE,n=[t.SPACE,t.ENTER,t.UP_ARROW,t.DOWN_ARROW];return n.indexOf(e.keyCode)!=-1},hasModifierKey:function(e){return e.ctrlKey||e.metaKey||e.altKey},ELEMENT_MAX_PIXELS:1533917,BEFORE_NG_ARIA:210,KEY_CODE:{COMMA:188,SEMICOLON:186,ENTER:13,ESCAPE:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT_ARROW:37,UP_ARROW:38,RIGHT_ARROW:39,DOWN_ARROW:40,TAB:9,BACKSPACE:8,DELETE:46},CSS:{TRANSITIONEND:"transitionend"+(d?" webkitTransitionEnd":""),ANIMATIONEND:"animationend"+(d?" webkitAnimationEnd":""),TRANSFORM:e("transform"),TRANSFORM_ORIGIN:e("transformOrigin"),TRANSITION:e("transition"),TRANSITION_DURATION:e("transitionDuration"),ANIMATION_PLAY_STATE:e("animationPlayState"),ANIMATION_DURATION:e("animationDuration"),ANIMATION_NAME:e("animationName"),ANIMATION_TIMING:e("animationTimingFunction"),ANIMATION_DIRECTION:e("animationDirection")},MEDIA:{xs:"(max-width: 599px)","gt-xs":"(min-width: 600px)",sm:"(min-width: 600px) and (max-width: 959px)","gt-sm":"(min-width: 960px)",md:"(min-width: 960px) and (max-width: 1279px)","gt-md":"(min-width: 1280px)",lg:"(min-width: 1280px) and (max-width: 1919px)","gt-lg":"(min-width: 1920px)",xl:"(min-width: 1920px)",landscape:"(orientation: landscape)",portrait:"(orientation: portrait)",print:"print"},MEDIA_PRIORITY:["xl","gt-lg","lg","gt-md","md","gt-sm","sm","gt-xs","xs","landscape","portrait","print"]};return c}t.module("material.core").factory("$mdConstant",e)}(),function(){function e(e,n){function o(){return[].concat(v)}function i(){return v.length}function r(e){return v.length&&e>-1&&e-1}function h(){return v.length?v[0]:null}function f(){return v.length?v[v.length-1]:null}function g(e,o,i,a){i=i||b;for(var d=u(o);;){if(!r(d))return null;var s=d+(e?-1:1),c=null;if(r(s)?c=v[s]:n&&(c=e?f():h(),s=u(c)),null===c||s===a)return null;if(i(c))return c;t.isUndefined(a)&&(a=s),d=s}}var b=function(){return!0};e&&!t.isArray(e)&&(e=Array.prototype.slice.call(e)),n=!!n;var v=e||[];return{items:o,count:i,inRange:r,contains:p,indexOf:u,itemAt:s,findBy:c,add:l,remove:m,first:h,last:f,next:t.bind(null,g,!1),previous:t.bind(null,g,!0),hasPrevious:d,hasNext:a}}t.module("material.core").config(["$provide",function(t){t.decorator("$mdUtil",["$delegate",function(t){return t.iterator=e,t}])}])}(),function(){function e(e,n,o){function i(e){var n=u[e];t.isUndefined(n)&&(n=u[e]=r(e));var o=h[n];return t.isUndefined(o)&&(o=a(n)),o}function r(t){return e.MEDIA[t]||("("!==t.charAt(0)?"("+t+")":t)}function a(e){var t=p[e];return t||(t=p[e]=o.matchMedia(e)),t.addListener(d),h[t.media]=!!t.matches}function d(e){n.$evalAsync(function(){h[e.media]=!!e.matches})}function s(e){return p[e]}function c(t,n){for(var o=0;o-1}function g(e){return String(e).indexOf("%")>-1}function b(e){return e[0]||e}var v=c.startSymbol(),E=c.endSymbol(),$="{{"===v&&"}}"===E,y=function(e,n,o){var i=!1;if(e&&e.length){var r=u.getComputedStyle(e[0]);i=t.isDefined(r[n])&&(!o||r[n]==o)}return i},C={dom:{},now:e.performance&&e.performance.now?t.bind(e.performance,e.performance.now):Date.now||function(){return(new Date).getTime()},getModelOption:function(e,t){if(e.$options){var n=e.$options;return n.getOption?n.getOption(t):n[t]}},bidi:function(e,n,i,r){var a=!("rtl"==o[0].dir||"rtl"==o[0].body.dir);if(0==arguments.length)return a?"ltr":"rtl";var d=t.element(e);a&&t.isDefined(i)?d.css(n,h(i)):!a&&t.isDefined(r)&&d.css(n,h(r))},bidiProperty:function(e,n,i,r){var a=!("rtl"==o[0].dir||"rtl"==o[0].body.dir),d=t.element(e);a&&t.isDefined(n)?(d.css(n,h(r)),d.css(i,"")):!a&&t.isDefined(i)&&(d.css(i,h(r)),d.css(n,""))},clientRect:function(e,t,n){var o=b(e);t=b(t||o.offsetParent||document.body);var i=o.getBoundingClientRect(),r=n?t.getBoundingClientRect():{left:0,top:0,width:0,height:0};return{left:i.left-r.left,top:i.top-r.top,width:i.width,height:i.height}},offsetRect:function(e,t){return C.clientRect(e,t,!0)},nodesToArray:function(e){e=e||[];for(var t=[],n=0;n
'),e.append(o)),o.on("wheel",n),o.on("touchmove",n),function(){o.off("wheel"),o.off("touchmove"),!i.disableScrollMask&&o[0].parentNode&&o[0].parentNode.removeChild(o[0])}}function a(){var e=o[0].documentElement,n=e.style.cssText||"",i=d.style.cssText||"",r=C.getViewportTop(),a=d.clientWidth,s=d.scrollHeight>d.clientHeight+1,c=e.scrollTop>0?e:d;return s&&t.element(d).css({position:"fixed",width:"100%",top:-r+"px"}),d.clientWidth
").css({width:"100%","z-index":-1,position:"absolute",height:"35px","overflow-y":"scroll"});e.children().css("height","60px"),o[0].body.appendChild(e[0]),this.floatingScrollbars.cached=e[0].offsetWidth==e[0].childNodes[0].offsetWidth,e.remove()}return this.floatingScrollbars.cached},forceFocus:function(t){var n=t[0]||t;document.addEventListener("click",function i(e){e.target===n&&e.$focus&&(n.focus(),e.stopImmediatePropagation(),e.preventDefault(),n.removeEventListener("click",i))},!0);var o=document.createEvent("MouseEvents");o.initMouseEvent("click",!1,!0,e,{},0,0,0,0,!1,!1,!1,!1,0,null),o.$material=!0,o.$focus=!0,n.dispatchEvent(o)},createBackdrop:function(e,t){return a(C.supplant('',[t]))(e)},supplant:function(e,t,n){return n=n||/\{([^\{\}]*)\}/g,e.replace(n,function(e,n){var o=n.split("."),i=t;try{for(var r in o)o.hasOwnProperty(r)&&(i=i[o[r]])}catch(a){i=e}return"string"==typeof i||"number"==typeof i?i:e})},fakeNgModel:function(){return{$fake:!0,$setTouched:t.noop,$setViewValue:function(e){this.$viewValue=e,this.$render(e),this.$viewChangeListeners.forEach(function(e){e()})},$isEmpty:function(e){return 0===(""+e).length},$parsers:[],$formatters:[],$viewChangeListeners:[],$render:t.noop}},debounce:function(e,t,o,i){var a;return function(){var d=o,s=Array.prototype.slice.call(arguments);r.cancel(a),a=r(function(){a=n,e.apply(d,s)},t||10,i)}},throttle:function(e,t){var n;return function(){var o=this,i=arguments,r=C.now();(!n||r-n>t)&&(e.apply(o,i),n=r)}},time:function(e){var t=C.now();return e(),C.now()-t},valueOnUse:function(e,t,n){var o=null,i=Array.prototype.slice.call(arguments),r=i.length>3?i.slice(3):[];Object.defineProperty(e,t,{get:function(){return null===o&&(o=n.apply(e,r)),o}})},nextUid:function(){return""+i++},disconnectScope:function(e){if(e&&e.$root!==e&&!e.$$destroyed){var t=e.$parent;e.$$disconnected=!0,t.$$childHead===e&&(t.$$childHead=e.$$nextSibling),t.$$childTail===e&&(t.$$childTail=e.$$prevSibling),e.$$prevSibling&&(e.$$prevSibling.$$nextSibling=e.$$nextSibling),e.$$nextSibling&&(e.$$nextSibling.$$prevSibling=e.$$prevSibling),e.$$nextSibling=e.$$prevSibling=null}},reconnectScope:function(e){if(e&&e.$root!==e&&e.$$disconnected){var t=e,n=t.$parent;t.$$disconnected=!1,t.$$prevSibling=n.$$childTail,n.$$childHead?(n.$$childTail.$$nextSibling=t,n.$$childTail=t):n.$$childHead=n.$$childTail=t}},getClosest:function(e,n,o){if(t.isString(n)){var i=n.toUpperCase();n=function(e){return e.nodeName.toUpperCase()===i}}if(e instanceof t.element&&(e=e[0]),o&&(e=e.parentNode),!e)return null;do if(n(e))return e;while(e=e.parentNode);return null},elementContains:function(n,o){var i=e.Node&&e.Node.prototype&&Node.prototype.contains,r=i?t.bind(n,n.contains):t.bind(n,function(e){return n===o||!!(16&this.compareDocumentPosition(e))});return r(o)},extractElementByName:function(e,n,o,i){function r(e){return a(e)||(o?d(e):null)}function a(e){if(e)for(var t=0,o=e.length;t");o[0].body.appendChild(n[0]);for(var i=["sticky","-webkit-sticky"],r=0;rt)&&p(o)}function i(){var e=n||1e3,t=C.now()-c;return r(t,a,d,e)}function r(e,t,n,o){if(e>o)return t+n;var i=(e/=o)*e,r=i*e;return t+n*(-2*r+3*i)}var a=e.scrollTop,d=t-a,s=a-1;o?a(e,t,function(){return c(e)}):r(e,t,n)}function s(e,t){var n=c(e),o=n.indexOf(i.startSymbol())>-1;o||n||r(e,t,n)}function c(e){function t(t){for(;t.parentNode&&(t=t.parentNode)!==e;)if(t.getAttribute&&"true"===t.getAttribute("aria-hidden"))return!0}e=e[0]||e;for(var n,o=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null,!1),i="";n=o.nextNode();)t(n)||(i+=n.textContent);return i.trim()||""}function l(e,t){function n(e){var t=e.currentStyle?e.currentStyle:o.getComputedStyle(e);return"none"===t.display}var i=e.hasChildNodes(),r=!1;if(i)for(var a=e.childNodes,d=0;d").html(i.trim()).contents();return n._compileElement(o,r,e)})},o.prototype._compileElement=function(e,n,o){function i(i){if(e.$scope=i,o.controller){var s=t.extend({},e,{$element:n}),c=r._createController(o,s,e);n.data("$ngControllerController",c),n.children().data("$ngControllerController",c),d.controller=c}return a(i)}var r=this,a=this.$compile(n),d={element:n,cleanup:n.remove.bind(n),locals:e,link:i};return d},o.prototype._createController=function(e,o,i){var r=this.$controller(e.controller,o,!0,e.controllerAs);n()&&e.bindToController&&t.extend(r.instance,i);var a=r();return!n()&&e.bindToController&&t.extend(r.instance,i),t.isFunction(a.$onInit)&&a.$onInit(),a},o.prototype._fetchContentElement=function(e){function n(e){var t=e.parentNode,n=e.nextElementSibling;return function(){n?t.insertBefore(e,n):t.appendChild(e)}}var o=e.contentElement,i=null;return t.isString(o)?(o=document.querySelector(o),i=n(o)):(o=o[0]||o,i=document.contains(o)?n(o):function(){o.parentNode&&o.parentNode.removeChild(o)}),{element:t.element(o),restore:i}}}t.module("material.core").provider("$mdCompiler",e),e.$inject=["$compileProvider"]}(),function(){function n(){}function o(n,o,i){function r(e){return function(t,n){n.distancethis.options.maxDistance&&this.cancel()},onEnd:function(){this.onCancel()}}).handler("drag",{options:{minDistance:6,horizontal:!0,cancelMultiplier:1.5},onSetup:function(e,t){v&&(this.oldTouchAction=e[0].style[v],e[0].style[v]=t.horizontal?"pan-y":"pan-x")},onCleanup:function(e){this.oldTouchAction&&(e[0].style[v]=this.oldTouchAction)},onStart:function(e){this.state.registeredParent||this.cancel()},onMove:function(e,t){var n,o;v||"touchmove"!==e.type||e.preventDefault(),this.state.dragPointer?this.dispatchDragMove(e):(this.state.options.horizontal?(n=Math.abs(t.distanceX)>this.state.options.minDistance,o=Math.abs(t.distanceY)>this.state.options.minDistance*this.state.options.cancelMultiplier):(n=Math.abs(t.distanceY)>this.state.options.minDistance,o=Math.abs(t.distanceX)>this.state.options.minDistance*this.state.options.cancelMultiplier),n?(this.state.dragPointer=d(e),l(e,this.state.dragPointer),this.dispatchEvent(e,"$md.dragstart",this.state.dragPointer)):o&&this.cancel())},dispatchDragMove:o.throttle(function(e){this.state.isRunning&&(l(e,this.state.dragPointer),this.dispatchEvent(e,"$md.drag",this.state.dragPointer))}),onEnd:function(e,t){this.state.dragPointer&&(l(e,this.state.dragPointer),this.dispatchEvent(e,"$md.dragend",this.state.dragPointer))}}).handler("swipe",{options:{minVelocity:.65,minDistance:10},onEnd:function(e,t){var n;Math.abs(t.velocityX)>this.state.options.minVelocity&&Math.abs(t.distanceX)>this.state.options.minDistance?(n="left"==t.directionX?"$md.swipeleft":"$md.swiperight",this.dispatchEvent(e,n)):Math.abs(t.velocityY)>this.state.options.minVelocity&&Math.abs(t.distanceY)>this.state.options.minDistance&&(n="up"==t.directionY?"$md.swipeup":"$md.swipedown",this.dispatchEvent(e,n))}})}function i(e){this.name=e,this.state={}}function r(){function n(e,n,o){o=o||p;var i=new t.element.Event(n);i.$material=!0,i.pointer=o,i.srcEvent=e,t.extend(i,{clientX:o.x,clientY:o.y,screenX:o.x,screenY:o.y,pageX:o.x,pageY:o.y,ctrlKey:e.ctrlKey,altKey:e.altKey,shiftKey:e.shiftKey,metaKey:e.metaKey}),t.element(o.target).trigger(i)}function o(t,n,o){o=o||p;var i;"click"===n||"mouseup"==n||"mousedown"==n?(i=document.createEvent("MouseEvents"),i.initMouseEvent(n,!0,!0,e,t.detail,o.x,o.y,o.x,o.y,t.ctrlKey,t.altKey,t.shiftKey,t.metaKey,t.button,t.relatedTarget||null)):(i=document.createEvent("CustomEvent"),i.initCustomEvent(n,!0,!0,{})),i.$material=!0,i.pointer=o,i.srcEvent=t,o.target.dispatchEvent(i)}var r="undefined"!=typeof e.jQuery&&t.element===e.jQuery;return i.prototype={options:{},dispatchEvent:r?n:o,onSetup:t.noop,onCleanup:t.noop,onStart:t.noop,onMove:t.noop,onEnd:t.noop,onCancel:t.noop,start:function(e,n){if(!this.state.isRunning){var o=this.getNearestParent(e.target),i=o&&o.$mdGesture[this.name]||{};this.state={isRunning:!0,options:t.extend({},this.options,i),registeredParent:o},this.onStart(e,n)}},move:function(e,t){this.state.isRunning&&this.onMove(e,t)},end:function(e,t){this.state.isRunning&&(this.onEnd(e,t),this.state.isRunning=!1)},cancel:function(e,t){this.onCancel(e,t),this.state={}},getNearestParent:function(e){for(var t=e;t;){if((t.$mdGesture||{})[this.name])return t;t=t.parentNode}return null},registerElement:function(e,t){function n(){delete e[0].$mdGesture[o.name],e.off("$destroy",n),o.onCleanup(e,t||{})}var o=this;return e[0].$mdGesture=e[0].$mdGesture||{},e[0].$mdGesture[this.name]=t||{},e.on("$destroy",n),o.onSetup(e,t||{}),n}},i}function a(e,n){function o(e){var t=!e.clientX&&!e.clientY;t||e.$material||e.isIonicTap||c(e)||"mousedown"===e.type&&(u(e.target)||u(document.activeElement))||(e.preventDefault(),e.stopPropagation())}function i(e){var t=0===e.clientX&&0===e.clientY,n=e.target&&"submit"===e.target.type;t||e.$material||e.isIonicTap||c(e)||n?(v=null,"label"==e.target.tagName.toLowerCase()&&(v={x:e.x,y:e.y})):(e.preventDefault(),e.stopPropagation(),v=null)}function r(e,t){var o;for(var i in f)o=f[i],o instanceof n&&("start"===e&&o.cancel(),o[e](t,p))}function a(e){if(!p){var t=+Date.now();h&&!s(e,h)&&t-h.endTime<1500||(p=d(e),r("start",e))}}function m(e){p&&s(e,p)&&(l(e,p),r("move",e))}function g(e){p&&s(e,p)&&(l(e,p),p.endTime=+Date.now(),"pointercancel"!==e.type&&r("end",e),h=p,p=null)}document.contains||(document.contains=function(e){return document.body.contains(e)}),!E&&e.isHijackingClicks&&(document.addEventListener("click",i,!0),document.addEventListener("mouseup",o,!0),document.addEventListener("mousedown",o,!0),document.addEventListener("focus",o,!0),E=!0);var b="mousedown touchstart pointerdown",$="mousemove touchmove pointermove",y="mouseup mouseleave touchend touchcancel pointerup pointercancel";t.element(document).on(b,a).on($,m).on(y,g).on("$$mdGestureReset",function(){h=p=null})}function d(e){var t=m(e),n={startTime:+Date.now(),target:e.target,type:e.type.charAt(0)};return n.startX=n.x=t.pageX,n.startY=n.y=t.pageY,n}function s(e,t){return e&&t&&e.type.charAt(0)===t.type}function c(e){return v&&v.x==e.x&&v.y==e.y}function l(e,t){var n=m(e),o=t.x=n.pageX,i=t.y=n.pageY;t.distanceX=o-t.startX,t.distanceY=i-t.startY,t.distance=Math.sqrt(t.distanceX*t.distanceX+t.distanceY*t.distanceY),t.directionX=t.distanceX>0?"right":t.distanceX<0?"left":"",t.directionY=t.distanceY>0?"down":t.distanceY<0?"up":"",t.duration=+Date.now()-t.startTime,t.velocityX=t.distanceX/t.duration,t.velocityY=t.distanceY/t.duration}function m(e){return e=e.originalEvent||e,e.touches&&e.touches[0]||e.changedTouches&&e.changedTouches[0]||e}function u(e){return!!e&&"-1"!=e.getAttribute("tabindex")&&!e.hasAttribute("disabled")&&(e.hasAttribute("tabindex")||e.hasAttribute("href")||e.isContentEditable||["INPUT","SELECT","BUTTON","TEXTAREA","VIDEO","AUDIO"].indexOf(e.nodeName)!=-1)}o.$inject=["$$MdGestureHandler","$$rAF","$timeout"],a.$inject=["$mdGesture","$$MdGestureHandler"];var p,h,f={},g=!1,b=6,v=null,E=!1;t.module("material.core.gestures",[]).provider("$mdGesture",n).factory("$$MdGestureHandler",r).run(a),n.prototype={skipClickHijack:function(){return g=!0},setMaxClickDistance:function(e){b=parseInt(e)},$get:["$$MdGestureHandler","$$rAF","$timeout",function(e,t,n){return new o(e,t,n)}]}}(),function(){function n(e,n){this.$timeout=e,this.$mdUtil=n,this.bodyElement=t.element(document.body),this.isBuffering=!1,this.bufferTimeout=null,this.lastInteractionType=null,this.lastInteractionTime=null,this.inputEventMap={keydown:"keyboard",mousedown:"mouse",mouseenter:"mouse",touchstart:"touch",pointerdown:"pointer",MSPointerDown:"pointer"},this.iePointerMap={2:"touch",3:"touch",4:"mouse"},this.initializeEvents()}n.$inject=["$timeout","$mdUtil"],t.module("material.core.interaction",[]).service("$mdInteraction",n),n.prototype.initializeEvents=function(){var t="MSPointerEvent"in e?"MSPointerDown":"PointerEvent"in e?"pointerdown":null;this.bodyElement.on("keydown mousedown",this.onInputEvent.bind(this)),"ontouchstart"in document.documentElement&&this.bodyElement.on("touchstart",this.onBufferInputEvent.bind(this)),t&&this.bodyElement.on(t,this.onInputEvent.bind(this))},n.prototype.onInputEvent=function(e){if(!this.isBuffering){var t=this.inputEventMap[e.type];"pointer"===t&&(t=this.iePointerMap[e.pointerType]||e.pointerType),this.lastInteractionType=t,this.lastInteractionTime=this.$mdUtil.now()}},n.prototype.onBufferInputEvent=function(e){this.$timeout.cancel(this.bufferTimeout),this.onInputEvent(e),this.isBuffering=!0,this.bufferTimeout=this.$timeout(function(){this.isBuffering=!1}.bind(this),650,!1); },n.prototype.getLastInteractionType=function(){return this.lastInteractionType},n.prototype.isUserInvoked=function(e){var n=t.isNumber(e)?e:15;return this.lastInteractionTime>=this.$mdUtil.now()-n}}(),function(){function e(){function e(e){function n(e){return s.optionsFactory=e.options,s.methods=(e.methods||[]).concat(a),c}function o(e,t){return d[e]=t,c}function i(t,n){if(n=n||{},n.methods=n.methods||[],n.options=n.options||function(){return{}},/^cancel|hide|show$/.test(t))throw new Error("Preset '"+t+"' in "+e+" is reserved!");if(n.methods.indexOf("_options")>-1)throw new Error("Method '_options' in "+e+" is reserved!");return s.presets[t]={methods:n.methods.concat(a),optionsFactory:n.options,argOption:n.argOption},c}function r(n,o){function i(e){return e=e||{},e._options&&(e=e._options),m.show(t.extend({},l,e))}function r(e){return m.destroy(e)}function a(t,n){var i={};return i[e]=u,o.invoke(t||function(){return n},{},i)}var c,l,m=n(),u={hide:m.hide,cancel:m.cancel,show:i,destroy:r};return c=s.methods||[],l=a(s.optionsFactory,{}),t.forEach(d,function(e,t){u[t]=e}),t.forEach(s.presets,function(e,n){function o(e){this._options=t.extend({},i,e)}var i=a(e.optionsFactory,{}),r=(e.methods||[]).concat(c);if(t.extend(i,{$type:n}),t.forEach(r,function(e){o.prototype[e]=function(t){return this._options[e]=t,this}}),e.argOption){var d="show"+n.charAt(0).toUpperCase()+n.slice(1);u[d]=function(e){var t=u[n](e);return u.show(t)}}u[n]=function(n){return arguments.length&&e.argOption&&!t.isObject(n)&&!t.isArray(n)?(new o)[e.argOption](n):new o(n)}}),u}r.$inject=["$$interimElement","$injector"];var a=["onHide","onShow","onRemove"],d={},s={presets:{}},c={setDefaults:n,addPreset:i,addMethod:o,$get:r};return c.addPreset("build",{methods:["controller","controllerAs","resolve","multiple","template","templateUrl","themable","transformTemplate","parent","contentElement"]}),c}function o(e,o,i,r,a,d,s,c,l,m,u){return function(){function p(e){e=e||{};var t=new v(e||{}),n=e.multiple?o.resolve():o.all(y);e.multiple||(n=n.then(function(){var e=C.concat(M.map(E.cancel));return o.all(e)}));var i=n.then(function(){return t.show()["catch"](function(e){return e})["finally"](function(){y.splice(y.indexOf(i),1),M.push(t)})});return y.push(i),t.deferred.promise["catch"](function(e){return e instanceof Error&&u(e),e}),t.deferred.promise}function h(e,t){function i(n){var o=n.remove(e,!1,t||{})["catch"](function(e){return e})["finally"](function(){C.splice(C.indexOf(o),1)});return M.splice(M.indexOf(n),1),C.push(o),n.deferred.promise}return t=t||{},t.closeAll?o.all(M.slice().reverse().map(i)):t.closeTo!==n?o.all(M.slice(t.closeTo).map(i)):i(M[M.length-1])}function f(e,n){var i=M.pop();if(!i)return o.when(e);var r=i.remove(e,!0,n||{})["catch"](function(e){return e})["finally"](function(){C.splice(C.indexOf(r),1)});return C.push(r),i.deferred.promise["catch"](t.noop)}function g(e){return function(){var t=arguments;return M.length?e.apply(E,t):y.length?y[0]["finally"](function(){return e.apply(E,t)}):o.when("No interim elements currently showing up.")}}function b(e){var n=e?null:M.shift(),i=t.element(e).length&&t.element(e)[0].parentNode;if(i){var r=M.filter(function(e){return e.options.element[0]===i});r.length&&(n=r[0],M.splice(M.indexOf(n),1))}return n?n.remove($,!1,{$destroy:!0}):o.when($)}function v(m){function u(){return o(function(e,t){function n(e){C.deferred.reject(e),t(e)}m.onCompiling&&m.onCompiling(m),f(m).then(function(t){M=g(t,m),m.cleanupElement=t.cleanup,T=$(M,m,t.controller).then(e,n)})["catch"](n)})}function p(e,n,i){function r(e){C.deferred.resolve(e)}function a(e){C.deferred.reject(e)}return M?(m=t.extend(m||{},i||{}),m.cancelAutoHide&&m.cancelAutoHide(),m.element.triggerHandler("$mdInterimElementRemove"),m.$destroy===!0?y(m.element,m).then(function(){n&&a(e)||r(e)}):(o.when(T)["finally"](function(){y(m.element,m).then(function(){n?a(e):r(e)},a)}),C.deferred.promise)):o.when(!1)}function h(e){return e=e||{},e.template&&(e.template=s.processTemplate(e.template)),t.extend({preserveScope:!1,cancelAutoHide:t.noop,scope:e.scope||i.$new(e.isolateScope),onShow:function(e,t,n){return d.enter(t,n.parent)},onRemove:function(e,t){return t&&d.leave(t)||o.when()}},e)}function f(e){var t=e.skipCompile?null:c.compile(e);return t||o(function(t){t({locals:{},link:function(){return e.element}})})}function g(e,n){t.extend(e.locals,n);var o=e.link(n.scope);return n.element=o,n.parent=b(o,n),n.themable&&l(o),o}function b(n,o){var i=o.parent;if(i=t.isFunction(i)?i(o.scope,n,o):t.isString(i)?t.element(e[0].querySelector(i)):t.element(i),!(i||{}).length){var r;return a[0]&&a[0].querySelector&&(r=a[0].querySelector(":not(svg) > body")),r||(r=a[0]),"#comment"==r.nodeName&&(r=e[0].body),t.element(r)}return i}function v(){var e,o=t.noop;m.hideDelay&&(e=r(E.hide,m.hideDelay),o=function(){r.cancel(e)}),m.cancelAutoHide=function(){o(),m.cancelAutoHide=n}}function $(e,n,i){var r=n.onShowing||t.noop,a=n.onComplete||t.noop;try{r(n.scope,e,n,i)}catch(d){return o.reject(d)}return o(function(t,r){try{o.when(n.onShow(n.scope,e,n,i)).then(function(){a(n.scope,e,n),v(),t(e)},r)}catch(d){r(d.message)}})}function y(e,n){var i=n.onRemoving||t.noop;return o(function(t,r){try{var a=o.when(n.onRemove(n.scope,e,n)||!0);i(e,a),n.$destroy?(t(e),!n.preserveScope&&n.scope&&a.then(function(){n.scope.$destroy()})):a.then(function(){!n.preserveScope&&n.scope&&n.scope.$destroy(),t(e)},r)}catch(d){r(d.message)}})}var C,M,T=o.when(!0);return m=h(m),C={options:m,deferred:o.defer(),show:u,remove:p}}var E,$=!1,y=[],C=[],M=[];return E={show:p,hide:g(h),cancel:g(f),destroy:b,$injector_:m}}}return o.$inject=["$document","$q","$rootScope","$timeout","$rootElement","$animate","$mdUtil","$mdCompiler","$mdTheming","$injector","$exceptionHandler"],e.$get=o,e}t.module("material.core").provider("$$interimElement",e)}(),function(){!function(){function e(e){function d(e){return e.replace(m,"").replace(u,function(e,t,n,o){return o?n.toUpperCase():n})}var m=/^((?:x|data)[\:\-_])/i,u=/([\:\-\_]+(.))/g,p=["","xs","gt-xs","sm","gt-sm","md","gt-md","lg","gt-lg","xl","print"],h=["layout","flex","flex-order","flex-offset","layout-align"],f=["show","hide","layout-padding","layout-margin"];t.forEach(p,function(n){t.forEach(h,function(t){var o=n?t+"-"+n:t;e.directive(d(o),r(o))}),t.forEach(f,function(t){var o=n?t+"-"+n:t;e.directive(d(o),a(o))})}),e.provider("$$mdLayout",function(){return{$get:t.noop,validateAttributeValue:l,validateAttributeUsage:c,disableLayouts:function(e){A.enabled=e!==!0}}}).directive("mdLayoutCss",o).directive("ngCloak",i("ng-cloak")).directive("layoutWrap",a("layout-wrap")).directive("layoutNowrap",a("layout-nowrap")).directive("layoutNoWrap",a("layout-no-wrap")).directive("layoutFill",a("layout-fill")).directive("layoutLtMd",s("layout-lt-md",!0)).directive("layoutLtLg",s("layout-lt-lg",!0)).directive("flexLtMd",s("flex-lt-md",!0)).directive("flexLtLg",s("flex-lt-lg",!0)).directive("layoutAlignLtMd",s("layout-align-lt-md")).directive("layoutAlignLtLg",s("layout-align-lt-lg")).directive("flexOrderLtMd",s("flex-order-lt-md")).directive("flexOrderLtLg",s("flex-order-lt-lg")).directive("offsetLtMd",s("flex-offset-lt-md")).directive("offsetLtLg",s("flex-offset-lt-lg")).directive("hideLtMd",s("hide-lt-md")).directive("hideLtLg",s("hide-lt-lg")).directive("showLtMd",s("show-lt-md")).directive("showLtLg",s("show-lt-lg")).config(n)}function n(){var e=!!document.querySelector("[md-layouts-disabled]");A.enabled=!e}function o(){return A.enabled=!1,{restrict:"A",priority:"900"}}function i(e){return["$timeout",function(n){return{restrict:"A",priority:-10,compile:function(o){return A.enabled?(o.addClass(e),function(t,o){n(function(){o.removeClass(e)},10,!1)}):t.noop}}}]}function r(e){function n(t,n,o){var i=d(n,e,o),r=o.$observe(o.$normalize(e),i);i(p(e,o,"")),t.$on("$destroy",function(){r()})}return["$mdUtil","$interpolate","$log",function(o,i,r){return g=o,b=i,v=r,{restrict:"A",compile:function(o,i){var r;return A.enabled&&(c(e,i,o,v),l(e,p(e,i,""),m(o,e,i)),r=n),r||t.noop}}}]}function a(e){function n(t,n){n.addClass(e)}return["$mdUtil","$interpolate","$log",function(o,i,r){return g=o,b=i,v=r,{restrict:"A",compile:function(o,i){var r;return A.enabled&&(l(e,p(e,i,""),m(o,e,i)),n(null,o),r=n),r||t.noop}}}]}function d(e,n){var o;return function(i){var r=l(n,i||"");t.isDefined(r)&&(o&&e.removeClass(o),o=r?n+"-"+r.trim().replace($,"-"):n,e.addClass(o))}}function s(e){var n=e.split("-");return["$log",function(o){return o.warn(e+"has been deprecated. Please use a `"+n[0]+"-gt-` variant."),t.noop}]}function c(e,t,n,o){var i,r,a,d=n[0].nodeName.toLowerCase();switch(e.replace(E,"")){case"flex":"md-button"!=d&&"fieldset"!=d||(r="<"+d+" "+e+">",a="https://github.com/philipwalton/flexbugs#9-some-html-elements-cant-be-flex-containers",i="Markup '{0}' may not work as expected in IE Browsers. Consult '{1}' for details.",o.warn(g.supplant(i,[r,a])))}}function l(e,n,o){var i;if(!u(n)){switch(e.replace(E,"")){case"layout":h(n,C)||(n=C[0]);break;case"flex":h(n,y)||isNaN(n)&&(n="");break;case"flex-offset":case"flex-order":n&&!isNaN(+n)||(n="0");break;case"layout-align":var r=f(n);n=g.supplant("{main}-{cross}",r);break;case"layout-padding":case"layout-margin":case"layout-fill":case"layout-wrap":case"layout-nowrap":case"layout-nowrap":n=""}n!=i&&(o||t.noop)(n)}return n?n.trim():""}function m(e,t,n){return function(e){u(e)||(n[n.$normalize(t)]=e)}}function u(e){return(e||"").indexOf(b.startSymbol())>-1}function p(e,t,n){var o=t.$normalize(e);return t[o]?t[o].trim().replace($,"-"):n||null}function h(e,t,n){e=n&&e?e.replace($,n):e;var o=!1;return e&&t.forEach(function(t){t=n?t.replace($,n):t,o=o||t===e}),o}function f(e){var t,n={main:"start",cross:"stretch"};return e=e||"",0!==e.indexOf("-")&&0!==e.indexOf(" ")||(e="none"+e),t=e.toLowerCase().trim().replace($,"-").split("-"),t.length&&"space"===t[0]&&(t=[t[0]+"-"+t[1],t[2]]),t.length>0&&(n.main=t[0]||n.main),t.length>1&&(n.cross=t[1]||n.cross),M.indexOf(n.main)<0&&(n.main="start"),T.indexOf(n.cross)<0&&(n.cross="stretch"),n}var g,b,v,E=/(-gt)?-(sm|md|lg|print)/g,$=/\s+/g,y=["grow","initial","auto","none","noshrink","nogrow"],C=["row","column"],M=["","start","center","end","stretch","space-around","space-between"],T=["","start","center","end","stretch"],A={enabled:!0,breakpoints:[]};e(t.module("material.core.layout",["ng"]))}()}(),function(){function e(e){this._$timeout=e,this._liveElement=this._createLiveElement(),this._announceTimeout=100}e.$inject=["$timeout"],t.module("material.core").service("$mdLiveAnnouncer",e),e.prototype.announce=function(e,t){t||(t="polite");var n=this;n._liveElement.textContent="",n._liveElement.setAttribute("aria-live",t),n._$timeout(function(){n._liveElement.textContent=e},n._announceTimeout,!1)},e.prototype._createLiveElement=function(){var e=document.createElement("div");return e.classList.add("md-visually-hidden"),e.setAttribute("role","status"),e.setAttribute("aria-atomic","true"),e.setAttribute("aria-live","polite"),document.body.appendChild(e),e}}(),function(){t.module("material.core.meta",[]).provider("$$mdMeta",function(){function e(e){if(r[e])return!0;var n=document.getElementsByName(e)[0];return!!n&&(r[e]=t.element(n),!0)}function n(n,o){if(e(n),r[n])r[n].attr("content",o);else{var a=t.element('');i.append(a),r[n]=a}return function(){r[n].attr("content",""),r[n].remove(),delete r[n]}}function o(t){if(!e(t))throw Error("$$mdMeta: could not find a meta tag with the name '"+t+"'");return r[t].attr("content")}var i=t.element(document.head),r={},a={setMeta:n,getMeta:o};return t.extend({},a,{$get:function(){return a}})})}(),function(){function e(e,o){function i(e){return e&&""!==e}var r,a=[],d={};return r={notFoundError:function(t,n){e.error((n||"")+"No instance found for handle",t)},getInstances:function(){return a},get:function(e){if(!i(e))return null;var t,n,o;for(t=0,n=a.length;t');return this.$element.append(e),e},o.prototype.clearTimeout=function(){this.timeout&&(this.$timeout.cancel(this.timeout),this.timeout=null)},o.prototype.isRippleAllowed=function(){var e=this.$element[0];do{if(!e.tagName||"BODY"===e.tagName)break;if(e&&t.isFunction(e.hasAttribute)){if(e.hasAttribute("disabled"))return!1;if("false"===this.inkRipple()||"0"===this.inkRipple())return!1}}while(e=e.parentNode);return!0},o.prototype.inkRipple=function(){return this.$element.attr("md-ink-ripple")},o.prototype.createRipple=function(e,n){function o(e,t,n){return e?Math.max(t,n):Math.sqrt(Math.pow(t,2)+Math.pow(n,2))}if(this.isRippleAllowed()){var i=this,r=i.$mdColorUtil,d=t.element('
'),s=this.$element.prop("clientWidth"),c=this.$element.prop("clientHeight"),l=2*Math.max(Math.abs(s-e),e),m=2*Math.max(Math.abs(c-n),n),u=o(this.options.fitRipple,l,m),p=this.calculateColor();d.css({left:e+"px",top:n+"px",background:"black",width:u+"px",height:u+"px",backgroundColor:r.rgbaToRgb(p),borderColor:r.rgbaToRgb(p)}),this.lastRipple=d,this.clearTimeout(),this.timeout=this.$timeout(function(){i.clearTimeout(),i.mousedown||i.fadeInComplete(d)},.35*a,!1),this.options.dimBackground&&this.container.css({backgroundColor:p}),this.container.append(d),this.ripples.push(d),d.addClass("md-ripple-placed"),this.$mdUtil.nextTick(function(){d.addClass("md-ripple-scaled md-ripple-active"),i.$timeout(function(){i.clearRipples()},a,!1)},!1)}},o.prototype.fadeInComplete=function(e){this.lastRipple===e?this.timeout||this.mousedown||this.removeRipple(e):this.removeRipple(e)},o.prototype.removeRipple=function(e){var t=this,n=this.ripples.indexOf(e);n<0||(this.ripples.splice(this.ripples.indexOf(e),1),e.removeClass("md-ripple-active"),e.addClass("md-ripple-remove"),0===this.ripples.length&&this.container.css({backgroundColor:""}),this.$timeout(function(){t.fadeOutComplete(e)},a,!1))},o.prototype.fadeOutComplete=function(e){e.remove(),this.lastRipple=null}}(),function(){!function(){function e(e){function n(n,o,i){return e.attach(n,o,t.extend({center:!1,dimBackground:!0,outline:!1,rippleSize:"full"},i))}return{attach:n}}e.$inject=["$mdInkRipple"],t.module("material.core").factory("$mdTabInkRipple",e)}()}(),function(){t.module("material.core.theming.palette",[]).constant("$mdColorPalette",{red:{50:"#ffebee",100:"#ffcdd2",200:"#ef9a9a",300:"#e57373",400:"#ef5350",500:"#f44336",600:"#e53935",700:"#d32f2f",800:"#c62828",900:"#b71c1c",A100:"#ff8a80",A200:"#ff5252",A400:"#ff1744",A700:"#d50000",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 300 A100",contrastStrongLightColors:"400 500 600 700 A200 A400 A700"},pink:{50:"#fce4ec",100:"#f8bbd0",200:"#f48fb1",300:"#f06292",400:"#ec407a",500:"#e91e63",600:"#d81b60",700:"#c2185b",800:"#ad1457",900:"#880e4f",A100:"#ff80ab",A200:"#ff4081",A400:"#f50057",A700:"#c51162",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 A100",contrastStrongLightColors:"500 600 A200 A400 A700"},purple:{50:"#f3e5f5",100:"#e1bee7",200:"#ce93d8",300:"#ba68c8",400:"#ab47bc",500:"#9c27b0",600:"#8e24aa",700:"#7b1fa2",800:"#6a1b9a",900:"#4a148c",A100:"#ea80fc",A200:"#e040fb",A400:"#d500f9",A700:"#aa00ff",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 A100",contrastStrongLightColors:"300 400 A200 A400 A700"},"deep-purple":{50:"#ede7f6",100:"#d1c4e9",200:"#b39ddb",300:"#9575cd",400:"#7e57c2",500:"#673ab7",600:"#5e35b1",700:"#512da8",800:"#4527a0",900:"#311b92",A100:"#b388ff",A200:"#7c4dff",A400:"#651fff",A700:"#6200ea",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 A100",contrastStrongLightColors:"300 400 A200"},indigo:{50:"#e8eaf6",100:"#c5cae9",200:"#9fa8da",300:"#7986cb",400:"#5c6bc0",500:"#3f51b5",600:"#3949ab",700:"#303f9f",800:"#283593",900:"#1a237e",A100:"#8c9eff",A200:"#536dfe",A400:"#3d5afe",A700:"#304ffe",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 A100",contrastStrongLightColors:"300 400 A200 A400"},blue:{50:"#e3f2fd",100:"#bbdefb",200:"#90caf9",300:"#64b5f6",400:"#42a5f5",500:"#2196f3",600:"#1e88e5",700:"#1976d2",800:"#1565c0",900:"#0d47a1",A100:"#82b1ff",A200:"#448aff",A400:"#2979ff",A700:"#2962ff",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 300 400 A100",contrastStrongLightColors:"500 600 700 A200 A400 A700"},"light-blue":{50:"#e1f5fe",100:"#b3e5fc",200:"#81d4fa",300:"#4fc3f7",400:"#29b6f6",500:"#03a9f4",600:"#039be5",700:"#0288d1",800:"#0277bd",900:"#01579b",A100:"#80d8ff",A200:"#40c4ff",A400:"#00b0ff",A700:"#0091ea",contrastDefaultColor:"dark",contrastLightColors:"600 700 800 900 A700",contrastStrongLightColors:"600 700 800 A700"},cyan:{50:"#e0f7fa",100:"#b2ebf2",200:"#80deea",300:"#4dd0e1",400:"#26c6da",500:"#00bcd4",600:"#00acc1",700:"#0097a7",800:"#00838f",900:"#006064",A100:"#84ffff",A200:"#18ffff",A400:"#00e5ff",A700:"#00b8d4",contrastDefaultColor:"dark",contrastLightColors:"700 800 900",contrastStrongLightColors:"700 800 900"},teal:{50:"#e0f2f1",100:"#b2dfdb",200:"#80cbc4",300:"#4db6ac",400:"#26a69a",500:"#009688",600:"#00897b",700:"#00796b",800:"#00695c",900:"#004d40",A100:"#a7ffeb",A200:"#64ffda",A400:"#1de9b6",A700:"#00bfa5",contrastDefaultColor:"dark",contrastLightColors:"500 600 700 800 900",contrastStrongLightColors:"500 600 700"},green:{50:"#e8f5e9",100:"#c8e6c9",200:"#a5d6a7",300:"#81c784",400:"#66bb6a",500:"#4caf50",600:"#43a047",700:"#388e3c",800:"#2e7d32",900:"#1b5e20",A100:"#b9f6ca",A200:"#69f0ae",A400:"#00e676",A700:"#00c853",contrastDefaultColor:"dark",contrastLightColors:"500 600 700 800 900",contrastStrongLightColors:"500 600 700"},"light-green":{50:"#f1f8e9",100:"#dcedc8",200:"#c5e1a5",300:"#aed581",400:"#9ccc65",500:"#8bc34a",600:"#7cb342",700:"#689f38",800:"#558b2f",900:"#33691e",A100:"#ccff90",A200:"#b2ff59",A400:"#76ff03",A700:"#64dd17",contrastDefaultColor:"dark",contrastLightColors:"700 800 900",contrastStrongLightColors:"700 800 900"},lime:{50:"#f9fbe7",100:"#f0f4c3",200:"#e6ee9c",300:"#dce775",400:"#d4e157",500:"#cddc39",600:"#c0ca33",700:"#afb42b",800:"#9e9d24",900:"#827717",A100:"#f4ff81",A200:"#eeff41",A400:"#c6ff00",A700:"#aeea00",contrastDefaultColor:"dark",contrastLightColors:"900",contrastStrongLightColors:"900"},yellow:{50:"#fffde7",100:"#fff9c4",200:"#fff59d",300:"#fff176",400:"#ffee58",500:"#ffeb3b",600:"#fdd835",700:"#fbc02d",800:"#f9a825",900:"#f57f17",A100:"#ffff8d",A200:"#ffff00",A400:"#ffea00",A700:"#ffd600",contrastDefaultColor:"dark"},amber:{50:"#fff8e1",100:"#ffecb3",200:"#ffe082",300:"#ffd54f",400:"#ffca28",500:"#ffc107",600:"#ffb300",700:"#ffa000",800:"#ff8f00",900:"#ff6f00",A100:"#ffe57f",A200:"#ffd740",A400:"#ffc400",A700:"#ffab00",contrastDefaultColor:"dark"},orange:{50:"#fff3e0",100:"#ffe0b2",200:"#ffcc80",300:"#ffb74d",400:"#ffa726",500:"#ff9800",600:"#fb8c00",700:"#f57c00",800:"#ef6c00",900:"#e65100",A100:"#ffd180",A200:"#ffab40",A400:"#ff9100",A700:"#ff6d00",contrastDefaultColor:"dark",contrastLightColors:"800 900",contrastStrongLightColors:"800 900"},"deep-orange":{50:"#fbe9e7",100:"#ffccbc",200:"#ffab91",300:"#ff8a65",400:"#ff7043",500:"#ff5722",600:"#f4511e",700:"#e64a19",800:"#d84315",900:"#bf360c",A100:"#ff9e80",A200:"#ff6e40",A400:"#ff3d00",A700:"#dd2c00",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 300 400 A100 A200",contrastStrongLightColors:"500 600 700 800 900 A400 A700"},brown:{50:"#efebe9",100:"#d7ccc8",200:"#bcaaa4",300:"#a1887f",400:"#8d6e63",500:"#795548",600:"#6d4c41",700:"#5d4037",800:"#4e342e",900:"#3e2723",A100:"#d7ccc8",A200:"#bcaaa4",A400:"#8d6e63",A700:"#5d4037",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 A100 A200",contrastStrongLightColors:"300 400"},grey:{50:"#fafafa",100:"#f5f5f5",200:"#eeeeee",300:"#e0e0e0",400:"#bdbdbd",500:"#9e9e9e",600:"#757575",700:"#616161",800:"#424242",900:"#212121",A100:"#ffffff",A200:"#000000",A400:"#303030",A700:"#616161",contrastDefaultColor:"dark",contrastLightColors:"600 700 800 900 A200 A400 A700"},"blue-grey":{50:"#eceff1",100:"#cfd8dc",200:"#b0bec5",300:"#90a4ae",400:"#78909c",500:"#607d8b",600:"#546e7a",700:"#455a64",800:"#37474f",900:"#263238",A100:"#cfd8dc",A200:"#b0bec5",A400:"#78909c",A700:"#455a64",contrastDefaultColor:"light",contrastDarkColors:"50 100 200 300 A100 A200",contrastStrongLightColors:"400 500 700"}})}(),function(){!function(e){function t(e){var t=!!document.querySelector("[md-themes-disabled]");e.disableTheming(t)}function o(t,o){function i(e,t){return t=t||{},p[e]=a(e,t),h}function r(t,n){return a(t,e.extend({},p[t]||{},n))}function a(e,t){var n=w.filter(function(e){return!t[e]});if(n.length)throw new Error("Missing colors %1 in palette %2!".replace("%1",n.join(", ")).replace("%2",e));return t}function s(t,n){if(E[t])return E[t];n=n||"default";var o="string"==typeof n?E[n]:n,i=new l(t);return o&&e.forEach(o.colors,function(t,n){i.colors[n]={name:t.name,hues:e.extend({},t.hues)}}),E[t]=i,i}function l(t){function n(t){if(t=0===arguments.length||!!t,t!==o.isDark){o.isDark=t,o.foregroundPalette=o.isDark?g:f,o.foregroundShadow=o.isDark?b:v;var n=o.isDark?A:T,i=o.isDark?T:A;return e.forEach(n,function(e,t){var n=o.colors[t],r=i[t];if(n)for(var a in n.hues)n.hues[a]===r[a]&&(n.hues[a]=e[a])}),o}}var o=this;o.name=t,o.colors={},o.dark=n,n(!1),C.forEach(function(t){var n=(o.isDark?A:T)[t];o[t+"Palette"]=function(i,r){var a=o.colors[t]={name:i,hues:e.extend({},n,r)};return Object.keys(a.hues).forEach(function(e){if(!n[e])throw new Error("Invalid hue name '%1' in theme %2's %3 color %4. Available hue names: %4".replace("%1",e).replace("%2",o.name).replace("%3",i).replace("%4",Object.keys(n).join(", ")))}),Object.keys(a.hues).map(function(e){return a.hues[e]}).forEach(function(e){if(w.indexOf(e)==-1)throw new Error("Invalid hue value '%1' in theme %2's %3 color %4. Available hue values: %5".replace("%1",e).replace("%2",o.name).replace("%3",t).replace("%4",i).replace("%5",w.join(", ")))}),o},o[t+"Color"]=function(){var e=Array.prototype.slice.call(arguments);return console.warn("$mdThemingProviderTheme."+t+"Color() has been deprecated. Use $mdThemingProviderTheme."+t+"Palette() instead."),o[t+"Palette"].apply(o,e)}})}function m(t,o,i,r){function a(e){return e===n||""===e||l.THEMES[e]!==n}function d(e,t){function n(){return d&&d.$mdTheme||("default"==y?"":y)}function i(t){if(t){a(t)||r.warn("Attempted to use unregistered theme '"+t+"'. Register it with $mdThemingProvider.theme().");var n=e.data("$mdThemeName");n&&e.removeClass("md-"+n+"-theme"),e.addClass("md-"+t+"-theme"),e.data("$mdThemeName",t),d&&e.data("$mdThemeController",d)}}var d=t.controller("mdTheme")||e.data("$mdThemeController");if(i(n()),d)var s=$||d.$shouldWatch||o.parseAttributeBoolean(e.attr("md-theme-watch")),c=d.registerChanges(function(t){i(t),s?e.on("$destroy",c):c()})}var l=function(e,o){o===n&&(o=e,e=n),e===n&&(e=t),l.inherit(o,o)};return Object.defineProperty(l,"THEMES",{get:function(){return e.extend({},E)}}),Object.defineProperty(l,"PALETTES",{get:function(){return e.extend({},p)}}),Object.defineProperty(l,"ALWAYS_WATCH",{get:function(){return $}}),l.inherit=d,l.registered=a,l.defaultTheme=function(){return y},l.generateTheme=function(e){c(E[e],e,k.nonce)},l.defineTheme=function(e,t){t=t||{};var n=s(e);return t.primary&&n.primaryPalette(t.primary),t.accent&&n.accentPalette(t.accent),t.warn&&n.warnPalette(t.warn),t.background&&n.backgroundPalette(t.background),t.dark&&n.dark(),this.generateTheme(e),i.resolve(e)},l.setBrowserColor=_,l}m.$inject=["$rootScope","$mdUtil","$q","$log"],p={};var h,E={},$=!1,y="default";e.extend(p,t);var M=function(e){var t=o.setMeta("theme-color",e),n=o.setMeta("msapplication-navbutton-color",e);return function(){t(),n()}},_=function(t){t=e.isObject(t)?t:{};var n=t.theme||"default",o=t.hue||"800",i=p[t.palette]||p[E[n].colors[t.palette||"primary"].name],r=e.isObject(i[o])?i[o].hex:i[o];return M(r)};return h={definePalette:i,extendPalette:r,theme:s,configuration:function(){return e.extend({},k,{defaultTheme:y,alwaysWatchTheme:$,registeredStyles:[].concat(k.registeredStyles)})},disableTheming:function(t){k.disableTheming=e.isUndefined(t)||!!t},registerStyles:function(e){k.registeredStyles.push(e)},setNonce:function(e){k.nonce=e},generateThemesOnDemand:function(e){k.generateOnDemand=e},setDefaultTheme:function(e){y=e},alwaysWatchTheme:function(e){$=e},enableBrowserColor:_,$get:m,_LIGHT_DEFAULT_HUES:T,_DARK_DEFAULT_HUES:A,_PALETTES:p,_THEMES:E,_parseRules:d,_rgba:u}}function i(t,n,o,i,r,a){return{priority:101,link:{pre:function(d,s,c){var l=[],m=n.startSymbol(),u=n.endSymbol(),p=c.mdTheme.trim(),h=p.substr(0,m.length)===m&&p.lastIndexOf(u)===p.length-u.length,f="::",g=c.mdTheme.split(m).join("").split(u).join("").trim().substr(0,f.length)===f,b={registerChanges:function(t,n){return n&&(t=e.bind(n,t)),l.push(t),function(){var e=l.indexOf(t);e>-1&&l.splice(e,1)}},$setTheme:function(e){t.registered(e)||a.warn("attempted to use unregistered theme '"+e+"'"),b.$mdTheme=e;for(var n=l.length;n--;)l[n](e)},$shouldWatch:i.parseAttributeBoolean(s.attr("md-theme-watch"))||t.ALWAYS_WATCH||h&&!g};s.data("$mdThemeController",b);var v=function(){var e=n(c.mdTheme)(d);return o(e)(d)||e},E=function(t){return"string"==typeof t?b.$setTheme(t):void r.when(e.isFunction(t)?t():t).then(function(e){b.$setTheme(e)})};E(v());var $=d.$watch(v,function(e){e&&(E(e),b.$shouldWatch||$())})}}}}function r(){return k.disableTheming=!0,{restrict:"A",priority:"900"}}function a(e){return e}function d(t,n,o){l(t,n),o=o.replace(/THEME_NAME/g,t.name);var i=[],r=t.colors[n],a=new RegExp("\\.md-"+t.name+"-theme","g"),d=new RegExp("('|\")?{{\\s*("+n+")-(color|contrast)-?(\\d\\.?\\d*)?\\s*}}(\"|')?","g"),s=/'?"?\{\{\s*([a-zA-Z]+)-(A?\d+|hue\-[0-3]|shadow|default)-?(\d\.?\d*)?(contrast)?\s*\}\}'?"?/g,c=p[r.name];return o=o.replace(s,function(e,n,o,i,r){return"foreground"===n?"shadow"==o?t.foregroundShadow:t.foregroundPalette[o]||t.foregroundPalette[1]:(0!==o.indexOf("hue")&&"default"!==o||(o=t.colors[n].hues[o]),u((p[t.colors[n].name][o]||"")[r?"contrast":"value"],i))}),e.forEach(r.hues,function(e,n){var r=o.replace(d,function(t,n,o,i,r){return u(c[e]["color"===i?"value":"contrast"],r)});if("default"!==n&&(r=r.replace(a,".md-"+t.name+"-theme.md-"+n)),"default"==t.name){var s=/((?:\s|>|\.|\w|-|:|\(|\)|\[|\]|"|'|=)*)\.md-default-theme((?:\s|>|\.|\w|-|:|\(|\)|\[|\]|"|'|=)*)/g;r=r.replace(s,function(e,t,n){return e+", "+t+n})}i.push(r)}),i}function s(t,n){function o(t,n){var o=t.contrastDefaultColor,i=t.contrastLightColors||[],r=t.contrastStrongLightColors||[],a=t.contrastDarkColors||[];"string"==typeof i&&(i=i.split(" ")),"string"==typeof r&&(r=r.split(" ")),"string"==typeof a&&(a=a.split(" ")),delete t.contrastDefaultColor,delete t.contrastLightColors,delete t.contrastStrongLightColors,delete t.contrastDarkColors,e.forEach(t,function(n,d){function s(){return"light"===o?a.indexOf(d)>-1?E:r.indexOf(d)>-1?y:$:i.indexOf(d)>-1?r.indexOf(d)>-1?y:$:E}if(!e.isObject(n)){var c=m(n);if(!c)throw new Error("Color %1, in palette %2's hue %3, is invalid. Hex or rgb(a) color expected.".replace("%1",n).replace("%2",t.name).replace("%3",d));t[d]={hex:t[d],value:c,contrast:s()}}})}var i=document.head,r=i?i.firstElementChild:null,a=!k.disableTheming&&t.has("$MD_THEME_CSS")?t.get("$MD_THEME_CSS"):"";if(a+=k.registeredStyles.join(""),r&&0!==a.length){e.forEach(p,o);var d=a.split(/\}(?!(\}|'|"|;))/).filter(function(e){return e&&e.trim().length}).map(function(e){return e.trim()+"}"}),s=new RegExp("md-("+C.join("|")+")","g");C.forEach(function(e){_[e]=""}),d.forEach(function(e){for(var t,n=(e.match(s),0);t=C[n];n++)if(e.indexOf(".md-"+t)>-1)return _[t]+=e;for(n=0;t=C[n];n++)if(e.indexOf(t)>-1)return _[t]+=e;return _[M]+=e}),k.generateOnDemand||e.forEach(n.THEMES,function(e){ h[e.name]||"default"!==n.defaultTheme()&&"default"===e.name||c(e,e.name,k.nonce)})}}function c(e,t,n){var o=document.head,i=o?o.firstElementChild:null;h[t]||(C.forEach(function(t){for(var r=d(e,t,_[t]);r.length;){var a=r.shift();if(a){var s=document.createElement("style");s.setAttribute("md-theme-style",""),n&&s.setAttribute("nonce",n),s.appendChild(document.createTextNode(a)),o.insertBefore(s,i)}}}),h[e.name]=!0)}function l(e,t){if(!p[(e.colors[t]||{}).name])throw new Error("You supplied an invalid color palette for theme %1's %2 palette. Available palettes: %3".replace("%1",e.name).replace("%2",t).replace("%3",Object.keys(p).join(", ")))}function m(t){if(e.isArray(t)&&3==t.length)return t;if(/^rgb/.test(t))return t.replace(/(^\s*rgba?\(|\)\s*$)/g,"").split(",").map(function(e,t){return 3==t?parseFloat(e,10):parseInt(e,10)});if("#"==t.charAt(0)&&(t=t.substring(1)),/^([a-fA-F0-9]{3}){1,2}$/g.test(t)){var n=t.length/3,o=t.substr(0,n),i=t.substr(n,n),r=t.substr(2*n);return 1===n&&(o+=o,i+=i,r+=r),[parseInt(o,16),parseInt(i,16),parseInt(r,16)]}}function u(t,n){return t?(4==t.length&&(t=e.copy(t),n?t.pop():n=t.pop()),n&&("number"==typeof n||"string"==typeof n&&n.length)?"rgba("+t.join(",")+","+n+")":"rgb("+t.join(",")+")"):"rgb('0,0,0')"}t.$inject=["$mdThemingProvider"],i.$inject=["$mdTheming","$interpolate","$parse","$mdUtil","$q","$log"],a.$inject=["$mdTheming"],o.$inject=["$mdColorPalette","$$mdMetaProvider"],s.$inject=["$injector","$mdTheming"],e.module("material.core.theming",["material.core.theming.palette","material.core.meta"]).directive("mdTheme",i).directive("mdThemable",a).directive("mdThemesDisabled",r).provider("$mdTheming",o).config(t).run(s);var p,h={},f={name:"dark",1:"rgba(0,0,0,0.87)",2:"rgba(0,0,0,0.54)",3:"rgba(0,0,0,0.38)",4:"rgba(0,0,0,0.12)"},g={name:"light",1:"rgba(255,255,255,1.0)",2:"rgba(255,255,255,0.7)",3:"rgba(255,255,255,0.5)",4:"rgba(255,255,255,0.12)"},b="1px 1px 0px rgba(0,0,0,0.4), -1px -1px 0px rgba(0,0,0,0.4)",v="",E=m("rgba(0,0,0,0.87)"),$=m("rgba(255,255,255,0.87)"),y=m("rgb(255,255,255)"),C=["primary","accent","warn","background"],M="primary",T={accent:{"default":"A200","hue-1":"A100","hue-2":"A400","hue-3":"A700"},background:{"default":"50","hue-1":"A100","hue-2":"100","hue-3":"300"}},A={background:{"default":"A400","hue-1":"800","hue-2":"900","hue-3":"A200"}};C.forEach(function(e){var t={"default":"500","hue-1":"300","hue-2":"800","hue-3":"A100"};T[e]||(T[e]=t),A[e]||(A[e]=t)});var w=["50","100","200","300","400","500","600","700","800","900","A100","A200","A400","A700"],k={disableTheming:!1,generateOnDemand:!1,registeredStyles:[],nonce:null},_={}}(e.angular)}(),function(){function n(n,o,i,r,a){var d;return d={translate3d:function(e,t,n,o){function i(n){return a(e,{to:n||t,addClass:o.transitionOutClass,removeClass:o.transitionInClass,duration:o.duration}).start()}return a(e,{from:t,to:n,addClass:o.transitionInClass,removeClass:o.transitionOutClass,duration:o.duration}).start().then(function(){return i})},waitTransitionEnd:function(t,n){var a=3e3;return o(function(o,d){function s(e){e&&e.target!==t[0]||(e&&i.cancel(l),t.off(r.CSS.TRANSITIONEND,s),o())}function c(n){return n=n||e.getComputedStyle(t[0]),"0s"==n.transitionDuration||!n.transition&&!n.transitionProperty}n=n||{},c(n.cachedTransitionStyles)&&(a=0);var l=i(s,n.timeout||a);t.on(r.CSS.TRANSITIONEND,s)})},calculateTransformValues:function(e,t){function n(){var t=e?e.parent():null,n=t?t.parent():null;return n?d.clientRect(n):null}var o=t.element,i=t.bounds;if(o||i){var r=o?d.clientRect(o)||n():d.copyRect(i),a=d.copyRect(e[0].getBoundingClientRect()),s=d.centerPointFor(a),c=d.centerPointFor(r);return{centerX:c.x-s.x,centerY:c.y-s.y,scaleX:Math.round(100*Math.min(.5,r.width/a.width))/100,scaleY:Math.round(100*Math.min(.5,r.height/a.height))/100}}return{centerX:0,centerY:0,scaleX:.5,scaleY:.5}},calculateZoomToOrigin:function(e,o){var i="translate3d( {centerX}px, {centerY}px, 0 ) scale( {scaleX}, {scaleY} )",r=t.bind(null,n.supplant,i);return r(d.calculateTransformValues(e,o))},calculateSlideToOrigin:function(e,o){var i="translate3d( {centerX}px, {centerY}px, 0 )",r=t.bind(null,n.supplant,i);return r(d.calculateTransformValues(e,o))},toCss:function(e){function n(e,n,i){t.forEach(n.split(" "),function(e){o[e]=i})}var o={},i="left top right bottom width height x y min-width min-height max-width max-height";return t.forEach(e,function(e,a){if(!t.isUndefined(e))if(i.indexOf(a)>=0)o[a]=e+"px";else switch(a){case"transition":n(a,r.CSS.TRANSITION,e);break;case"transform":n(a,r.CSS.TRANSFORM,e);break;case"transformOrigin":n(a,r.CSS.TRANSFORM_ORIGIN,e);break;case"font-size":o["font-size"]=e}}),o},toTransformCss:function(e,n,o){var i={};return t.forEach(r.CSS.TRANSFORM.split(" "),function(t){i[t]=e}),n&&(o=o||"all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important",i.transition=o),i},copyRect:function(e,n){return e?(n=n||{},t.forEach("left top right bottom width height".split(" "),function(t){n[t]=Math.round(e[t])}),n.width=n.width||n.right-n.left,n.height=n.height||n.bottom-n.top,n):null},clientRect:function(e){var n=t.element(e)[0].getBoundingClientRect(),o=function(e){return e&&e.width>0&&e.height>0};return o(n)?d.copyRect(n):null},centerPointFor:function(e){return e?{x:Math.round(e.left+e.width/2),y:Math.round(e.top+e.height/2)}:{x:0,y:0}}}}t.module("material.core").factory("$$mdAnimate",["$q","$timeout","$mdConstant","$animateCss",function(e,t,o,i){return function(r){return n(r,e,t,o,i)}}])}(),function(){t.version.minor>=4?t.module("material.core.animate",[]):!function(){function e(e){return e.replace(/-[a-z]/g,function(e){return e.charAt(1).toUpperCase()})}var n=t.forEach,o=t.isDefined(document.documentElement.style.WebkitAppearance),i=o?"-webkit-":"",r=(o?"webkitTransitionEnd ":"")+"transitionend",a=(o?"webkitAnimationEnd ":"")+"animationend",d=["$document",function(e){return function(){return e[0].body.clientWidth+1}}],s=["$$rAF",function(e){return function(){var t=!1;return e(function(){t=!0}),function(n){t?n():e(n)}}}],c=["$q","$$rAFMutex",function(e,o){function i(e){this.setHost(e),this._doneCallbacks=[],this._runInAnimationFrame=o(),this._state=0}var r=0,a=1,d=2;return i.prototype={setHost:function(e){this.host=e||{}},done:function(e){this._state===d?e():this._doneCallbacks.push(e)},progress:t.noop,getPromise:function(){if(!this.promise){var t=this;this.promise=e(function(e,n){t.done(function(t){t===!1?n():e()})})}return this.promise},then:function(e,t){return this.getPromise().then(e,t)},"catch":function(e){return this.getPromise()["catch"](e)},"finally":function(e){return this.getPromise()["finally"](e)},pause:function(){this.host.pause&&this.host.pause()},resume:function(){this.host.resume&&this.host.resume()},end:function(){this.host.end&&this.host.end(),this._resolve(!0)},cancel:function(){this.host.cancel&&this.host.cancel(),this._resolve(!1)},complete:function(e){var t=this;t._state===r&&(t._state=a,t._runInAnimationFrame(function(){t._resolve(e)}))},_resolve:function(e){this._state!==d&&(n(this._doneCallbacks,function(t){t(e)}),this._doneCallbacks.length=0,this._state=d)}},i.all=function(e,t){function o(n){r=r&&n,++i===e.length&&t(r)}var i=0,r=!0;n(e,function(e){e.done(o)})},i}];t.module("material.core.animate",[]).factory("$$forceReflow",d).factory("$$AnimateRunner",c).factory("$$rAFMutex",s).factory("$animateCss",["$window","$$rAF","$$AnimateRunner","$$forceReflow","$$jqLite","$timeout","$animate",function(t,d,s,c,l,m,u){function p(o,d){var c=[],l=y(o),p=l&&u.enabled(),g=!1,M=!1;p&&(d.transitionStyle&&c.push([i+"transition",d.transitionStyle]),d.keyframeStyle&&c.push([i+"animation",d.keyframeStyle]),d.delay&&c.push([i+"transition-delay",d.delay+"s"]),d.duration&&c.push([i+"transition-duration",d.duration+"s"]),g=d.keyframeStyle||d.to&&(d.duration>0||d.transitionStyle),M=!!d.addClass||!!d.removeClass,C(o,!0));var T=p&&(g||M);E(o,d);var A,w,k=!1;return{close:t.close,start:function(){function t(){if(!k)return k=!0,A&&w&&o.off(A,w),h(o,d),v(o,d),n(c,function(t){l.style[e(t[0])]=""}),u.complete(!0),u}var u=new s;return b(function(){if(C(o,!1),!T)return t();n(c,function(t){var n=t[0],o=t[1];l.style[e(n)]=o}),h(o,d);var s=f(o);if(0===s.duration)return t();var u=[];d.easing&&(s.transitionDuration&&u.push([i+"transition-timing-function",d.easing]),s.animationDuration&&u.push([i+"animation-timing-function",d.easing])),d.delay&&s.animationDelay&&u.push([i+"animation-delay",d.delay+"s"]),d.duration&&s.animationDuration&&u.push([i+"animation-duration",d.duration+"s"]),n(u,function(t){var n=t[0],o=t[1];l.style[e(n)]=o,c.push(t)});var p=s.delay,g=1e3*p,b=s.duration,v=1e3*b,E=Date.now();A=[],s.transitionDuration&&A.push(r),s.animationDuration&&A.push(a),A=A.join(" "),w=function(e){e.stopPropagation();var n=e.originalEvent||e,o=n.timeStamp||Date.now(),i=parseFloat(n.elapsedTime.toFixed(3));Math.max(o-E,0)>=g&&i>=b&&t()},o.on(A,w),$(o,d),m(t,g+1.5*v,!1)}),u}}}function h(e,t){t.addClass&&(l.addClass(e,t.addClass),t.addClass=null),t.removeClass&&(l.removeClass(e,t.removeClass),t.removeClass=null)}function f(e){function n(e){return o?"Webkit"+e.charAt(0).toUpperCase()+e.substr(1):e}var i=y(e),r=t.getComputedStyle(i),a=g(r[n("transitionDuration")]),d=g(r[n("animationDuration")]),s=g(r[n("transitionDelay")]),c=g(r[n("animationDelay")]);d*=parseInt(r[n("animationIterationCount")],10)||1;var l=Math.max(d,a),m=Math.max(c,s);return{duration:l,delay:m,animationDuration:d,transitionDuration:a,animationDelay:c,transitionDelay:s}}function g(e){var t=0,o=(e||"").split(/\s*,\s*/);return n(o,function(e){"s"==e.charAt(e.length-1)&&(e=e.substring(0,e.length-1)),e=parseFloat(e)||0,t=t?Math.max(e,t):e}),t}function b(e){M&&M(),T.push(e),M=d(function(){M=null;for(var e=c(),t=0;t0&&(t.pointer.distanceY>20||Math.abs(t.pointer.velocityY)>o)){var i=e.prop("offsetHeight")-t.pointer.distanceY,a=Math.min(i/t.pointer.velocityY*.75,500);e.css(n.CSS.TRANSITION_DURATION,a+"ms"),r.nextTick(d.cancel,!0)}else e.css(n.CSS.TRANSITION_DURATION,""),e.css(n.CSS.TRANSFORM,"")}var m=c.register(t,"drag",{horizontal:!1});return t.on("$md.dragstart",a).on("$md.drag",s).on("$md.dragend",l),{element:e,cleanup:function(){m(),t.off("$md.dragstart",a),t.off("$md.drag",s),t.off("$md.dragend",l)}}}var h;return{themable:!0,onShow:m,onRemove:u,disableBackdrop:!1,escapeToClose:!0,clickOutsideToClose:!0,disableParentScroll:!0}}n.$inject=["$animate","$mdConstant","$mdUtil","$mdTheming","$mdBottomSheet","$rootElement","$mdGesture","$log"];var o=.5,i=80;return e("$mdBottomSheet").setDefaults({methods:["disableParentScroll","escapeToClose","clickOutsideToClose"],options:n})}e.$inject=["$mdBottomSheet"],n.$inject=["$$interimElementProvider"],t.module("material.components.bottomSheet",["material.core","material.components.backdrop"]).directive("mdBottomSheet",e).provider("$mdBottomSheet",n)}(),function(){function e(e){return{restrict:"E",link:function(t,n){e(n)}}}function n(e,n,o,i){function r(e){return t.isDefined(e.href)||t.isDefined(e.ngHref)||t.isDefined(e.ngLink)||t.isDefined(e.uiSref)}function a(e,t){if(r(t))return'';var n="undefined"==typeof t.type?"button":t.type;return''}function d(a,d,s){n(d),e.attach(a,d),o.expectWithoutText(d,"aria-label"),r(s)&&t.isDefined(s.ngDisabled)&&a.$watch(s.ngDisabled,function(e){d.attr("tabindex",e?-1:0)}),d.on("click",function(e){s.disabled===!0&&(e.preventDefault(),e.stopImmediatePropagation())}),d.hasClass("md-no-focus")||(d.on("focus",function(){i.isUserInvoked()&&"keyboard"!==i.getLastInteractionType()||d.addClass("md-focused")}),d.on("blur",function(){d.removeClass("md-focused")}))}return{restrict:"EA",replace:!0,transclude:!0,template:a,link:d}}n.$inject=["$mdButtonInkRipple","$mdTheming","$mdAria","$mdInteraction"],e.$inject=["$mdTheming"],t.module("material.components.button",["material.core"]).directive("mdButton",n).directive("a",e)}(),function(){function e(e){return{restrict:"E",link:function(t,n,o){n.addClass("_md"),e(n)}}}e.$inject=["$mdTheming"],t.module("material.components.card",["material.core"]).directive("mdCard",e)}(),function(){function e(e,n,o,i,r,a){function d(d,s){function c(d,s,c,l){function m(e,t,n){c[e]&&d.$watch(c[e],function(e){n[e]&&s.attr(t,n[e])})}function u(e){var t=e.which||e.keyCode;t!==o.KEY_CODE.SPACE&&t!==o.KEY_CODE.ENTER||(e.preventDefault(),s.addClass("md-focused"),p(e))}function p(e){s[0].hasAttribute("disabled")||d.skipToggle||d.$apply(function(){var t=c.ngChecked&&c.ngClick?c.checked:!v.$viewValue;v.$setViewValue(t,e&&e.type),v.$render()})}function h(){s.toggleClass("md-checked",!!v.$viewValue&&!g)}function f(e){g=e!==!1,g&&s.attr("aria-checked","mixed"),s.toggleClass("md-indeterminate",g)}var g,b=l[0],v=l[1]||r.fakeNgModel(),E=l[2];if(b){var $=b.isErrorGetter||function(){return v.$invalid&&(v.$touched||E&&E.$submitted)};b.input=s,d.$watch($,b.setInvalid)}i(s),s.children().on("focus",function(){s.focus()}),r.parseAttributeBoolean(c.mdIndeterminate)&&(f(),d.$watch(c.mdIndeterminate,f)),c.ngChecked&&d.$watch(d.$eval.bind(d,c.ngChecked),function(e){v.$setViewValue(e),v.$render()}),m("ngDisabled","tabindex",{"true":"-1","false":c.tabindex}),n.expectWithText(s,"aria-label"),e.link.pre(d,{on:t.noop,0:{}},c,[v]),s.on("click",p).on("keypress",u).on("focus",function(){"keyboard"===a.getLastInteractionType()&&s.addClass("md-focused")}).on("blur",function(){s.removeClass("md-focused")}),v.$render=h}return s.$set("tabindex",s.tabindex||"0"),s.$set("type","checkbox"),s.$set("role",s.type),{pre:function(e,t){t.on("click",function(e){this.hasAttribute("disabled")&&e.stopImmediatePropagation()})},post:c}}return e=e[0],{restrict:"E",transclude:!0,require:["^?mdInputContainer","?ngModel","?^form"],priority:o.BEFORE_NG_ARIA,template:'
',compile:d}}e.$inject=["inputDirective","$mdAria","$mdConstant","$mdTheming","$mdUtil","$mdInteraction"],t.module("material.components.checkbox",["material.core"]).directive("mdCheckbox",e)}(),function(){t.module("material.components.chips",["material.core","material.components.autocomplete"])}(),function(){!function(){function e(e,n,o){function r(e,t){try{t&&e.css(s(t))}catch(n){o.error(n.message)}}function a(e){var t=l(e);return d(t)}function d(t,o){o=o||!1;var i=e.PALETTES[t.palette][t.hue];return i=o?i.contrast:i.value,n.supplant("rgba({0}, {1}, {2}, {3})",[i[0],i[1],i[2],i[3]||t.opacity])}function s(e){var n={},o=e.hasOwnProperty("color");return t.forEach(e,function(e,t){var i=l(e),r=t.indexOf("background")>-1;n[t]=d(i),r&&!o&&(n.color=d(i,!0))}),n}function c(n){return t.isDefined(e.THEMES[n.split("-")[0]])}function l(n){var o=n.split("-"),i=t.isDefined(e.THEMES[o[0]]),r=i?o.splice(0,1)[0]:e.defaultTheme();return{theme:r,palette:m(o,r),hue:u(o,r),opacity:o[2]||1}}function m(t,o){var r=t.length>1&&i.indexOf(t[1])!==-1,a=t[0].replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();if(r&&(a=t[0]+"-"+t.splice(1,1)),i.indexOf(a)===-1){var d=e.THEMES[o].colors[a];if(!d)throw new Error(n.supplant("mdColors: couldn't find '{palette}' in the palettes.",{palette:a}));a=d.name}return a}function u(t,o){var i=e.THEMES[o].colors;if("hue"===t[1]){var r=parseInt(t.splice(2,1)[0],10);if(r<1||r>3)throw new Error(n.supplant("mdColors: 'hue-{hueNumber}' is not a valid hue, can be only 'hue-1', 'hue-2' and 'hue-3'",{hueNumber:r}));if(t[1]="hue-"+r,!(t[0]in i))throw new Error(n.supplant("mdColors: 'hue-x' can only be used with [{availableThemes}], but was used with '{usedTheme}'",{availableThemes:Object.keys(i).join(", "),usedTheme:t[0]}));return i[t[0]].hues[t[1]]}return t[1]||i[t[0]in i?t[0]:"primary"].hues["default"]}return i=i||Object.keys(e.PALETTES),{applyThemeColors:r,getThemeColor:a,hasTheme:c}}function n(e,n,i,r){return{restrict:"A",require:["^?mdTheme"],compile:function(a,d){function s(){var e=d.mdColors,i=e.indexOf("::")>-1,r=!!i||o.test(d.mdColors);d.mdColors=e.replace("::","");var a=t.isDefined(d.mdColorsWatch);return!i&&!r&&(!a||n.parseAttributeBoolean(d.mdColorsWatch))}var c=s();return function(n,o,a,d){var s=d[0],l={},m=function(t){"string"!=typeof t&&(t=""),a.mdColors||(a.mdColors="{}");var o=r(a.mdColors)(n);return s&&Object.keys(o).forEach(function(n){var i=o[n];e.hasTheme(i)||(o[n]=(t||s.$mdTheme)+"-"+i)}),u(o),o},u=function(e){if(!t.equals(e,l)){var n=Object.keys(l);l.background&&!n.color&&n.push("color"),n.forEach(function(e){o.css(e,"")})}l=e},p=t.noop;s&&(p=s.registerChanges(function(t){e.applyThemeColors(o,m(t))})),n.$on("$destroy",function(){p()});try{c?n.$watch(m,t.bind(this,e.applyThemeColors,o),!0):e.applyThemeColors(o,m())}catch(h){i.error(h.message)}}}}}n.$inject=["$mdColors","$mdUtil","$log","$parse"],e.$inject=["$mdTheming","$mdUtil","$log"];var o=/^{((\s|,)*?["'a-zA-Z-]+?\s*?:\s*?('|")[a-zA-Z0-9-.]*('|"))+\s*}$/,i=null;t.module("material.components.colors",["material.core"]).directive("mdColors",n).service("$mdColors",e)}()}(),function(){function e(e){function t(e,t){this.$scope=e,this.$element=t}return{restrict:"E",controller:["$scope","$element",t],link:function(t,o){o.addClass("_md"),e(o),t.$broadcast("$mdContentLoaded",o),n(o[0])}}}function n(e){t.element(e).on("$md.pressdown",function(t){"t"===t.pointer.type&&(t.$materialScrollFixed||(t.$materialScrollFixed=!0,0===e.scrollTop?e.scrollTop=1:e.scrollHeight===e.scrollTop+e.offsetHeight&&(e.scrollTop-=1)))})}e.$inject=["$mdTheming"],t.module("material.components.content",["material.core"]).directive("mdContent",e)}(),function(){t.module("material.components.datepicker",["material.core","material.components.icon","material.components.virtualRepeat"])}(),function(){function e(e,n,o){return{restrict:"E",link:function(i,r){r.addClass("_md"),n(r),e(function(){function e(){r.toggleClass("md-content-overflow",a.scrollHeight>a.clientHeight)}var n,a=r[0].querySelector("md-dialog-content");a&&(n=a.getElementsByTagName("img"),e(),t.element(n).on("load",e)),i.$on("$destroy",function(){o.destroy(r)})})}}}function o(e){function o(){return{template:['',' ','

{{ dialog.title }}

','
','
',"

{{::dialog.mdTextContent}}

","
",' ',' '," ","
"," ",' '," {{ dialog.cancel }}"," ",' '," {{ dialog.ok }}"," "," ","
"].join("").replace(/\s\s+/g,""),controller:i,controllerAs:"dialog",bindToController:!0}}function i(e,t){this.$onInit=function(){var n="prompt"==this.$type;n&&this.initialValue&&(this.result=this.initialValue),this.hide=function(){e.hide(!n||this.result)},this.abort=function(){e.cancel()},this.keypress=function(n){n.keyCode===t.KEY_CODE.ENTER&&e.hide(this.result)}}}function r(e,o,i,r,s,c,l,m,u,p,h,f,g){function b(e){e.defaultTheme=h.defaultTheme(),y(e)}function v(e,t,n,o){if(o){var i=o.htmlContent||n.htmlContent||"",r=o.textContent||n.textContent||o.content||n.content||"";if(i&&!p.has("$sanitize"))throw Error("The ngSanitize module must be loaded in order to use htmlContent.");if(i&&r)throw Error("md-dialog cannot have both `htmlContent` and `textContent`");o.mdHtmlContent=i,o.mdTextContent=r}}function E(e,n,o,r){function a(){n[0].querySelector(".md-actions")&&u.warn("Using a class of md-actions is deprecated, please use .")}function d(){function e(){return n[0].querySelector(".dialog-close, md-dialog-actions button:last-child")}if(o.focusOnOpen){var t=i.findFocusTarget(n)||e()||s;t.focus()}}t.element(c[0].body).addClass("md-dialog-is-showing");var s=n.find("md-dialog");if(s.hasClass("ng-cloak")){var l="$mdDialog: using `` will affect the dialog opening animations.";u.warn(l,n[0])}return C(o),A(s,o),T(e,n,o),M(n,o),_(n,o).then(function(){w(n,o),a(),d()})}function $(e,n,o){function i(){return x(n,o)}function r(){t.element(c[0].body).removeClass("md-dialog-is-showing"),o.contentElement&&o.reverseContainerStretch(),o.cleanupElement(),o.$destroy||"keyboard"!==o.originInteraction||o.origin.focus()}return o.deactivateListeners(),o.unlockScreenReader(),o.hideBackdrop(o.$destroy),a&&a.parentNode&&a.parentNode.removeChild(a),d&&d.parentNode&&d.parentNode.removeChild(d),o.$destroy?r():i().then(r)}function y(e){var n;e.targetEvent&&e.targetEvent.target&&(n=t.element(e.targetEvent.target));var o=n&&n.controller("mdTheme");if(o){e.themeWatch=o.$shouldWatch;var i=e.theme||o.$mdTheme;i&&(e.scope.theme=i);var r=o.registerChanges(function(t){e.scope.theme=t,e.themeWatch||r()})}}function C(e){function o(e,o){var i=t.element(e||{});if(i&&i.length){var r={top:0,left:0,height:0,width:0},a=t.isFunction(i[0].getBoundingClientRect);return t.extend(o||{},{element:a?i:n,bounds:a?i[0].getBoundingClientRect():t.extend({},r,i[0]),focus:t.bind(i,i.focus)})}}function i(e,n){return t.isString(e)&&(e=c[0].querySelector(e)),t.element(e||n)}e.origin=t.extend({element:null,bounds:null,focus:t.noop},e.origin||{}),e.parent=i(e.parent,m),e.closeTo=o(i(e.closeTo)),e.openFrom=o(i(e.openFrom)),e.targetEvent&&(e.origin=o(e.targetEvent.target,e.origin),e.originInteraction=g.getLastInteractionType())}function M(n,o){var a=t.element(l),d=i.debounce(function(){k(n,o)},60),s=[],c=function(){var t="alert"==o.$type?e.hide:e.cancel;i.nextTick(t,!0)};if(o.escapeToClose){var m=o.parent,u=function(e){e.keyCode===r.KEY_CODE.ESCAPE&&(e.stopPropagation(),e.preventDefault(),c())};n.on("keydown",u),m.on("keydown",u),s.push(function(){n.off("keydown",u),m.off("keydown",u)})}if(a.on("resize",d),s.push(function(){a.off("resize",d)}),o.clickOutsideToClose){var p,h=n,f=function(e){p=e.target},g=function(e){p===h[0]&&e.target===h[0]&&(e.stopPropagation(),e.preventDefault(),c())};h.on("mousedown",f),h.on("mouseup",g),s.push(function(){h.off("mousedown",f),h.off("mouseup",g)})}o.deactivateListeners=function(){s.forEach(function(e){e()}),o.deactivateListeners=null}}function T(e,t,n){n.disableParentScroll&&(n.restoreScroll=i.disableScrollAround(t,n.parent)),n.hasBackdrop&&(n.backdrop=i.createBackdrop(e,"md-dialog-backdrop md-opaque"),s.enter(n.backdrop,n.parent)),n.hideBackdrop=function(e){n.backdrop&&(e?n.backdrop.remove():s.leave(n.backdrop)),n.disableParentScroll&&(n.restoreScroll&&n.restoreScroll(),delete n.restoreScroll),n.hideBackdrop=null}}function A(e,t){var n="alert"===t.$type?"alertdialog":"dialog",r=e.find("md-dialog-content"),s=e.attr("id"),c="dialogContent_"+(s||i.nextUid());e.attr({role:n,tabIndex:"-1"}),0===r.length&&(r=e,s&&(c=s)),r.attr("id",c),e.attr("aria-describedby",c),t.ariaLabel?o.expect(e,"aria-label",t.ariaLabel):o.expectAsync(e,"aria-label",function(){if(t.title)return t.title;var e=r.text().split(/\s+/);return e.length>3&&(e=e.slice(0,3).concat("...")),e.join(" ")}),a=document.createElement("div"),a.classList.add("md-dialog-focus-trap"),a.tabIndex=0,d=a.cloneNode(!1);var l=function(){e.focus()};a.addEventListener("focus",l),d.addEventListener("focus",l),e[0].parentNode.insertBefore(a,e[0]),e.after(d)}function w(e,t){function n(e){for(;e.parentNode;){if(e===document.body)return;for(var t=e.parentNode.children,i=0;i/g.test(e)?""+(e||"")+"":e||""}var o=f.startSymbol(),i=f.endSymbol(),r=o+(t.themeWatch?"":"::")+"theme"+i;return'
'+n(e)+"
"}}}i.$inject=["$mdDialog","$mdConstant"],r.$inject=["$mdDialog","$mdAria","$mdUtil","$mdConstant","$animate","$document","$window","$rootElement","$log","$injector","$mdTheming","$interpolate","$mdInteraction"];var a,d;return e("$mdDialog").setDefaults({methods:["disableParentScroll","hasBackdrop","clickOutsideToClose","escapeToClose","targetEvent","closeTo","openFrom","parent","fullscreen","multiple"],options:r}).addPreset("alert",{methods:["title","htmlContent","textContent","content","ariaLabel","ok","theme","css"],options:o}).addPreset("confirm",{methods:["title","htmlContent","textContent","content","ariaLabel","ok","cancel","theme","css"],options:o}).addPreset("prompt",{methods:["title","htmlContent","textContent","initialValue","content","placeholder","ariaLabel","ok","cancel","theme","css","required"],options:o})}e.$inject=["$$rAF","$mdTheming","$mdDialog"],o.$inject=["$$interimElementProvider"],t.module("material.components.dialog",["material.core","material.components.backdrop"]).directive("mdDialog",e).provider("$mdDialog",o)}(),function(){function e(e){return{restrict:"E",link:e}}e.$inject=["$mdTheming"],t.module("material.components.divider",["material.core"]).directive("mdDivider",e)}(),function(){!function(){function e(e){return{restrict:"E",require:["^?mdFabSpeedDial","^?mdFabToolbar"],compile:function(t,n){var o=t.children(),i=e.prefixer().hasAttribute(o,"ng-repeat");i?o.addClass("md-fab-action-item"):o.wrap('
')}}}e.$inject=["$mdUtil"],t.module("material.components.fabActions",["material.core"]).directive("mdFabActions",e)}()}(),function(){!function(){function e(e,n,o,i,r,a){function d(){N.direction=N.direction||"down",N.isOpen=N.isOpen||!1,l(),n.addClass("md-animations-waiting")}function s(){var o=["click","focusin","focusout"];t.forEach(o,function(e){n.on(e,c)}),e.$on("$destroy",function(){t.forEach(o,function(e){n.off(e,c)}),h()})}function c(e){"click"==e.type&&k(e),"focusout"!=e.type||D||(D=a(function(){N.close()},100,!1)),"focusin"==e.type&&D&&(a.cancel(D),D=null)}function l(){N.currentActionIndex=-1}function m(){e.$watch("vm.direction",function(e,t){o.removeClass(n,"md-"+t),o.addClass(n,"md-"+e),l()});var t,i;e.$watch("vm.isOpen",function(e){l(),t&&i||(t=_(),i=x()),e?p():h();var r=e?"md-is-open":"",a=e?"":"md-is-open";t.attr("aria-haspopup",!0),t.attr("aria-expanded",e),i.attr("aria-hidden",!e),o.setClass(n,r,a)})}function u(){n[0].scrollHeight>0?o.addClass(n,"_md-animations-ready").then(function(){n.removeClass("md-animations-waiting")}):S<10&&(a(u,100),S+=1)}function p(){n.on("keydown",g),i.nextTick(function(){t.element(document).on("click touchend",f)})}function h(){n.off("keydown",g),t.element(document).off("click touchend",f)}function f(e){if(e.target){var t=i.getClosest(e.target,"md-fab-trigger"),n=i.getClosest(e.target,"md-fab-actions");t||n||N.close(); }}function g(e){switch(e.which){case r.KEY_CODE.ESCAPE:return N.close(),e.preventDefault(),!1;case r.KEY_CODE.LEFT_ARROW:return y(e),!1;case r.KEY_CODE.UP_ARROW:return C(e),!1;case r.KEY_CODE.RIGHT_ARROW:return M(e),!1;case r.KEY_CODE.DOWN_ARROW:return T(e),!1}}function b(e){E(e,-1)}function v(e){E(e,1)}function E(e,n){var o=$();N.currentActionIndex=N.currentActionIndex+n,N.currentActionIndex=Math.min(o.length-1,N.currentActionIndex),N.currentActionIndex=Math.max(0,N.currentActionIndex);var i=t.element(o[N.currentActionIndex]).children()[0];t.element(i).attr("tabindex",0),i.focus(),e.preventDefault(),e.stopImmediatePropagation()}function $(){var e=x()[0].querySelectorAll(".md-fab-action-item");return t.forEach(e,function(e){t.element(t.element(e).children()[0]).attr("tabindex",-1)}),e}function y(e){"left"===N.direction?v(e):b(e)}function C(e){"down"===N.direction?b(e):v(e)}function M(e){"left"===N.direction?b(e):v(e)}function T(e){"up"===N.direction?b(e):v(e)}function A(e){return i.getClosest(e,"md-fab-trigger")}function w(e){return i.getClosest(e,"md-fab-actions")}function k(e){A(e.target)&&N.toggle(),w(e.target)&&N.close()}function _(){return n.find("md-fab-trigger")}function x(){return n.find("md-fab-actions")}var N=this,S=0;N.open=function(){e.$evalAsync("vm.isOpen = true")},N.close=function(){e.$evalAsync("vm.isOpen = false"),n.find("md-fab-trigger")[0].focus()},N.toggle=function(){e.$evalAsync("vm.isOpen = !vm.isOpen")},N.$onInit=function(){d(),s(),m(),u()},1===t.version.major&&t.version.minor<=4&&this.$onInit();var D}e.$inject=["$scope","$element","$animate","$mdUtil","$mdConstant","$timeout"],t.module("material.components.fabShared",["material.core"]).controller("MdFabController",e)}()}(),function(){!function(){function n(){function e(e,t){t.prepend('
')}return{restrict:"E",scope:{direction:"@?mdDirection",isOpen:"=?mdOpen"},bindToController:!0,controller:"MdFabController",controllerAs:"vm",link:e}}function o(n){function o(e){n(e,r,!1)}function i(n){if(!n.hasClass("md-animations-waiting")||n.hasClass("_md-animations-ready")){var o=n[0],i=n.controller("mdFabSpeedDial"),r=o.querySelectorAll(".md-fab-action-item"),a=o.querySelector("md-fab-trigger"),d=o.querySelector("._md-css-variables"),s=parseInt(e.getComputedStyle(d).zIndex);t.forEach(r,function(e,t){var n=e.style;n.transform=n.webkitTransform="",n.transitionDelay="",n.opacity=1,n.zIndex=r.length-t+s}),a.style.zIndex=s+r.length+1,i.isOpen||t.forEach(r,function(e,t){var n,o,r=e.style,d=(a.clientHeight-e.clientHeight)/2,s=(a.clientWidth-e.clientWidth)/2;switch(i.direction){case"up":n=e.scrollHeight*(t+1)+d,o="Y";break;case"down":n=-(e.scrollHeight*(t+1)+d),o="Y";break;case"left":n=e.scrollWidth*(t+1)+s,o="X";break;case"right":n=-(e.scrollWidth*(t+1)+s),o="X"}var c="translate"+o+"("+n+"px)";r.transform=r.webkitTransform=c})}}return{addClass:function(e,t,n){e.hasClass("md-fling")?(i(e),o(n)):n()},removeClass:function(e,t,n){i(e),o(n)}}}function i(n){function o(e){n(e,r,!1)}function i(n){var o=n[0],i=n.controller("mdFabSpeedDial"),r=o.querySelectorAll(".md-fab-action-item"),d=o.querySelector("._md-css-variables"),s=parseInt(e.getComputedStyle(d).zIndex);t.forEach(r,function(e,t){var n=e.style,o=t*a;n.opacity=i.isOpen?1:0,n.transform=n.webkitTransform=i.isOpen?"scale(1)":"scale(0)",n.transitionDelay=(i.isOpen?o:r.length-o)+"ms",n.zIndex=r.length-t+s})}var a=65;return{addClass:function(e,t,n){i(e),o(n)},removeClass:function(e,t,n){i(e),o(n)}}}o.$inject=["$timeout"],i.$inject=["$timeout"];var r=300;t.module("material.components.fabSpeedDial",["material.core","material.components.fabShared","material.components.fabActions"]).directive("mdFabSpeedDial",n).animation(".md-fling",o).animation(".md-scale",i).service("mdFabSpeedDialFlingAnimation",o).service("mdFabSpeedDialScaleAnimation",i)}()}(),function(){!function(){function n(){function e(e,t,n){t.addClass("md-fab-toolbar"),t.find("md-fab-trigger").find("button").prepend('
')}return{restrict:"E",transclude:!0,template:'
',scope:{direction:"@?mdDirection",isOpen:"=?mdOpen"},bindToController:!0,controller:"MdFabController",controllerAs:"vm",link:e}}function o(){function n(n,o,i){if(o){var r=n[0],a=n.controller("mdFabToolbar"),d=r.querySelector(".md-fab-toolbar-background"),s=r.querySelector("md-fab-trigger button"),c=r.querySelector("md-toolbar"),l=r.querySelector("md-fab-trigger button md-icon"),m=n.find("md-fab-actions").children();if(s&&d){var u=e.getComputedStyle(s).getPropertyValue("background-color"),p=r.offsetWidth,h=(r.offsetHeight,2*(p/s.offsetWidth));d.style.backgroundColor=u,d.style.borderRadius=p+"px",a.isOpen?(c.style.pointerEvents="inherit",d.style.width=s.offsetWidth+"px",d.style.height=s.offsetHeight+"px",d.style.transform="scale("+h+")",d.style.transitionDelay="0ms",l&&(l.style.transitionDelay=".3s"),t.forEach(m,function(e,t){e.style.transitionDelay=25*(m.length-t)+"ms"})):(c.style.pointerEvents="none",d.style.transform="scale(1)",d.style.top="0",n.hasClass("md-right")&&(d.style.left="0",d.style.right=null),n.hasClass("md-left")&&(d.style.right="0",d.style.left=null),d.style.transitionDelay="200ms",l&&(l.style.transitionDelay="0ms"),t.forEach(m,function(e,t){e.style.transitionDelay=200+25*t+"ms"}))}}}return{addClass:function(e,t,o){n(e,t,o),o()},removeClass:function(e,t,o){n(e,t,o),o()}}}t.module("material.components.fabToolbar",["material.core","material.components.fabShared","material.components.fabActions"]).directive("mdFabToolbar",n).animation(".md-fab-toolbar",o).service("mdFabToolbarAnimation",o)}()}(),function(){function e(e,o,i,r){function a(n,a,d,s){function c(){for(var e in o.MEDIA)r(e),r.getQuery(o.MEDIA[e]).addListener(M);return r.watchResponsiveAttributes(["md-cols","md-row-height","md-gutter"],d,m)}function l(){s.layoutDelegate=t.noop,T();for(var e in o.MEDIA)r.getQuery(o.MEDIA[e]).removeListener(M)}function m(e){null==e?s.invalidateLayout():r(e)&&s.invalidateLayout()}function u(e){var o=g(),r={tileSpans:b(o),colCount:v(),rowMode:y(),rowHeight:$(),gutter:E()};if(e||!t.equals(r,A)){var d=i(r.colCount,r.tileSpans,o).map(function(e,n){return{grid:{element:a,style:f(r.colCount,n,r.gutter,r.rowMode,r.rowHeight)},tiles:e.map(function(e,i){return{element:t.element(o[i]),style:h(e.position,e.spans,r.colCount,n,r.gutter,r.rowMode,r.rowHeight)}})}}).reflow().performance();n.mdOnLayout({$event:{performance:d}}),A=r}}function p(e){return w+e+k}function h(e,t,n,o,i,r,a){var d=1/n*100,s=(n-1)/n,c=_({share:d,gutterShare:s,gutter:i}),l="rtl"!=document.dir&&"rtl"!=document.body.dir,m=l?{left:x({unit:c,offset:e.col,gutter:i}),width:N({unit:c,span:t.col,gutter:i}),paddingTop:"",marginTop:"",top:"",height:""}:{right:x({unit:c,offset:e.col,gutter:i}),width:N({unit:c,span:t.col,gutter:i}),paddingTop:"",marginTop:"",top:"",height:""};switch(r){case"fixed":m.top=x({unit:a,offset:e.row,gutter:i}),m.height=N({unit:a,span:t.row,gutter:i});break;case"ratio":var u=d/a,p=_({share:u,gutterShare:s,gutter:i});m.paddingTop=N({unit:p,span:t.row,gutter:i}),m.marginTop=x({unit:p,offset:e.row,gutter:i});break;case"fit":var h=(o-1)/o,u=1/o*100,p=_({share:u,gutterShare:h,gutter:i});m.top=x({unit:p,offset:e.row,gutter:i}),m.height=N({unit:p,span:t.row,gutter:i})}return m}function f(e,t,n,o,i){var r={};switch(o){case"fixed":r.height=N({unit:i,span:t,gutter:n}),r.paddingBottom="";break;case"ratio":var a=1===e?0:(e-1)/e,d=1/e*100,s=d*(1/i),c=_({share:s,gutterShare:a,gutter:n});r.height="",r.paddingBottom=N({unit:c,span:t,gutter:n});break;case"fit":}return r}function g(){return[].filter.call(a.children(),function(e){return"MD-GRID-TILE"==e.tagName&&!e.$$mdDestroyed})}function b(e){return[].map.call(e,function(e){var n=t.element(e).controller("mdGridTile");return{row:parseInt(r.getResponsiveAttribute(n.$attrs,"md-rowspan"),10)||1,col:parseInt(r.getResponsiveAttribute(n.$attrs,"md-colspan"),10)||1}})}function v(){var e=parseInt(r.getResponsiveAttribute(d,"md-cols"),10);if(isNaN(e))throw"md-grid-list: md-cols attribute was not found, or contained a non-numeric value";return e}function E(){return C(r.getResponsiveAttribute(d,"md-gutter")||1)}function $(){var e=r.getResponsiveAttribute(d,"md-row-height");if(!e)throw"md-grid-list: md-row-height attribute was not found";switch(y()){case"fixed":return C(e);case"ratio":var t=e.split(":");return parseFloat(t[0])/parseFloat(t[1]);case"fit":return 0}}function y(){var e=r.getResponsiveAttribute(d,"md-row-height");if(!e)throw"md-grid-list: md-row-height attribute was not found";return"fit"==e?"fit":e.indexOf(":")!==-1?"ratio":"fixed"}function C(e){return/\D$/.test(e)?e:e+"px"}a.addClass("_md"),a.attr("role","list"),s.layoutDelegate=u;var M=t.bind(s,s.invalidateLayout),T=c();n.$on("$destroy",l);var A,w=e.startSymbol(),k=e.endSymbol(),_=e(p("share")+"% - ("+p("gutter")+" * "+p("gutterShare")+")"),x=e("calc(("+p("unit")+" + "+p("gutter")+") * "+p("offset")+")"),N=e("calc(("+p("unit")+") * "+p("span")+" + ("+p("span")+" - 1) * "+p("gutter")+")")}return{restrict:"E",controller:n,scope:{mdOnLayout:"&"},link:a}}function n(e){this.layoutInvalidated=!1,this.tilesInvalidated=!1,this.$timeout_=e.nextTick,this.layoutDelegate=t.noop}function o(e){function n(t,n){var o,a,d,s,c,l;return s=e.time(function(){a=i(t,n)}),o={layoutInfo:function(){return a},map:function(t){return c=e.time(function(){var e=o.layoutInfo();d=t(e.positioning,e.rowCount)}),o},reflow:function(t){return l=e.time(function(){var e=t||r;e(d.grid,d.tiles)}),o},performance:function(){return{tileCount:n.length,layoutTime:s,mapTime:c,reflowTime:l,totalTime:s+c+l}}}}function o(e,t){e.element.css(e.style),t.forEach(function(e){e.element.css(e.style)})}function i(e,t){function n(t,n){if(t.col>e)throw"md-grid-list: Tile at position "+n+" has a colspan ("+t.col+") that exceeds the column count ("+e+")";for(var a=0,l=0;l-a=e?o():(a=c.indexOf(0,d),a!==-1&&(l=r(a+1))!==-1?d=l+1:(a=l=0,o()));return i(a,t.col,t.row),d=a+t.col,{col:a,row:s}}function o(){d=0,s++,i(0,e,-1)}function i(e,t,n){for(var o=e;o",transclude:!0,scope:{},controller:["$attrs",function(e){this.$attrs=e}],link:n}}function r(){return{template:"
",transclude:!0}}n.$inject=["$mdUtil"],o.$inject=["$mdUtil"],e.$inject=["$interpolate","$mdConstant","$mdGridLayout","$mdMedia"],i.$inject=["$mdMedia"],t.module("material.components.gridList",["material.core"]).directive("mdGridList",e).directive("mdGridTile",i).directive("mdGridTileFooter",r).directive("mdGridTileHeader",r).factory("$mdGridLayout",o),n.prototype={invalidateTiles:function(){this.tilesInvalidated=!0,this.invalidateLayout()},invalidateLayout:function(){this.layoutInvalidated||(this.layoutInvalidated=!0,this.$timeout_(t.bind(this,this.layout)))},layout:function(){try{this.layoutDelegate(this.tilesInvalidated)}finally{this.layoutInvalidated=!1,this.tilesInvalidated=!1}}}}(),function(){t.module("material.components.icon",["material.core"])}(),function(){function n(e,t){function n(t){var n=t[0].querySelector(r),o=t[0].querySelector(a);return n&&t.addClass("md-icon-left"),o&&t.addClass("md-icon-right"),function(t,n){e(n)}}function o(e,n,o,i){var r=this;r.isErrorGetter=o.mdIsError&&t(o.mdIsError),r.delegateClick=function(){r.input.focus()},r.element=n,r.setFocused=function(e){n.toggleClass("md-input-focused",!!e)},r.setHasValue=function(e){n.toggleClass("md-input-has-value",!!e)},r.setHasPlaceholder=function(e){n.toggleClass("md-input-has-placeholder",!!e)},r.setInvalid=function(e){e?i.addClass(n,"md-input-invalid"):i.removeClass(n,"md-input-invalid")},e.$watch(function(){return r.label&&r.input},function(e){e&&!r.label.attr("for")&&r.label.attr("for",r.input.attr("id"))})}o.$inject=["$scope","$element","$attrs","$animate"];var i=["INPUT","TEXTAREA","SELECT","MD-SELECT"],r=i.reduce(function(e,t){return e.concat(["md-icon ~ "+t,".md-icon ~ "+t])},[]).join(","),a=i.reduce(function(e,t){return e.concat([t+" ~ md-icon",t+" ~ .md-icon"])},[]).join(",");return{restrict:"E",compile:n,controller:o}}function o(){return{restrict:"E",require:"^?mdInputContainer",link:function(e,t,n,o){!o||n.mdNoFloat||t.hasClass("md-container-ignore")||(o.label=t,e.$on("$destroy",function(){o.label=null}))}}}function i(e,n,o,i,r){function a(a,d,s,c){function l(e){return h.setHasValue(!g.$isEmpty(e)),e}function m(){h.label&&s.$observe("required",function(e){h.label.toggleClass("md-required",e&&!E)})}function u(){h.setHasValue(d.val().length>0||(d[0].validity||{}).badInput)}function p(){function o(){d.attr("rows",1).css("height","auto").addClass("md-no-flex");var e=c();if(!$){var t=d[0].style.padding||"";$=d.css("padding",0).prop("offsetHeight"),d[0].style.padding=t}if(b&&$&&(e=Math.max(e,$*b)),v&&$){var n=$*v;n-1&&g.$formatters.splice(e,1)}}function u(){function e(e){e.preventDefault(),l=!0,u=e.clientY,p=parseFloat(d.css("height"))||d.prop("offsetHeight")}function n(e){l&&(e.preventDefault(),m(),f.addClass("md-input-resized"))}function o(e){l&&d.css("height",p+e.pointer.distanceY+"px")}function i(e){l&&(l=!1,f.removeClass("md-input-resized"))}if(!s.hasOwnProperty("mdNoResize")){var c=t.element('
'),l=!1,u=null,p=0,f=h.element,g=r.register(c,"drag",{horizontal:!1});d.wrap('
').after(c),c.on("mousedown",e),f.on("$md.dragstart",n).on("$md.drag",o).on("$md.dragend",i),a.$on("$destroy",function(){c.off("mousedown",e).remove(),f.off("$md.dragstart",n).off("$md.drag",o).off("$md.dragend",i),g(),c=null,f=null,g=null})}}var p=!s.hasOwnProperty("mdNoAutogrow");if(u(),p){var b=s.hasOwnProperty("rows")?parseInt(s.rows):NaN,v=s.hasOwnProperty("maxRows")?parseInt(s.maxRows):NaN,E=a.$on("md-resize-textarea",o),$=null,y=d[0];if(i(function(){e.nextTick(o)},10,!1),d.on("input",o),f&&g.$formatters.push(l),b||d.attr("rows",1),t.element(n).on("resize",o),a.$on("$destroy",m),s.hasOwnProperty("mdDetectHidden")){var C=function(){var e=!1;return function(){var t=0===y.offsetHeight;t===!1&&e===!0&&o(),e=t}}();a.$watch(function(){return e.nextTick(C,!1),!0})}}}var h=c[0],f=!!c[1],g=c[1]||e.fakeNgModel(),b=c[2],v=t.isDefined(s.readonly),E=e.parseAttributeBoolean(s.mdNoAsterisk),$=d[0].tagName.toLowerCase();if(h){if("hidden"===s.type)return void d.attr("aria-hidden","true");if(h.input){if(h.input[0].contains(d[0]))return;throw new Error(" can only have *one* ,